Repository navigation
feat(catalog): episode-level title cards (apply + display) - #240
Conversation
Accept `type: "titlecard"` for an episode on
`POST /api/v2/admin/items/{id}/images/apply`. The name aliases the pipeline's
`still` in `metadata.ImageTypeFromString`, so an episode title card is cached
and published through the existing episode-still path with no schema change
(the `episodes` table already carries `still_path`). Because the resolver
aliases to `ImageStill`, `artworkTargetColumns` accepts it only for an episode
and refuses a movie, series, or season with `400 unsupported_image_type`
before any download, instead of silently storing it as a poster.
Surface the episode's current title card to the image picker: the shared
handler `current` view now carries `still_url`, marked `json:"-"` so the
frozen v1 body is unchanged, and apiv2 emits it as an additive `still_url`.
Contract artifacts are regenerated. The OpenAPI change is additive only:
an optional response property plus a description on the existing `type` field.
The regenerated web contract types are left for the UI lane.
The episode detail hero always painted the parent series' backdrop, so the one piece of artwork an episode owns — its still — arrived on the detail payload as `poster_url` and was never drawn. Prefer it for the hero backdrop: a still is 16:9, the same slot the backdrop already occupies, so the page keeps its layout and DetailHero's existing fade-in and thumbhash placeholder. The generated thumbnail therefore stands in while the title card loads, and is what shows when the episode has no title card at all. The chain keeps the series backdrop in second place, so an episode with nothing of its own renders exactly as it did before, and reaches the season's episode row last. Episode rows name this artwork `still_url` — with the series art substituted when the episode has none — which is the only source left when the detail carries neither a still nor a backdrop (a series with a poster but no backdrop). The thumbhash resolves in the same order so the placeholder always belongs to the image it is replacing, and the page glow is keyed to whichever thumbhash the hero shows, the way the ebook and manga pages key theirs to their poster. No admin picker for episode art: Edit Metadata still excludes the Images section for episodes, and building one is out of scope here. Regenerate the committed v2 web bindings so the additive `still_url` on the image picker's `current` view and the widened `type` description are typed; `make verify-apiv2-web-types` reports the pair current. EpisodeContent tests cover all three sources of hero artwork.
Production review: REQUEST CHANGESBackend reuse is sound and it's one coherent concern, but 3 mediums block merge. CI was still IN_PROGRESS at review time — full green on the final head required regardless. 1. Medium — hero can pair an image with another image's thumbhash
2. Medium — new catalog docs describe fields episode detail doesn't carry
3. Medium — v1 "unchanged" claim needs reconciling
4. Low — "apply stores still" test doesn't store
What's goodNo new type/migration ( Before merge
|
…ard policy Address the PR #240 review. Web: pick the episode hero artwork by URL first, then use that same source's thumbhash even when it is absent. The independent `||` chains could show one image behind another image's generated thumbnail. Tests cover a preferred still with no hash and an orphaned hash whose URL is absent. Docs: describe episode rows and episode details separately. Rows carry still_url/still_thumbhash with a series fallback; details serve the still as poster_url/poster_thumbhash and the series backdrop separately, and the web hero order is documented apart from the backend row fallback. Tests: pin the v1 bridge ruling that titlecard on a non-episode scope is now a 400 rather than a silent poster store — an allowed correctness fix, not a contract change — alongside the unchanged mapping for every previously-valid request. Rename the request-mapping test and add integration coverage that a successful apply publishes to detail and row reads with the sibling and parent untouched. Add the v1 still_url omission and the v2 unset-omission pins.
|
Review addressed and pushed ( |
Review at
|
Problem
Closes #229
Validation tasks: none found covering episode artwork.
Episode title cards are a core part of the curated-artwork workflow, but the images API only supported show/season-level types - users could not apply complete per-episode sets.
Approach
Server: the episode still pipeline already existed end to end (still_path/thumbhash, resolver mapping, publish, serve); the gap was type recognition. Map "titlecard" to the existing still type (no new type invented, no migration): accepted on episode scope, 400 on any other scope with no download. Surface the episode still in the picker current view (additive still_url, v1 body unchanged). Web: episode detail hero selects source by URL then uses that source's thumbhash (never mixed), preferring the title card with series-backdrop and season-row fallbacks; no new components or loading paths. The v1 wrong-scope behavior change (silent poster store → 400) is documented as a bridge correctness fix; v1 response shapes unchanged.
Validation
Risks
The v2 response change is additive. The shared apply handler intentionally rejects non-episode
titlecardrequests that previously overwrote the scope's poster; documented request mappings and v1 response shapes remain unchanged. Apple/Android: no work required (existing image components, no new fields).Checklist
AI Disclosure