Skip to content

Sync ICS feeds like holidays, waste pickup, and F1 calendars into your CalDAV calendar (e.g., mailbox.org). Supports emoji mapping, recurring events, location filters, deduplication, and Docker automation.

License

Notifications You must be signed in to change notification settings

magicdude4eva/calendar-sync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

15 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“… calendar-sync

GitHub stars Build Python GitHub forks GitHub issues GitHub last commit License

calendar-sync is a flexible utility to sync one or more ICS feeds (iCalendar) into a CalDAV-compatible calendar β€” ideal for mailbox.org, Nextcloud, Synology, and more.

It supports features such as:

  • βœ… Deterministic UID generation for clean deduplication
  • πŸ“… Emoji mapping for more readable calendar events
  • πŸ” Full support for recurring events (e.g., yearly holidays) and custom extra events
  • 🧼 Optional cleanup of previously imported events
  • πŸ“ Location-based filtering (e.g., for regional holidays in Austria)
  • 🐳 Docker deployment for simple automation
  • πŸ’‘ Dry-run mode to preview changes without writing
  • πŸ•“ Timezone-aware handling for accurate scheduling

This is perfect for importing:

  • πŸ—‘οΈ Municipal waste collection schedules (e.g., MΓΌll App)
  • πŸ‡¦πŸ‡Ή Austrian public holidays
  • 🏎️ Formula 1 calendar with free practice, qualifying, and GP events

Unlike subscription-based ICS calendars, this tool writes events directly into your calendar, giving you full control over notifications, offline visibility, and data retention.

Use it on your Synology NAS, a server, or as a cron-triggered Docker container β€” and never miss a bin collection or Grand Prix again.

calendar-sync.mp4


paypal


paypal 🍺 Please support me: Although all my software is free, it is always appreciated if you can support my efforts on Github with a contribution via Paypal - this allows me to write cool projects like this in my personal time and hopefully help you or your business.


✨ Features

  • πŸ” Sync multiple ICS feeds to any CalDAV calendar
  • 🧠 Deterministic UID generation & deduplication
  • πŸ” Automatic expansion of YEARLY recurring events
  • πŸ“ Location-based filtering for region-specific holidays
  • 🧹 Optional cleanup of old imported events
  • πŸ“… Supports emoji mapping for event names
  • πŸ›‘ Dry run mode to test before writing
  • 🐳 Docker support for simple deployment

πŸš€ Usage

Manual

python src/calendar_sync.py --import
python src/calendar_sync.py --import --dry-run
python src/calendar_sync.py --cleanup

With Docker Compose

First, build the container:

docker-compose build

Then run the sync:

docker-compose run --rm calendar-sync --import
docker-compose run --rm calendar-sync --import --dry-run
docker-compose run --rm calendar-sync --cleanup

🧰 Manual Installation

git clone https://github.com/magicdude4eva/calendar-sync.git
cd calendar-sync
python3.13 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

βš™οΈ config.json

{
  "caldav_url": "https://dav-sso.mailbox.org/caldav/...",
  "username": "your@email.com",
  "password": "your-app-password",
  "timezone": "Europe/Vienna",
  "uid_prefix": "ICS-",
  "future_event_limit_days": 365,
  "ics_feeds": [
    {
      "url": "https://example.com/my.ics",
      "emoji_mapping": {
        "Papier": "♻️",
        "default": "πŸ“¦"
      }
    }
  ]
}

πŸ› οΈ How It Works

  • Fetches events from each configured ICS feed
  • Normalizes dates and checks if the UID exists
  • Skips, adds, or replaces events as needed
  • Uses emoji mappings to prefix event names
  • All-day events are handled properly (no time zone shift)
  • Recurring RRULE:FREQ=YEARLY events are expanded into individual years
  • Events can be filtered by LOCATION using import_locations

πŸ—ΊοΈ For import_locations, configure it per feed. For example:

{
  "url": "https://www.feiertage-oesterreich.at/kalender-download/ics/feiertage-oesterreich.ics",
  "import_locations": "K,St,V",
  "emoji_mapping": {
    "Β§": "πŸ‡¦πŸ‡Ή",
    "default": "πŸ—“οΈ"
  }
}

To discover valid locations, run the sync once and check the logs. Example:

INFO: ⏭️ Skipping 'St. Florian' (2025-05-04) due to unmatched location: OΓ–

πŸ—“οΈ Support for Yearly Recurring Events (RRULE:FREQ=YEARLY)

The script now automatically expands ICS events with RRULE:FREQ=YEARLY rules into individual event instances for each year, up to the configured future limit (future_event_limit_days).
This ensures recurring events like public holidays or anniversaries are correctly synced across multiple years.

Behavior:

  • Detects yearly recurring events by scanning raw RRULE data.
  • Expands the base event for each year (e.g. from 2025 to 2026).
  • Skips events in the past or beyond the future limit.
  • Deduplicates intelligently using UID hashing per year.

βž• Support for Custom Extra Events

In addition to ICS feeds, you can define your own custom events using the extra_events entry in config.json.

This allows you to add things like:

  • 🌷 Mother's Day (2nd Sunday of May)
  • πŸ‘¨β€πŸ‘§β€πŸ‘¦ Father's Day (2nd Sunday of June)
  • πŸ”₯ Summer Solstice (21st June)
  • πŸŽƒ Halloween (31st October)
  • πŸ•―οΈ Advent Sundays
  • 🧾 Tax Deadlines
  • β˜€οΈ Daylight Saving Time changes

Supported Formats:

Format Description Example
N.Weekday.Month Nth weekday of a month 2.Sunday.5 β†’ 2nd Sunday in May
-N.Weekday.Month Nth weekday from end of month -1.Sunday.3 β†’ last Sunday in March
DD.MM.fixed Fixed date 31.10.fixed β†’ 31st October

Sample:

    "extra_events": [
      "β˜€οΈ Sommerzeit beginnt:-1.Sunday.3",
      "🌷 Muttertag:2.Sunday.5",
      "πŸ‘¨β€πŸ‘§β€πŸ‘¦ Vatertag:2.Sunday.6",
      "πŸ”₯ Sonnwendfeier:21.6.fixed",
      "🧾 SteuererklÀrung:30.6.fixed",
      "πŸŒ’ Sommerzeit endet:-1.Sunday.10",
      "πŸŽƒ Halloween:31.10.fixed",
      "πŸ•―οΈ 1. Advent:-4.Sunday.12",
      "πŸ•―οΈ 2. Advent:-3.Sunday.12",
      "πŸ•―οΈ 3. Advent:-2.Sunday.12",
      "πŸ•―οΈ 4. Advent:-1.Sunday.12",
      "πŸ‘Ή Krampusnacht:5.12.fixed",
      "πŸŽ… Nikolaus:6.12.fixed"    
      ],

πŸ§ͺ Dry Run

Add --dry-run to see what would happen without making changes:

docker-compose run --rm calendar-sync --import --dry-run

πŸ—‚οΈ Project Structure

calendar-sync/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ calendar_sync.py      # Entry script
β”‚   └── utils.py              # Core sync logic
β”œβ”€β”€ config.json               # Configuration
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ requirements.txt
└── README.md

πŸ“· mailbox.org Setup Guide

1. πŸ” Create Application Password

Go to Settings β†’ Security β†’ Application Passwords
Select Calendar and Addressbook Client (CalDAV/CardDAV)
Create Application Password


2. πŸ“… Create a New Calendar

Go to the Calendar section β†’ click + Add new calendar
Create a New Calendar


3. πŸ”— Get the CalDAV URL

Right-click your new calendar β†’ Properties β†’ Copy the URL
Get the CalDAV URL

Paste it into config.json under "caldav_url"


πŸ“„ License

This project is licensed under the MIT License.


❀️ Contributing

PRs welcome! File issues or ideas via GitHub.

Donations are always welcome

🍺 Please support me: Although all my software is free, it is always appreciated if you can support my efforts on Github with a contribution via Paypal - this allows me to write cool projects like this in my personal time and hopefully help you or your business.

(CRO)    0xBAdB43af444055c4031B79a76F74895469BA0CD7 (Cronos)
(USDC)   0xBAdB43af444055c4031B79a76F74895469BA0CD7
(ETH)    0xfc316ba7d8dc325250f1adfafafc320ad75d87c0
(BTC)    1Mhq9SY6DzPhs7PNDx7idXFDWsGtyn7GWM
(BNB)    0xfc316ba7d8dc325250f1adfafafc320ad75d87c0
Crypto.com PayString: magicdude$paystring.crypto.com    

Go to Curve.com to add your Crypto.com card to ApplePay and signup to Crypto.com for a staking and free Crypto debit card.

Use Binance Exchange to trade #altcoins. I also accept old-school PayPal.

About

Sync ICS feeds like holidays, waste pickup, and F1 calendars into your CalDAV calendar (e.g., mailbox.org). Supports emoji mapping, recurring events, location filters, deduplication, and Docker automation.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published