Add iCal reader and module
This commit is contained in:
parent
bcd130dc06
commit
8c7d5f583e
5
main.py
5
main.py
@ -69,6 +69,11 @@ def main():
|
|||||||
ratp = RATPWeatherModule().draw_module(config, int(480/1.6), 94)
|
ratp = RATPWeatherModule().draw_module(config, int(480/1.6), 94)
|
||||||
image.paste(ratp, (480-int(480/1.6), 155))
|
image.paste(ratp, (480-int(480/1.6), 155))
|
||||||
|
|
||||||
|
# ical
|
||||||
|
from modules.ical import IcalModule
|
||||||
|
cal = IcalModule().draw_module(config, 480-int(480/1.6), 255)
|
||||||
|
image.paste(cal, (0, 250))
|
||||||
|
|
||||||
# Toolbar
|
# Toolbar
|
||||||
from modules.weather import WeatherToolbarModule
|
from modules.weather import WeatherToolbarModule
|
||||||
image.paste(WeatherToolbarModule().draw_module(config, 480, 50), (0, 530))
|
image.paste(WeatherToolbarModule().draw_module(config, 480, 50), (0, 530))
|
||||||
|
64
modules/ical.py
Normal file
64
modules/ical.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
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, cals=[]):
|
||||||
|
self.cals = 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
|
Loading…
Reference in New Issue
Block a user