feat(plex): apply the sidebar filters to the Discover rails too

Discover now behaves like the Browse grid — the active metadata filters (genre /
rating / year / collection / studio / …) narrow every rail: Continue watching,
Recently added, Surprise me, the genre tiles, and Because you watched. Same
LibraryFilters / meta_filter_conds the grid uses, applied to each rail's movie +
show query (movie duration included); a rail may come back empty, which the client
already hides. Genre-language matches the grid.

Because Discover honours filters itself, adding a filter no longer force-flips the
Discover landing to the grid (only a header SEARCH does, since Discover has no
search rail) — so you stay on Discover with narrowed rails.

Frontend threads `filters` into api.plexDiscover/plexSurprise + their query keys
(plexSurprise is variadic now) and the watched-toggle setQueryData; PlexDiscover
reads them from usePlex. Tests: two discover filter-narrowing cases; PlexDiscover
dom test updated for the provider default + 3-arg call.
This commit is contained in:
2026-08-22 17:35:37 +02:00
parent a60164edc4
commit 9798e506cf
7 changed files with 159 additions and 55 deletions
+12 -7
View File
@@ -6,6 +6,7 @@ import { qk } from "../lib/queryKeys";
import { api, type PlexCard, type PlexDiscover as PlexDiscoverData } from "../lib/api";
import { plexLang } from "../i18n";
import { toggleWatchState } from "../lib/plexWatch";
import { usePlex } from "./PlexProvider";
import { Carousel } from "./Carousel";
import { PlexPosterCard } from "./plexCards";
import { LoadingState, StateMessage } from "./QueryState";
@@ -89,14 +90,17 @@ export default function PlexDiscover({
const { t } = useTranslation();
const qc = useQueryClient();
const lang = plexLang();
// The active sidebar filters narrow every rail, so Discover matches the Browse grid. They're in the
// query keys so a filter change refetches (and the watched-toggle setQueryData below keys the same).
const { filters } = usePlex();
const q = useQuery({
queryKey: qk.plexDiscover(scope, lang),
queryFn: () => api.plexDiscover(scope, lang),
queryKey: qk.plexDiscover(scope, lang, filters),
queryFn: () => api.plexDiscover(scope, lang, filters),
});
// Surprise-me is its own query so the ↻ button can redraw it without refetching the whole surface.
const surpriseQ = useQuery({
queryKey: qk.plexSurprise(scope),
queryFn: () => api.plexSurprise(scope),
queryKey: qk.plexSurprise(scope, filters),
queryFn: () => api.plexSurprise(scope, undefined, filters, lang),
staleTime: 0,
});
@@ -107,7 +111,7 @@ export default function PlexDiscover({
optimistic: (next) => {
const flip = (cards: PlexCard[]) =>
cards.map((c) => (c.id === card.id ? { ...c, status: next } : c));
qc.setQueryData<PlexDiscoverData>(qk.plexDiscover(scope, lang), (old) =>
qc.setQueryData<PlexDiscoverData>(qk.plexDiscover(scope, lang, filters), (old) =>
old
? {
...old,
@@ -119,8 +123,9 @@ export default function PlexDiscover({
}
: old,
);
qc.setQueryData<{ scope: string; items: PlexCard[] }>(qk.plexSurprise(scope), (old) =>
old ? { ...old, items: flip(old.items) } : old,
qc.setQueryData<{ scope: string; items: PlexCard[] }>(
qk.plexSurprise(scope, filters),
(old) => (old ? { ...old, items: flip(old.items) } : old),
);
},
resync: () => {