feat(plex): sort direction, genre any/all, multi-person filters; fix back-nav + player stop
UAT follow-ups on the Plex filter epic: - Sort now has an asc/desc toggle (sort_dir), applied to any sort field. - Genre multi-select gains an Any/All mode (genre_mode: OR vs AND containment). - Director/actor/studio become multi-value: people AND (titles featuring all selected), studios OR; clicking them on the info page stacks (unions) instead of replacing, and the sidebar shows each as a removable 'Active' chip. - fix(history): clicking a metadata filter on the info page now pushes a fresh grid entry instead of history.back(), so browser Back returns to the info page rather than leaving the Plex module. - fix(player): fully tear down the <video> + hls on unmount and guard late play() calls, so backing out of a just-started video no longer leaves audio playing in the background. i18n en/hu/de (match any/all, sort direction).
This commit is contained in:
parent
eefd7e3abd
commit
1982cfa7b9
10 changed files with 160 additions and 60 deletions
|
|
@ -723,6 +723,7 @@ export interface PlexCastMember {
|
|||
// The expanded Plex browse filters (movie libraries). Persisted per-account as JSON.
|
||||
export interface PlexFilters {
|
||||
genres: string[];
|
||||
genreMode?: "any" | "all"; // how multiple genres combine (default any)
|
||||
contentRatings: string[];
|
||||
yearMin?: number | null;
|
||||
yearMax?: number | null;
|
||||
|
|
@ -730,11 +731,18 @@ export interface PlexFilters {
|
|||
durationMin?: number | null; // seconds
|
||||
durationMax?: number | null;
|
||||
addedWithin?: string; // "" | "24h" | "1w" | "1m" | "6m" | "1y"
|
||||
director?: string | null;
|
||||
actor?: string | null;
|
||||
studio?: string | null;
|
||||
directors: string[]; // AND — titles featuring ALL selected
|
||||
actors: string[]; // AND — titles featuring ALL selected
|
||||
studios: string[]; // OR — from any selected studio
|
||||
sortDir?: "asc" | "desc"; // sort direction (default desc)
|
||||
}
|
||||
export const EMPTY_PLEX_FILTERS: PlexFilters = { genres: [], contentRatings: [] };
|
||||
export const EMPTY_PLEX_FILTERS: PlexFilters = {
|
||||
genres: [],
|
||||
contentRatings: [],
|
||||
directors: [],
|
||||
actors: [],
|
||||
studios: [],
|
||||
};
|
||||
export function plexFilterCount(f: PlexFilters): number {
|
||||
return (
|
||||
f.genres.length +
|
||||
|
|
@ -743,9 +751,9 @@ export function plexFilterCount(f: PlexFilters): number {
|
|||
(f.ratingMin != null ? 1 : 0) +
|
||||
(f.durationMin != null || f.durationMax != null ? 1 : 0) +
|
||||
(f.addedWithin ? 1 : 0) +
|
||||
(f.director ? 1 : 0) +
|
||||
(f.actor ? 1 : 0) +
|
||||
(f.studio ? 1 : 0)
|
||||
f.directors.length +
|
||||
f.actors.length +
|
||||
f.studios.length
|
||||
);
|
||||
}
|
||||
export interface PlexFacets {
|
||||
|
|
@ -1097,6 +1105,7 @@ export const api = {
|
|||
const f = p.filters;
|
||||
if (f) {
|
||||
if (f.genres?.length) u.set("genres", f.genres.join(","));
|
||||
if (f.genreMode === "all") u.set("genre_mode", "all");
|
||||
if (f.contentRatings?.length) u.set("content_ratings", f.contentRatings.join(","));
|
||||
if (f.yearMin != null) u.set("year_min", String(f.yearMin));
|
||||
if (f.yearMax != null) u.set("year_max", String(f.yearMax));
|
||||
|
|
@ -1104,9 +1113,10 @@ export const api = {
|
|||
if (f.durationMin != null) u.set("duration_min", String(f.durationMin));
|
||||
if (f.durationMax != null) u.set("duration_max", String(f.durationMax));
|
||||
if (f.addedWithin) u.set("added_within", f.addedWithin);
|
||||
if (f.director) u.set("director", f.director);
|
||||
if (f.actor) u.set("actor", f.actor);
|
||||
if (f.studio) u.set("studio", f.studio);
|
||||
if (f.directors?.length) u.set("directors", f.directors.join(","));
|
||||
if (f.actors?.length) u.set("actors", f.actors.join(","));
|
||||
if (f.studios?.length) u.set("studios", f.studios.join(","));
|
||||
if (f.sortDir === "asc") u.set("sort_dir", "asc");
|
||||
}
|
||||
return req(`/api/plex/browse?${u.toString()}`);
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue