import hashlib import os from pathlib import Path from fastapi import APIRouter, HTTPException from fastapi.responses import FileResponse, RedirectResponse from sqlalchemy import text from .db import engine # Release-cover images for RecordGod. The stable URL the UI uses is /img/r/: # • if a LOCAL WebP copy exists (DISC_IMAGE_DIR), serve it — self-hosted, tiny, store-owned; # • else 302 → the Discogs thumb. Discogs already serves a ~150px q40 WebP (tiny), and a BROWSER can # load it even though server-side fetch is Cloudflare-403'd — so we redirect rather than proxy. # DISC_IMAGE_DIR is CONFIGURABLE (default now; per-store storage override later when shops host their own). # Local copies get populated by a backfill from WowPlatter's already-downloaded images / the harvester — # NOT by a server-side i.discogs fetch (that's blocked). Until then, the redirect gives working tiny WebP. IMAGE_DIR = Path(os.getenv("DISC_IMAGE_DIR", "/app/disc_images")) router = APIRouter() def _path(release_id: int) -> Path: h = hashlib.sha256(str(release_id).encode()).hexdigest() return IMAGE_DIR / h[:2] / f"{h}.webp" @router.get("/img/r/{release_id}") async def release_image(release_id: int): p = _path(release_id) if p.exists(): return FileResponse(p, media_type="image/webp", headers={"Cache-Control": "public, max-age=2592000"}) async with engine.connect() as conn: row = (await conn.execute(text("SELECT thumb FROM disc_release WHERE id = :r"), {"r": release_id})).first() if row and row[0]: return RedirectResponse(row[0], status_code=302) raise HTTPException(404, "no image")