perf(plex): batch bulk pushes, cache show enrichment; remove dead code + DRY (F6/F8/F10)
F6: coalesce whole-show/season Plex watch-pushes into ONE background task (push_bulk_state_to_plex) that reuses a single DB session + keep-alive Plex client, instead of scheduling one task (own session + HTTP client) per episode. F8: cache a show's live Plex enrichment (metadata + related) per rating_key for a short TTL and fetch the two calls in parallel; repeat opens skip the network. Raw payloads are cached; per-user shaping stays out. An empty related list is not cached (plex.related swallows a transient failure as [] — don't pin it for the TTL). F10: remove dead code — the pre-unified /browse route + browse(), the /people route + people() + _person_photo(), api.plexPeople, interface PlexPerson, and the orphaned plex.people i18n block. DRY: appendPlexFilters() shared by plexLibrary + plexFacets; one exported plexDetailUi.Filterable (was Fil + Filterable); PlexInfo migrated onto the shared plexDetailUi hooks/menu (DetailCustomizeMenu gained overlay + extra props; useDetailPrefs exposes savePref; PrefToggle exported). Reviewed (high) → clean. F7 (facet aggregate collapse) deferred: self-exclusion gives each sub-aggregate a distinct WHERE, and no measurement shows /facets slow.
This commit is contained in:
parent
9f8e410033
commit
b3af04a997
9 changed files with 180 additions and 450 deletions
|
|
@ -820,11 +820,23 @@ export function plexFilterCount(f: PlexFilters): number {
|
|||
(f.collection ? 1 : 0)
|
||||
);
|
||||
}
|
||||
export interface PlexPerson {
|
||||
name: string;
|
||||
kind: "actor" | "director";
|
||||
count: number;
|
||||
photo?: string | null;
|
||||
// Serialize the shared PlexFilters metadata fields onto a query string. Used by both the library grid
|
||||
// and the facets request so the two endpoints always agree on the filter set (paging/sort/sort_dir are
|
||||
// each caller's own concern and stay out of here).
|
||||
export function appendPlexFilters(u: URLSearchParams, f: PlexFilters): void {
|
||||
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));
|
||||
if (f.ratingMin != null) u.set("rating_min", String(f.ratingMin));
|
||||
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.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.collection) u.set("collection", f.collection);
|
||||
}
|
||||
export interface PlexFacets {
|
||||
genres: { value: string; count: number }[];
|
||||
|
|
@ -1193,19 +1205,7 @@ export const api = {
|
|||
if (p.limit) u.set("limit", String(p.limit));
|
||||
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));
|
||||
if (f.ratingMin != null) u.set("rating_min", String(f.ratingMin));
|
||||
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.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.collection) u.set("collection", f.collection);
|
||||
appendPlexFilters(u, f);
|
||||
u.set("sort_dir", f.sortDir ?? "asc"); // default ascending
|
||||
}
|
||||
return req(`/api/plex/library?${u.toString()}`);
|
||||
|
|
@ -1215,25 +1215,9 @@ export const api = {
|
|||
plexFacets: (scope: string, f?: PlexFilters, show?: string): Promise<PlexFacets> => {
|
||||
const u = new URLSearchParams({ scope });
|
||||
if (show && show !== "all") u.set("show", show);
|
||||
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));
|
||||
if (f.ratingMin != null) u.set("rating_min", String(f.ratingMin));
|
||||
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.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.collection) u.set("collection", f.collection);
|
||||
}
|
||||
if (f) appendPlexFilters(u, f);
|
||||
return req(`/api/plex/facets?${u.toString()}`);
|
||||
},
|
||||
plexPeople: (library: string, q: string): Promise<{ people: PlexPerson[] }> =>
|
||||
req(`/api/plex/people?library=${encodeURIComponent(library)}&q=${encodeURIComponent(q)}`),
|
||||
plexCollections: (library: string, q?: string): Promise<{ collections: PlexCollection[] }> =>
|
||||
req(`/api/plex/collections?library=${encodeURIComponent(library)}${q ? `&q=${encodeURIComponent(q)}` : ""}`),
|
||||
// --- Collection editing (admin only; writes back to Plex) ---
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue