Map backgrounds (aerial/osm/dark/light), bbox zoom, world locator, kometa YAML endpoint
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)
This commit is contained in:
+33
-5
@@ -1,5 +1,5 @@
|
||||
from fastapi import FastAPI, HTTPException, Response
|
||||
from fastapi.responses import FileResponse, Response as FastAPIResponse
|
||||
from fastapi.responses import FileResponse, Response as FastAPIResponse, PlainTextResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from pathlib import Path
|
||||
import logging
|
||||
@@ -7,7 +7,7 @@ import logging
|
||||
# Import our CircuitService
|
||||
from circuits_service import CircuitService, Format
|
||||
from ergast_service import ErgastService
|
||||
from posters_service import PostersService
|
||||
from posters_service import PostersService, BackgroundStyle
|
||||
from models.track_layout import TrackLayout
|
||||
|
||||
# Initialize FastAPI app
|
||||
@@ -71,9 +71,15 @@ async def root():
|
||||
|
||||
|
||||
@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)
|
||||
async def get_race_poster(grand_prix_name: str, season: int, bg: BackgroundStyle = BackgroundStyle.AERIAL):
|
||||
"""Plex-ready 1000x1500 race poster (PNG). Cached on disk per (race, bg).
|
||||
|
||||
`?bg=` selects the backdrop:
|
||||
- aerial (default) — Esri World Imagery satellite at the circuit's coords
|
||||
- osm — OpenStreetMap Carto street-map at the circuit's coords
|
||||
- none — plain black background (skip tile fetch)
|
||||
"""
|
||||
png = posters_service.render_race_poster(grand_prix_name, season, bg=bg)
|
||||
if not png:
|
||||
raise HTTPException(status_code=404, detail=f"No poster available for {grand_prix_name} {season}")
|
||||
return FastAPIResponse(
|
||||
@@ -93,6 +99,28 @@ async def get_season_poster(season: int):
|
||||
headers={"Cache-Control": "public, max-age=31536000"},
|
||||
)
|
||||
|
||||
|
||||
@app.get("/kometa/formula-1-metadata.yml")
|
||||
async def get_kometa_metadata():
|
||||
"""Generate a Kometa-compatible metadata YAML for the Formula 1 library.
|
||||
|
||||
One entry per F1 season from 1950..current+1. Each entry:
|
||||
- uses Kometa's f1_season builder for round/episode names
|
||||
- sets url_poster on the show (per-season hero from files-api)
|
||||
- sets url_poster on each Plex 'season' (== each F1 round) from the
|
||||
f1-circuits race poster endpoint
|
||||
|
||||
Kometa harmlessly skips shows / seasons that don't exist in the Plex
|
||||
library, so we can emit the full schedule and let Kometa do the matching.
|
||||
"""
|
||||
yaml = posters_service.render_kometa_metadata()
|
||||
return PlainTextResponse(
|
||||
content=yaml,
|
||||
media_type="text/yaml; charset=utf-8",
|
||||
# YAML changes only when the Jolpica schedule changes — cache 1h.
|
||||
headers={"Cache-Control": "public, max-age=3600"},
|
||||
)
|
||||
|
||||
@app.get("/circuits")
|
||||
async def get_countries():
|
||||
"""Get list of all available countries with their slugs"""
|
||||
|
||||
Reference in New Issue
Block a user