README.md
Rama main · réplica de lectura del repositorio original.
<p align="center">
<img src="docs/logo.svg" width="120" alt="ICS Combiner logo">
</p>
# ICS Combiner (FastAPI)
This service combines multiple iCalendar (ICS) feeds into a single calendar, with optional per‑calendar transforms. It runs as a FastAPI app with the same path‑based authentication scheme used by the MCP servers, and supports Redis caching for source ICS files with configurable refresh TTLs.
Key features
- FastAPI app with optional dual‑factor path auth using `ICS_API_KEY` and `SALT` (with legacy `MD5_SALT` support)
- Redis‑backed caching of source ICS feeds
- Per‑calendar refresh TTL with environment overrides
- Optional show/hide filtering via query params
- Dockerfile and example env provided
Environment
- ICS_API_KEY: API key to enable path‑based auth (optional for local/dev)
- SALT: Optional salt used for API path hash (preferred)
- MD5_SALT: Legacy name for `SALT` (still supported)
- REDIS_HOST, REDIS_SSL_PORT (default 6380), REDIS_KEY: Redis connection
- ICS_CACHE_NAMESPACE: Optional Redis namespace. Set this when sharing one Redis instance across multiple apps. If omitted, a namespace is derived from `ICS_API_KEY` when available.
- ICS_SOURCES: JSON array of calendar configs (see example)
- ICS_NAME: Combined calendar display name
- ICS_DAYS_HISTORY: Days of history to include (int)
- CACHE_TTL_ICS_SOURCE_DEFAULT: Default TTL (seconds) for source ICS caching
- CACHE_TTL_ICS_SOURCE_LKG: Optional last-known-good fallback TTL (seconds). Leave unset or set to 0 to retain indefinitely.
- CACHE_TTL_ICS_SOURCE_FAILURE_BACKOFF: Backoff TTL (seconds) after a source fetch failure (minimum 1)
Calendar source config
Each object in `ICS_SOURCES` may include the following keys (compatible with calcomb):
- Id (required, int): unique numeric ID per calendar
- Url (required, string): ICS feed URL
- Duration (optional, minutes): override event duration when DTSTART is datetime
- PadStartMinutes (optional, minutes): prepend minutes and extend duration accordingly
- Prefix (optional, string): prefix for SUMMARY
- MakeUnique (optional, bool): force UID uniqueness per calendar
- FilterDuplicates (optional, bool): de‑duplicate events by UID
- RefreshSeconds (optional, int): cache TTL for this calendar’s source ICS
- Set to 0 to bypass the fresh source cache while still using failure backoff and last-known-good fallback cache when Redis is configured.
Cache behavior
- Cache keys are scoped by app namespace so multiple apps can share one Redis instance without overwriting each other's source cache. Use a stable `ICS_CACHE_NAMESPACE` per app if `ICS_API_KEY` is not set or if several apps intentionally share an API key.
- Successful source fetches store a last-known-good copy indefinitely by default. A positive `CACHE_TTL_ICS_SOURCE_LKG` can cap that retention.
- Removed calendars are not emitted just because their old source data remains in Redis. The app tracks source keys per namespace and prunes cache entries for sources removed from `ICS_SOURCES` on the next combine request.
Endpoints
- GET /app/health — health status (no auth)
- GET /app/{ICS_API_KEY}/{hash}/ics?show=1,2&hide=3 — combined calendar
Run locally
1) Copy `.env.example` to `.env.local` and set values
2) `pip install -e .`
3) `python -m uvicorn src.server:app --host 0.0.0.0 --port 8080`
Run tests
- `pip install -e ".[dev]"`
- `python -m pytest -q`
Docker
- Build: `docker build -t ics-combiner .`
- Run: `docker run --env-file .env.local -p 8080:8080 ics-combiner`