* feat(sections): fix broken home section templates and add six new ones
Fixes templates that silently produced nothing:
- award_winners: hide from gallery (resolver is a stub until award data
exists); saved sections keep resolving
- seasonal_themed: christmas/st_patricks/thanksgiving get an interim
title-keyword resolver, and multi-theme selection skips themes without
an executable query so a data-less theme can no longer black out the
section during its own window (previously killed the section all of
December)
- taste_match: empty genre now auto-picks the profile's strongest taste
cluster (fallback: server top genre); the default preset was permanently
empty
- because_you_watched: honor the recipe's anchor_item_id key (fetcher only
read legacy source_item_id, so pinning an anchor did nothing)
- editorial_spotlight: reject subject_type=franchise (validated but could
never resolve); fix drawer misrepresenting pinned presets as auto-rotate
- admin_curated_list: add a catalog-search item picker so Editor's Picks
is actually addable; block saving an empty list; hide admin_only recipes
from profile-facing galleries
- discovery fetchers (hidden_gems, forgotten_favorites,
critically_acclaimed): honor single/multi library scope, intersected
with viewer access; implement hidden_gems max_play_count
New templates: returning_shows (new season of shows you've watched),
genre_roulette (rotating top-genre spotlight with title override),
anniversaries (milestone release anniversaries this month), short_watches
(well-rated movies under a runtime cap), family_movie_night seasonal
theme (Fri/Sat evenings), and a "New in 4K" format_showcase preset via a
new sort=recent param.
Adds a blanket test asserting every visible gallery preset's defaults
pass its own recipe validation — the gap that let taste_match and
Editor's Picks ship broken. New SQL shapes validated with EXPLAIN against
the dev database.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(sections): address PR #332 review findings
Codex review:
- returning_shows: the new-season file check now applies the effective
library scope (section scope ∩ viewer-allowed, minus disabled) to
media_files.media_folder_id, so an episode file that only exists in an
out-of-scope folder can no longer surface the series
- buildLibraryScope: replaced the media_item_libraries row join with
EXISTS / NOT EXISTS semi-joins. An item in several in-scope libraries
now yields exactly one row in the non-GROUP BY rails (short_watches,
anniversaries, seasonal keyword, format_showcase, new_to_library, ...),
and the disabled-library check is item-level, closing the join-row leak
where membership in an allowed library masked membership in a disabled
one. Deny-only mode keeps the positive-membership guard, mirroring
catalog's appendDiscoveryLibraryScope.
CodeRabbit review:
- recommendations reader: a taste cluster whose cached items are entirely
filtered out now falls through to the next cluster / global fallback
instead of returning an empty row
- genre_roulette: multi-library scopes get distinct rotation seeds
- returning_shows: reject negative lookback_days at validation
- shared oneOf() enum validator replaces per-recipe switch duplication
- SeasonalTitleOverride usable-filter contract covered by a direct test
- web NumberParamField: integer-only guard + step=1 (backend fields are
Go ints; fractional values failed unmarshalling at save)
- curated list picker: search failures show an error instead of a
misleading "No matches."; pre-existing item_ids hydrate display titles
via the watch-detail endpoint instead of rendering raw ids
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>