๐Ÿ“… 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.

Adds simple cache

+41 -1
+1 -1
README.md
··· 21 21 ```console 22 22 $ poetry run black . 23 23 $ poetry run mypy . 24 - $ poetry run flake8 **/*.py 24 + $ poetry run flake8 **/*.py --ignore=E501 25 25 ```
+31
triathlon_live_calendar/cache.py
··· 1 + from dataclasses import dataclass 2 + from datetime import datetime, timedelta 3 + from typing import Optional 4 + 5 + 6 + DEFAULT_EXPIRES_IN = timedelta(days=1) 7 + 8 + 9 + @dataclass 10 + class Response: 11 + content: str 12 + expires_on: datetime 13 + 14 + 15 + @dataclass 16 + class Cache: 17 + _response: Optional[Response] = None 18 + 19 + @property 20 + def response(self) -> Optional[str]: 21 + if not self._response: 22 + return None 23 + 24 + if self._response.expires_on < datetime.now(): 25 + return None 26 + 27 + return self._response.content 28 + 29 + def save(self, content: str, expires_in: Optional[timedelta] = None) -> None: 30 + expires_in = expires_in or DEFAULT_EXPIRES_IN 31 + self._response = Response(content, datetime.now() + expires_in)
+9
triathlon_live_calendar/server.py
··· 1 1 from fastapi import FastAPI, Response 2 2 3 3 from triathlon_live_calendar.scraper import calendar 4 + from triathlon_live_calendar.cache import Cache 4 5 5 6 6 7 app = FastAPI() 8 + cache = Cache() 7 9 8 10 9 11 @app.get("/") 10 12 async def home(response: Response): 11 13 response.headers["Content-type"] = "text/calendar" 12 14 return str(await calendar()) 15 + cached = cache.response 16 + if cached: 17 + return cached 18 + 19 + contents = str(await calendar()) 20 + cache.save(contents) 21 + return contents