Import ICS to Native Calendar App

Hey everyone, thought I’d post this guide for anyone wondering how to import and ICS file into the native calendar app. My first suggestion would be to use KompaktCalendar by david-ger since it integrates directly with android’s Calendar Provider API and will therefore work alongside any calendar syncing app, however if you’re like me and love the look and feel of the native apps you can try this solution. It’s a bit hacky - the basic idea is to create a Mudita Center backup, add in our ICS calendar events, and then restore the modified backup to the Kompakt. This guide was written for Mudita Center version 4.0.0 - I have not confirmed whether it still works on later versions. Some caveats: only event NAME, DESCRIPTION, and DATE / TIME will be copied. Recurring events WILL NOT repeat, the native calendar app does not support them. Existing events will be preserved.

You will need python3 and pip - you can install both with homebrew using brew install python. Here goes:

  1. Check that the timezone set on your computer is the same as the timezone set on your Kompakt
  2. Back up your Kompakt in the Mudita Center application, make sure to skip setting a password
  3. Then make a second backup - this is the one we will modify
  4. Locate the backup file - the backup folder will be shown in the Mudita Center > Settings > Backup tab and backup files will be located in a subfolder in the format {timestamp}_{serialNumber}.mcbackup - pick the one with the later timestamp
  5. Download the ICS file you wish to import
  6. Create a file import.py and copy-paste the script at the bottom of this post, then run pip install ics
  7. Run python import.py path/to/calendar.ics path/to/backup.mcbackup - this will modify the backup IN PLACE
  8. Open Mudita Center and restore the backup, deselecting everything except calendar events - you may receive an error about storage after restoring the calendar events, this seems to be a bug with the current version of Mudita Center
  9. If something went wrong and you want to restore the calendar to its previous state, open settings on the kompakt > manage apps > calendar > three dots and click delete storage, then restore calendar events from the FIRST backup that you made

Script:

import base64
import json
import sys
from datetime import datetime

from ics import Calendar

SYSTEM_TZ = datetime.now().astimezone()

with open(sys.argv[1], 'r', encoding='utf-8') as f:
    calendar = Calendar(f.read())

with open(sys.argv[2]) as f:
    backup = json.loads(f.read())

events = backup['data']['CALENDAR_EVENTS_V1']
events = events + '=' * (-len(events) % 4)
events = json.loads(base64.b64decode(events))

cal_id = max([e['id'] for e in events['data']], default=0) + 1

# Loop through the ICS events list
for event in calendar.events:
    begin = event.begin
    end = event.end
    if event.all_day:
        # In an ICS file, all day events start at the beginning of the day in UTC
        # and end at the start of the NEXT day UTC, however the native calendar app
        # starts them at the beginning of the day LOCAL time and ends at the end of
        # the SAME day local time
        begin -= SYSTEM_TZ.utcoffset()
        end -= SYSTEM_TZ.utcoffset()
    event_data = {
        'id': cal_id,
        'title': event.name or '',
        'description': event.description or '',
        'startDateTime': begin.int_timestamp * 1000,
        'endDateTime': end.int_timestamp * 1000 - (1 if event.all_day else 0),
        'allDay': event.all_day,
        'isPreReminderSet': False,
    }
    events['data'].append(event_data)
    cal_id += 1

backup['data']['CALENDAR_EVENTS_V1'] = base64.b64encode(json.dumps(events).encode()).decode()

with open(sys.argv[2], 'w') as f:
    f.write(json.dumps(backup, indent=2))
1 Like

Thank you for taking the time to post this. I’m sure it will help some users.

1 Like