posters_service:
- Standard / sprint episode-index → (label, slug) maps mirroring Kometa's
F1 builder numbering
- _fetch_map_landscape: aerial tile stitcher in 1920x1080
- render_session_thumb: GP aerial bg + projected track outline + GP name
+ session label with red accent bar
- _draw_track_projected now takes canvas_w / geo_center_y so it can be
reused for both 2:3 posters and 16:9 thumbs
- render_kometa_metadata now emits an episodes: block per Plex season
pointing every Kometa-numbered episode at the matching session thumb;
sprint vs standard format is detected from the Jolpica race entry
cdn-api:
- GET /posters/session/{name}/{year}/{slug}.png returns the thumb
posters_service:
- BackgroundStyle enum + tile stitcher for race posters
(Esri aerial / OSM Carto / CartoDB dark / CartoDB light / none)
- _resolve_circuit_geo: GeoJSON bbox centre + auto-zoom (no hand tuning),
falls back to Jolpica lat/lon + f1-locations.json zoom
- _draw_track_projected: project the layout's GeoJSON points into the
same window as the tile background, so the white outline aligns with
the actual track (the hand-drawn SVGs had arbitrary orientations)
- _render_world_locator: 140x140 CartoDB Dark inset at zoom 5 with a
red marker pinning the circuit on the continent
- _race_dark_overlay: dimming so the heading + footer stay legible
against any underlying tiles
- render_kometa_metadata: emits a Kometa-compatible YAML covering
every season 1950..current+1 with per-show + per-round url_poster
cdn-api:
- GET /posters/race/{name}/{year}.png supports ?bg= query param
- GET /kometa/formula-1-metadata.yml serves the generated config so
Kometa pulls it via metadata_files.url (auto-updates with schedule)
posters_service.render_season_poster() now fetches /dilbert/sports/
formula1/cars/{year}.jpg from the files-api CDN, centre-crops to 2:3,
and composites a vertical dark gradient so the FORMULA 1 / year /
WORLD CHAMPIONSHIP text stays legible over any photo.
Dockerfile:
- python:3.12-slim → python:3.12-alpine (smaller, no fastf1 leftover)
- fonts-dejavu-core → ttf-liberation: same font Arch dev ships, so
posters render byte-identical on dev and in the container.
- Drop fastf1 (unused in the served code path); add numpy explicitly
because models/geo_json/geometry.py imports it at module load.
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.
Indianapolis oval layout uses real OSM centerline data for the
2.5-mile oval used in the F1 championship from 1950-1960.
Madring is the new Madrid circuit for the 2026 Spanish Grand Prix,
track path extracted from Wikimedia SVG.
FastF1's get_event() couldn't resolve several grand prix names
(Qatar, Brazilian, Mexican, Barcelona), causing 500/404 errors.
Now uses Jolpica's race schedule directly — slugifies circuitName
to match against circuits.json with ASCII fallback for unicode.
Dataclass models have parent back-references (TrackLayout→Circuit→
Locality→Country) causing infinite recursion in dataclasses.asdict().
Add to_dict() methods that exclude parent refs, use them in API endpoints.