CreateRequest previously read the user's request count outside the
insert transaction, so two concurrent submissions at MaxRequests-1
could both pass the quota gate and end up at MaxRequests+1. Move the
count inside the same transaction as the insert and acquire a per-user
advisory lock so concurrent inserts serialize. The store reports
ErrQuotaExceeded when the racing path catches the user at the limit
and the service maps it back to QuotaError.
normalizeListFilter previously reset limit to 50 when callers asked
for more than 100, which is surprising. Clamp to the cap instead so a
request for 150 returns 100 and a request for 1_000_000 still cannot
hit the database with an unbounded scan.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Batch integration upserts in a single transaction
- Treat radarr/sonarr lookup results as arrays and require exact matches
- Prefer queue failures over downloading state when evaluating arr queues
- Allow retrying queued/downloading requests and block declines once fulfillment started
- Fall back to pending when auto-approval integration check fails
- Rename requests query hooks file and fix discover card request affordance
- Add `media_type=all` to request search, backed by TMDB `/search/multi` filtered to movies and series
- Default the Requests page filter to All and refresh search results grid styling
- Refine RequestPosterCard with status accent bar, richer fallback poster, and fluid grid layout
Wire curated TMDB-backed studios/networks/genres discovery into the requests service and UI, replacing on-demand logo fetches with fixed duotone logos and adding browse routes plus tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add GetMediaDetail TMDB client returning normalized detail with cast, crew, recommendations, and certifications
- Add /api/requests/detail/{media_type}/{tmdb_id} endpoint overlaying availability and request state
- Add RequestDetail page and link poster cards to it
- Treat empty/truncated Radarr/Sonarr POST responses as accepted; drop pre-submit existence lookups
- Add request domain, repository, service, and reconcile task
- Add Radarr/Sonarr fulfillment adapters and TMDB discovery
- Expose user and admin request APIs with quota and approval rules
- Add web UI for browsing, requesting, and admin queue management
- Migration 139 introduces media_requests and related tables
- Map number words and ordinals (e.g. "Two"/"2nd") to digit tokens in both SQL normalize_search_text and the Go mirror so "Dune: Part Two" and "Dune Part 2" match
- Rebuild title_normalized generated column and title FTS GIN indexes (migration 138)
- reload introdb API key on setting updates
- support recap/preview markers in playback and next-episode flow
- add profile defaults for recap and preview auto-play settings
- Rename actor-oriented API, storage, and webhook fields to user/profile terminology
- Switch dev compose helpers to use docker-compose.yml
- Update frontend types and webhook sync settings for the new endpoints
- Wire introdb marker fetching into playback and Jellyfin compat
- Persist and expose recap/preview markers alongside intro and credits
- Add new playback/profile settings for recap and preview behavior
- Add admin job support for collection defaults applies
- Keep preview synchronous while real applies run via the job queue
- Show collection apply job status in the admin UI
- Store bundled template posters in public S3 when available
- Presign imported user collection posters in API responses
- Thread frontend assets into router and collection handlers
Agent F's code review surfaced a critical gap: every Phase 1-3 template
ships a non-zero `DefaultSortOrder` in the documented PMM-style bands
(1000s charts, 2000s best-of-year, 3000s awards, 4000s streaming,
5000s popular by genre, 6000s top rated by genre, 7000s franchises,
8000s seasonal, 9000s misc/kids) and the test suite pins those values,
but none of the four `createCollectionFromTemplate` dispatch paths
forwarded the rank into `catalog.CreateLibraryCollectionInput.SortOrder`.
Applying any template — bundled or one-off — landed the new collection at
SortOrder 0, defeating the band scheme entirely.
Fix: add `SortOrder int` to each request struct
(`importMDBListRequest`, `importTMDBRequest`, `importTMDBFranchiseRequest`,
`importTMDBDiscoverRequest`) and forward `tmpl.DefaultSortOrder` →
`req.SortOrder` → `CreateLibraryCollectionInput.SortOrder` end-to-end.
The pre-existing `SourceTrakt` path is unchanged — no Trakt template
currently sets a non-zero `DefaultSortOrder` so the gap is dormant
there; revisit if/when a Trakt template needs ordering.
No new unit test: the fix is a per-struct field forward whose
end-to-end exercise requires the live repository. Adding a fake repo
to test the propagation would be a refactor beyond this fix's scope.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase-3 of the collection-templates expansion. Adds ten curated movie
franchises plus a generic placeholder template, all backed by Agent B's
tmdb_collection source. Templates land in the 7000s sort-order band.
Verified TMDB collection IDs (via api.themoviedb.org/3/collection/{id}):
- 10 Star Wars Collection (9 films)
- 645 James Bond Collection (25 films)
- 1241 Harry Potter Collection (8 films) — used for "Wizarding World"
- 9485 The Fast and the Furious Collection (12 films)
- 119 The Lord of the Rings Collection (3 films)
- 121938 The Hobbit Collection (3 films)
- 328 Jurassic Park Collection (7 films)
- 295 Pirates of the Caribbean Collection (5 films)
- 87359 Mission: Impossible Collection (8 films)
- 535313 Godzilla Collection (3 films) — used for "MonsterVerse"
Plan corrections / skips:
- MCU (plan ID 86311) resolves to "The Avengers Collection" (6 films),
not the full Marvel Cinematic Universe. TMDB has no umbrella MCU
collection. Skipped per the no-invent-IDs rule. Sort slot 7001 left
open.
- DC Extended Universe (plan ID 573436) resolves to "Spider-Man:
Spider-Verse Collection" — unrelated. No DCEU umbrella exists on
TMDB. Skipped. Sort slot 7005 left open.
- Wizarding World (plan ID 1241) is TMDB's Harry Potter octalogy;
Fantastic Beasts lives in a separate collection (435259). Used as-is
with description noting the scope.
- MonsterVerse (plan ID 535313) is labelled "Godzilla Collection" but
contains the three Legendary MonsterVerse Godzilla films, which is
the closest TMDB representation. Used as-is.
The placeholder template ships with CollectionID=0 and an empty sync
schedule so it can be applied without a valid franchise ID; admins edit
the resulting collection's source_config before the first sync.
Append the Phase-2 catalog from the collection-templates expansion plan:
- 18 Popular by Genre (sort_order 5001..5018, daily 0 4 * * *,
popularity.desc with vote_count_gte=300)
- 18 Top Rated by Genre (sort_order 6001..6018, weekly 0 5 * * 0,
vote_average.desc with vote_count_gte=1000)
- 1 Kids Movies (sort_order 9050, weekly, Family genre with
certification_lte=PG)
Adds TestPhase2DiscoverTemplatesUseExpectedBands to pin the band ranges
and the TMDB query parameters that define each section.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>