Add Plex-ready race + season poster endpoints

GET /posters/race/{grand_prix_name}/{season}.png
GET /posters/season/{season}.png

1000x1500 PNGs composed with Pillow + cairosvg:
checkered-flag strips top/bottom, F1 wordmark, round/year ribbon,
GP name, rasterised track outline (white), race date. Season poster
is wordmark + giant year + 'WORLD CHAMPIONSHIP'. Cached under
cache/posters/ so cold renders happen once.
This commit is contained in:
2026-06-13 20:57:28 +02:00
parent d74ece9680
commit 847ae2bae1
4 changed files with 234 additions and 5 deletions
+32 -2
View File
@@ -1,11 +1,13 @@
from fastapi import FastAPI, HTTPException, Response
from fastapi.responses import FileResponse
from fastapi.responses import FileResponse, Response as FastAPIResponse
from fastapi.middleware.cors import CORSMiddleware
from pathlib import Path
import logging
# Import our CircuitService
from circuits_service import CircuitService, Format
from ergast_service import ErgastService
from posters_service import PostersService
from models.track_layout import TrackLayout
# Initialize FastAPI app
@@ -30,6 +32,8 @@ logger = logging.getLogger(__name__)
# Initialize CircuitService
circuit_service = CircuitService()
ergast_service = ErgastService(circuit_service)
posters_service = PostersService(circuit_service, ergast_service)
def get_content_disposition(format: Format) -> str:
if format == Format.PNG:
@@ -59,10 +63,36 @@ async def root():
"/circuits/{country_slug}/{city_slug}/{circuit_slug}/layout/{layout_slug}",
"/tracks/{country_slug}/{city_slug}/{circuit_slug}/year/{year}/{format}",
"/tracks/{country_slug}/{city_slug}/{circuit_slug}/layout/{layout_slug}/{format}",
"/grand-prix/{grand_prix_name}/year/{year}"
"/grand-prix/{grand_prix_name}/year/{year}",
"/posters/race/{grand_prix_name}/{season}.png",
"/posters/season/{season}.png",
]
}
@app.get("/posters/race/{grand_prix_name}/{season}.png")
async def get_race_poster(grand_prix_name: str, season: int):
"""Plex-ready 1000x1500 race poster (PNG). Cached on disk."""
png = posters_service.render_race_poster(grand_prix_name, season)
if not png:
raise HTTPException(status_code=404, detail=f"No poster available for {grand_prix_name} {season}")
return FastAPIResponse(
content=png,
media_type="image/png",
headers={"Cache-Control": "public, max-age=31536000"},
)
@app.get("/posters/season/{season}.png")
async def get_season_poster(season: int):
"""Plex-ready 1000x1500 season poster (PNG). Cached on disk."""
png = posters_service.render_season_poster(season)
return FastAPIResponse(
content=png,
media_type="image/png",
headers={"Cache-Control": "public, max-age=31536000"},
)
@app.get("/circuits")
async def get_countries():
"""Get list of all available countries with their slugs"""