E5 S4: Plex Discover rail-surface (default landing)

A dedicated Plex "Discover" landing — a stack of horizontal Carousel rails
served from ONE consolidated read (serve-from-DB, no live Plex/TMDB call):

- GET /api/plex/discover → continue_watching (in-progress movies + shows, most
  recently progressed) · recently_added · genres (top-N tiles) ·
  because_you_watched (recs of the most-recent watched, TMDB-enriched movie,
  resolved to library rows by guid via serve_block's resolver).
- GET /api/plex/surprise → a fresh random, scope-bounded sample for the ↻ rail.

Frontend: PlexDiscover.tsx (rails reuse the S1 Carousel + S3 PlexPosterCard;
colored genre tiles → tap to filter the grid; ↻ reshuffles the surprise rail
alone). Discover is now the root sub-view; the flat grid becomes the bookmarkable
"Browse all" secondary view (?v=browse) reached by a header search/filter (a
browse-intent flip) or the new Discover⟷Browse toggle.

resolve_recs is promoted from _resolve_recs (now cross-module). Tests:
test_plex_discover.py (rail shape/order, continue-watching, because-you-watched
+ null, surprise bounds, scope) and PlexDiscover.dom.test.tsx; plexSubUrl
round-trip updated for discover-root/grid-browse. Backend lane 393, vitest 332.
This commit is contained in:
2026-08-20 22:15:54 +02:00
parent 5b5e76b73d
commit f9b63745f9
13 changed files with 1022 additions and 9 deletions
+14
View File
@@ -253,5 +253,19 @@
"movies": "Movies ({{count}})",
"shows": "Shows ({{count}})",
"empty": "No titles found for this person."
},
"view": {
"label": "View",
"browse": "Browse"
},
"discover": {
"tab": "Discover",
"continueWatching": "Continue watching",
"recentlyAdded": "Recently added",
"surprise": "Surprise me",
"reshuffle": "Reshuffle",
"byGenre": "Browse by genre",
"becauseWatched": "Because you watched {{title}}",
"empty": "Nothing to discover yet — run a Plex sync from the admin Config page."
}
}
+14
View File
@@ -253,5 +253,19 @@
"movies": "Filmek ({{count}})",
"shows": "Sorozatok ({{count}})",
"empty": "Nincs találat ehhez a személyhez."
},
"view": {
"label": "Nézet",
"browse": "Böngészés"
},
"discover": {
"tab": "Felfedezés",
"continueWatching": "Folytatás",
"recentlyAdded": "Nemrég hozzáadva",
"surprise": "Lepj meg",
"reshuffle": "Újrakeverés",
"byGenre": "Böngészés műfaj szerint",
"becauseWatched": "Mert megnézted: {{title}}",
"empty": "Még nincs mit felfedezni — futtass egy Plex-szinkront az admin Konfiguráció oldalról."
}
}