summaryrefslogtreecommitdiff
path: root/scripts/get_calendar.py
blob: b0bc1869992de29c4a37b866c41ff84fec7176d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from datetime import datetime, timedelta, time
from dateutil.relativedelta import relativedelta
import urllib2

import json
import logging
import sys
import copy
import os

from dateutil.rrule import rrulestr
import icalendar
import subprocess

def fetch_calendar(logger):
    """Fetches the calendar events and returns a icalendar.Calendar instance.
    """
    response = urllib2.urlopen(CALENDARIUM_IMPORT_URL)
    logger.debug('Fetched calendar from %s' % CALENDARIUM_IMPORT_URL)
    return icalendar.Calendar.from_ical(response.read())

def get_events(calendar, after, before):
    """Yields all events in calendar as dictionary.

    Only events after (including) after will be shown. Recurring events
    til before (inclusively) will be shown.
    """
    for event in calendar.walk('vevent'):
        event_fields = [
                # dest, src, default
                ('name', 'summary', 'unknown Event'),
                ('description', 'description', ''),
        ]
        event_info = {}
        for fieldinfo in event_fields:
            try:
                event_info[fieldinfo[0]] = event[fieldinfo[1]].format().encode("utf-8")
                event_info[fieldinfo[0]] = event_info[fieldinfo[0]].decode("string-escape")
            except KeyError:
                event_info[fieldinfo[0]] = fieldinfo[2]
        start = icalendar.vDDDTypes.from_ical(event['dtstart'].to_ical())
        if 'dtend' in event:
            end = icalendar.vDDDTypes.from_ical(event['dtend'].to_ical())
        else:
            end = start + icalendar.vDDDTypes.from_ical(event['duration'].to_ical())
        if not isinstance(start, datetime):
            start = datetime.combine(start, time())
        if not isinstance(end, datetime):
            end = datetime.combine(end, time())
        if end.hour == 0 and end.minute == 0 and end.second == 0:
            end -= timedelta(seconds=1)

        if 'rrule' in event:
            rrule = rrulestr(event['rrule'].to_ical(), dtstart=start)
            duration = end - start
            for occurence in rrule.between(after, before, True):
                event_info['start'] = occurence
                event_info['end'] = occurence + duration
                yield copy.deepcopy(event_info)
        else:
            if start >= after:
                event_info['start'] = start
                event_info['end'] = end
                yield event_info

class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        return json.JSONEncoder.default(self,obj)

#CALENDARIUM_IMPORT_URL = 'https://sublab.org:5232/calendars/events'
CALENDARIUM_IMPORT_URL = 'https://posteo.de/calendars/ics/ruku1tibpa2b2evfwsxrbvwcy2n60j9g'
if __name__ == '__main__':
    logging.basicConfig(stream=sys.stderr, level=logging.ERROR)
    logger = logging.getLogger('calendar_feed')
    calendar = fetch_calendar(logger)
    now = datetime.now()
    after = now - relativedelta(days=1)
    before = now + relativedelta(months=+1)

    events = []
    for event in get_events(calendar, after, before):
        event['start'] = event['start'].isoformat()
        event['end'] = event['end'].isoformat()
        events.append(event)
    destination = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../template/calendar.json')
    if os.path.exists(destination):
        with open(destination, 'r') as dfile:
            current = dfile.read()
    else:
        current = None
    output = json.dumps(events, indent=4)

    if current != output:
        with open(destination + '.new', 'w') as dfile:
            dfile.write(output)
        os.rename(destination + '.new', destination)
        subprocess.call(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'template.py'))