#!/usr/bin/python3 """calendar reminder this logs into a caldav server and get a digest of all of the events scheduled for next days. Good candidate to run from cron """ import sys import os from dotenv import load_dotenv from datetime import timedelta, date from os import environ from urllib.parse import quote_plus import caldav load_dotenv() # read parameters from dot env USERNAME = os.getenv('CALDAV_USERNAME') PASSWORD = os.getenv('CALDAV_PASSWORD') BASE_URL = os.getenv('CALDAV_URL') NEXT_DAYS = int(os.getenv('NEXT_DAYS')) def fill_event(component, calendar) -> dict[str, str]: # quite some data is tossed away here - like, the recurring rule. cur = {} cur["calendar"] = f"{calendar}" cur["summary"] = component.get("summary") cur["description"] = component.get("description") # month/day/year time? Never ever do that! # It's one of the most confusing date formats ever! # Use year-month-day time instead ... https://xkcd.com/1179/ cur["start"] = component.start.strftime("%m/%d/%Y %H:%M") endDate = component.end if endDate: cur["end"] = endDate.strftime("%m/%d/%Y %H:%M") return cur def fill_todo(component, calendar) -> dict[str, str]: cur = {} cur["calendar"] = f"{calendar}" cur["summary"] = component.get("summary") cur["description"] = component.get("description") return cur def display_event(event: dict[str, str]): print(event["start"] + " " + event["calendar"] + "/" + event["summary"]) def display_todo(todo: dict[str, str]): print("Todo : " + todo["summary"]) url = 'https://' + quote_plus(USERNAME) + ":" + quote_plus(PASSWORD) \ + '@' + BASE_URL + quote_plus(USERNAME) + '/' start = date.today() end = start + timedelta(days=NEXT_DAYS) client = caldav.DAVClient(url) calendars = client.principal().calendars() if not calendars: print("No calendars defined for " + USERNAME) sys.exit(0) for cal in calendars: events = cal.search(event=True, start=start, end=end, expand=True) \ + cal.search(todo=True) for event in events: for component in event.icalendar_instance.walk(): if component.name == "VEVENT": display_event(fill_event(component, cal)) elif component.name == "VTODO": display_todo(fill_todo(component, cal)) print(".")