Skip to main content

Radicale plugin: subscribe to ICS feeds with filtering and local edit support

Project description

radicale-ics-sync

Ever wanted to subscribe to an ICS feed (like a university timetable or a shared calendar) in Radicale, but still be able to edit events locally? That's what this plugin is for.

It syncs external ICS feeds into your Radicale calendars, keeps your local changes intact, and lets you filter out events you don't care about.

Installation

pip install radicale-ics-sync

Then configure Radicale to use the plugin (see Configuration).

Configuration

Radicale config

In your Radicale config file, set the storage type to radicale_ics_sync.storage:

[storage]
type = radicale_ics_sync.storage
filesystem_folder = /data/collections
# ics_config is optional; if omitted, defaults to /config/ics_sync.json
ics_config = /config/ics_sync.json

Sync jobs (ics_sync.json)

Create a file /config/ics_sync.json that defines which feeds to sync and where.

[
  {
    "feed": "https://example.com/calendar.ics",
    "collection": "username/calendar-name",
    "sync_interval": 3600,
    "include_patterns": [],
    "exclude_patterns": []
  }
]

You can provide multiple pairs of feed + collection. Each sync job supports these fields:

Field Required Default Description
feed URL of the ICS feed
collection Radicale collection path
sync_interval 3600 How often to poll the feed, in seconds
include_patterns [] Can be strings or arbitrary regex patterns
exclude_patterns [] Can be strings or arbitrary regex patterns

Note: The collection must already exist in Radicale before the plugin can sync to it. Create it through the Radicale web interface or your CalDAV client first.

Filtering

Patterns are matched case-insensitively against the event's SUMMARY (title) field.

{
  "feed": "https://university.example.com/timetable.ics",
  "collection": "alice/uni",
  "exclude_patterns": ["Tutorial", "Exercise"]
}
  • If include_patterns is set: only events matching at least one pattern are synced
  • If exclude_patterns is set: events matching any pattern are removed

Docker setup

Here is a minimal docker-compose.yml:

services:
  radicale:
    build: .
    container_name: radicale
    restart: always
    ports:
      - "5232:5232"
    volumes:
      - ./config:/config/config:ro  # Radicale config file (not a directory)
      - ./users:/config/users:ro
      - ./ics_sync.json:/config/ics_sync.json:ro
      - ./data:/data
    read_only: true
    tmpfs:
      - /tmp

And a Dockerfile to install the plugin:

FROM tomsquest/docker-radicale
RUN /venv/bin/pip install radicale-ics-sync --no-cache-dir

Non-Docker setup

Install Radicale and the plugin:

pip install radicale radicale-ics-sync

Create your Radicale config (e.g. ~/.config/radicale/config) and specify the path of your ics_sync.json:

[storage]
type = radicale_ics_sync.storage
filesystem_folder = ~/.local/share/radicale/collections
ics_config = ~/.config/radicale/ics_sync.json

Then create ~/.config/radicale/ics_sync.json and start Radicale:

radicale

State

The plugin stores its sync state in ics_sync_hashes.json, written next to your Radicale data. It tracks the last known content hash per event so unchanged events aren't rewritten. Safe to delete if you want a full re-sync on next startup.

Behavior

The plugin polls ICS feeds at a regular interval. Events are filtered by include/exclude patterns before being written to Radicale. Events that disappear from the upstream feed or are filtered out are deleted from the Radicale collection. Local edits to upstream events are preserved, until the upstream event itself changes, in which case the upstream version wins. Local events are not touched.

Limitations & Roadmap

  • Filtering is SUMMARY-only — other fields (LOCATION, DESCRIPTION) aren't supported yet, but are planned.
  • Upstream changes fully overwrite local edits — field-level merge (e.g. keeping your local title while accepting upstream time changes) is planned.

Contributing

Issues and pull requests are welcome.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

radicale_ics_sync-0.1.0.tar.gz (11.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

radicale_ics_sync-0.1.0-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file radicale_ics_sync-0.1.0.tar.gz.

File metadata

  • Download URL: radicale_ics_sync-0.1.0.tar.gz
  • Upload date:
  • Size: 11.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for radicale_ics_sync-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b1f63b6a1a65fcae30e56a1e005bb891608366d8bf88bb252a648d89740e1e0e
MD5 457b5a1fded2fcf8e5ce98b2aac8d24d
BLAKE2b-256 7cbfed337d557dfa923a88cea47a19721c904f603c6a578a37f325fdf738136f

See more details on using hashes here.

File details

Details for the file radicale_ics_sync-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for radicale_ics_sync-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 924d22e5f1ae2150a9874a47137567e64847018b8269c8fe0a16c768fcbd46e0
MD5 062277a642182ce7a6b64ab55ed3e350
BLAKE2b-256 6c16e61c05d8b82911dff9a1ffc85e798b11220a06daf33bf6730db2cd1fb53c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page