#!/usr/bin/env python3 import sys import html import logging import locale from datetime import datetime, timedelta, timezone, date from dateutil.rrule import rruleset, rrulestr import icalendar def _to_aware(dt): """Normalize a date or datetime to a timezone-aware UTC datetime.""" if isinstance(dt, date) and not isinstance(dt, datetime): return datetime(dt.year, dt.month, dt.day, tzinfo=timezone.utc) if dt.tzinfo is None: return dt.replace(tzinfo=timezone.utc) return dt.astimezone(timezone.utc) def vevent_to_event(event, rrstart=None): if rrstart is None: begin = _to_aware(event["DTSTART"].dt) else: begin = _to_aware(rrstart) return { "name": str(event.get("SUMMARY", "")), "url": str(event.get("URL", "")), "begin": begin } def parse_single_event(event, start, end): logging.info(f"Processing single event {event.get('SUMMARY', '')}") dtstart = _to_aware(event["DTSTART"].dt) if dtstart >= start and dtstart < end: return vevent_to_event(event) def parse_recurring_event(event, start, end): logging.info(f"Processing recurring event {event.get('SUMMARY', '')}") dtstart = _to_aware(event["DTSTART"].dt) rs = rruleset() rs.rrule(rrulestr(event["RRULE"].to_ical().decode("utf-8"), dtstart=dtstart)) if "EXDATE" in event.keys(): exdates = event["EXDATE"] if not isinstance(exdates, list): exdates = [exdates] for exdate_list in exdates: for dt in exdate_list.dts: rs.exdate(_to_aware(dt.dt)) events = [] for dt in rs.between(start, end, inc=True): events.append(vevent_to_event(event, dt)) return events def find_events(icsfilestr, start, end, num): with open(icsfilestr, "r") as icsfile: cal = icalendar.Calendar.from_ical(icsfile.read()) events = [] for event in cal.subcomponents: if event.name == "VEVENT": if "RRULE" in event.keys(): events.extend(parse_recurring_event(event, start, end)) else: ev = parse_single_event(event, start, end) if ev is not None: events.append(ev) events = sorted(events, key=lambda k: k["begin"]) events = events[0:num] return events def format_events(events): print("") for event in events: name = html.escape(event['name']) url = html.escape(event['url']) print( "" f"" f"" "" ) print("
{event['begin'].strftime('%A, %d.%m um %H:%M Uhr')}{name}
") if __name__ == "__main__": if len(sys.argv) < 4: print(f"Usage: {sys.argv[0]} calendar max_days max_items") sys.exit(1) locale.setlocale(locale.LC_TIME, "de_DE.UTF-8") calendar = sys.argv[1] max_days = int(sys.argv[2]) max_items = int(sys.argv[3]) now = datetime.now(timezone.utc) events = find_events(calendar, now, now + timedelta(days=max_days), max_items) format_events(events)