from datetime import datetime, timedelta, timezone import urllib.request from icalendar import Calendar, Event, vCalAddress, vText from PIL import Image, ImageDraw, ImageFont import pytz class IcalModule: def __init__(self, config): self.cals = config.cals def draw_module(self, config, width, height, line_height=19): now = datetime.now(tz=pytz.timezone('Europe/Paris')) toofar = now + timedelta(weeks=1) events = [] for cal in self.cals: with urllib.request.urlopen(cal) as c: ecal = Calendar.from_ical(c.read()) for component in ecal.walk(): if component.name == "VEVENT": if component.decoded("DTEND") < now: continue if component.decoded("DTSTART") > toofar: continue events.append({ "summary": component.get("SUMMARY"), "start": component.decoded("DTSTART"), "end": component.decoded("DTEND"), }) # Sort events events.sort(key=lambda e: e["start"]) image = Image.new('RGB', (width, height), '#fff') draw = ImageDraw.Draw(image) fnt_R = ImageFont.truetype(config.fnt_R_path, int(line_height*0.7)) fnt_B = ImageFont.truetype(config.fnt_RB_path, int(line_height*0.7)) last_evt = None align = 0 for evt in events: if last_evt is None or last_evt["start"].astimezone(pytz.timezone('Europe/Paris')).day != evt["start"].astimezone(pytz.timezone('Europe/Paris')).day: draw.text( (width / 2, align), evt["start"].astimezone(pytz.timezone('Europe/Paris')).strftime("%a %d %B"), fill="black", anchor="mt", font=fnt_B ) align += line_height draw.rectangle((0, align-4, width, align-4), fill="black") draw.text( (2, align), evt["start"].astimezone(pytz.timezone('Europe/Paris')).strftime("%H:%M") + " " + evt["summary"], fill="black", anchor="lt", font=fnt_R ) align += line_height last_evt = evt return image