koldfront

Splitting an .ics file up #debian #radicale #calendar #perl

🕔︎ - 2020-04-11

As I mentioned when I upgraded my server to Debian 10 (buster), the version of radicale included no longer supports calendar (.ics) files with more than one event. Instead each event is supposed to be in a file by itself, the file name being the UID of the event.

I have finally taken the time to write a little program that will take one of the .ics-files I used to use, and splits it out to a file per event.

Getting around to that took me, what, ¾ of a year? Oh well, here is is:

#!/usr/bin/perl

# split_ics - take an .ics file and a directory and write a file per event

# Copyright (C) 2020 by Adam Sjøgren <asjo@koldfront.dk> Under the GPLv2.

use strict;
use warnings;
use utf8;
use v5.12;

use Data::ICal;
use File::Slurp;

my $ics_file=$ARGV[0];
my $dir=$ARGV[1];

my $ics_data=File::Slurp::read_file($ics_file, { binmode=>':utf8' });
my $input=Data::ICal->new(data=>$ics_data);

foreach my $event (@{$input->entries}) {
    my $uid=$event->property('UID');
    my $filename=$dir . '/' . $uid->[0]->value;
    my $calendar=Data::ICal->new();
    $calendar->add_entry($event);
    open my $fh, '>:utf8', $filename || die $!;
    print $fh $calendar->as_string;
    close $fh;
}

The only tricky part was avoiding the Data::ICal-module splitting lines in the middle of multi-octet utf-8 characters.

A tip: you can run radicale --verify-storage to have any problems with the generated files reported. Do remember to run it as the radicale user, though.

One thing that is slightly different when going from regenerating one file to splitting it up, is that any calendar entry that has been deleted is now left as a stale file.

To remedy that, I'm using find(1) to remove the stale files - so I have a cron job doing something like this:

  dump_calendar > /tmp/calender.ics && sudo -u radicale split_ics /tmp/calender.ics /var/lib/radicale/collections/collection-root/asjo/calender.ics && sudo -u radicale find /var/lib/radicale/collections/collection-root/asjo/calender.ics/ -type f -not -path '*/.*' -not -newer /tmp/calender.ics -delete && rm /tmp/calender.ics

I.e. I have a script that writes a single calendar file in /tmp/, I use split_ics on it, and then I delete all files that are older than the temporary single calendar file, before cleaning that file up as well.

- Adam Sjøgren 🕝︎ - 2020-08-04

Add comment

To avoid spam many websites make you fill out a CAPTCHA, or log in via an account at a corporation such as Twitter, Facebook, Google or even Microsoft GitHub.

I have chosen to use a more old school method of spam prevention.

To post a comment here, you need to:

¹ Such as Thunderbird, Pan, slrn or Gnus (part of Emacs).