๐Ÿ“… Calendar file generator for triathlonlive.tv upcoming events triathlon-live-calendar.fly.dev
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fixes .ics file format

+28 -16
+14
triathlon_live_calendar/calendar.py
··· 1 + from asyncio import gather 2 + 3 + from httpx import AsyncClient 4 + from ics import Calendar # type: ignore 5 + 6 + from triathlon_live_calendar.scraper import event_from, event_urls 7 + 8 + 9 + async def calendar() -> Calendar: 10 + async with AsyncClient() as client: 11 + urls = await event_urls(client) 12 + requests = tuple(event_from(client, url) for url in urls) 13 + events = await gather(*requests) 14 + return Calendar(events=set(events))
+1 -10
triathlon_live_calendar/scraper.py
··· 1 - from asyncio import gather 2 1 from datetime import timedelta 3 2 from re import compile, findall 4 3 from typing import Tuple 5 4 6 5 from arrow import get # type: ignore 7 6 from httpx import AsyncClient 8 - from ics import Calendar, Event # type: ignore 7 + from ics import Event # type: ignore 9 8 from pyquery import PyQuery # type: ignore 10 9 11 10 ··· 32 31 begin=get(begin, DATETIME_FORMAT), 33 32 duration=DEFAULT_DURATION, 34 33 ) 35 - 36 - 37 - async def calendar() -> Calendar: 38 - async with AsyncClient() as client: 39 - urls = await event_urls(client) 40 - requests = tuple(event_from(client, url) for url in urls) 41 - events = await gather(*requests) 42 - return Calendar(events=events)
+13 -6
triathlon_live_calendar/server.py
··· 1 - from fastapi import FastAPI, Response 1 + from fastapi import FastAPI 2 + from fastapi.responses import PlainTextResponse 2 3 3 - from triathlon_live_calendar.scraper import calendar 4 4 from triathlon_live_calendar.cache import Cache 5 + from triathlon_live_calendar.calendar import calendar 6 + 7 + 8 + DEFAULT_HEADERS = { 9 + "Content-type": "text/calendar", 10 + "Content-Disposition": 'attachment; filename="triathlon_live.ics"', 11 + } 5 12 6 13 7 14 app = FastAPI() 8 15 cache = Cache() 9 16 10 17 11 - @app.get("/") 12 - async def home(response: Response): 13 - response.headers["Content-type"] = "text/calendar" 14 - return str(await calendar()) 18 + @app.get("/", response_class=PlainTextResponse) 19 + async def home(response: PlainTextResponse): 20 + response.headers.update(DEFAULT_HEADERS) 21 + 15 22 cached = cache.response 16 23 if cached: 17 24 return cached