38 lines
1.4 KiB
Python
38 lines
1.4 KiB
Python
"""Thumbnail endpoint: previews addressed only by asset ID and bounded size.
|
|
|
|
The browser never supplies a filesystem path. Errors return a consistent JSON
|
|
envelope with the service's typed code and status; successful responses carry the
|
|
image with an immutable cache header (the URL's identity comes from the versioned,
|
|
content-keyed cache).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Query, Request
|
|
from fastapi.responses import FileResponse, JSONResponse
|
|
|
|
from photo_pipeline.services.thumbnails import ThumbnailError, ThumbnailService
|
|
|
|
router = APIRouter(tags=["thumbnails"])
|
|
|
|
|
|
@router.get("/assets/{asset_id}/thumbnail")
|
|
def get_thumbnail(asset_id: str, request: Request, size: int = Query(512)):
|
|
service = ThumbnailService(
|
|
request.app.state.session_factory, request.app.state.config
|
|
)
|
|
try:
|
|
path = service.generate(asset_id, size)
|
|
except ThumbnailError as error:
|
|
return JSONResponse(
|
|
status_code=error.http_status,
|
|
content={"error": {"code": error.code, "message": str(error)}},
|
|
)
|
|
return FileResponse(
|
|
path,
|
|
media_type="image/webp",
|
|
# private: the URL is versioned and immutable, but these bytes are the user's
|
|
# photos and must never sit in a shared cache (US07-02).
|
|
headers={"Cache-Control": "private, max-age=31536000, immutable"},
|
|
)
|