From 97088d5393cdc23a2ae1264d3c810d19cbfe6770 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sat, 11 Jul 2026 23:10:24 +0200 Subject: [PATCH] chore(plex): dedup frontend formatters + LS key, drop dead wasPlaying pref MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - format.ts: new formatRuntime() ("1h 30m"); PlexBrowse dur() + PlexInfo fmtDur() were byte-identical copies, now both call it. - PlexPlayer fmt() delegates to formatDuration (keeps the NaN/negative clamp the live media clock needs); local reimplementation gone. - Register LS.plexPlayerPrefs; PlexPlayer uses it instead of a bare string. - Remove the dead PlexPlayerPrefs.wasPlaying field (written on play/pause, never read) + its two patchPrefs writes. - PlexBrowse item page: drop the redundant onStateChange={() => q.refetch()} — PlexInfo.setState already invalidates ["plex-item", id], so q refetches itself. --- frontend/src/components/PlexBrowse.tsx | 15 +++++--------- frontend/src/components/PlexInfo.tsx | 10 ++------- frontend/src/components/PlexPlayer.tsx | 28 +++++++++----------------- frontend/src/lib/format.ts | 9 +++++++++ frontend/src/lib/storage.ts | 1 + 5 files changed, 26 insertions(+), 37 deletions(-) diff --git a/frontend/src/components/PlexBrowse.tsx b/frontend/src/components/PlexBrowse.tsx index 9a7f341..82bdf25 100644 --- a/frontend/src/components/PlexBrowse.tsx +++ b/frontend/src/components/PlexBrowse.tsx @@ -26,6 +26,7 @@ import { type PlexSeasonDetail, type PlexUnifiedResult, } from "../lib/api"; +import { formatRuntime } from "../lib/format"; import { useDebounced } from "../lib/useDebounced"; import { useHistorySubview } from "../lib/history"; import { DetailCustomizeMenu, Filterable, useArtBackdrop, useDetailPrefs } from "../lib/plexDetailUi"; @@ -67,13 +68,6 @@ type Props = { const PAGE = 40; -function dur(n?: number | null): string { - if (!n) return ""; - const h = Math.floor(n / 3600); - const m = Math.floor((n % 3600) / 60); - return h ? `${h}h ${m}m` : `${m}m`; -} - export default function PlexBrowse({ q, onClearSearch, @@ -483,7 +477,7 @@ function PlexPosterCard({ style={{ background: "color-mix(in srgb, var(--card) 60%, transparent)" }} >
{card.title}
-
{[card.year, dur(card.duration_seconds)].filter(Boolean).join(" · ")}
+
{[card.year, formatRuntime(card.duration_seconds)].filter(Boolean).join(" · ")}
); @@ -526,7 +520,8 @@ function PlexInfoView({ onPlay={onPlay} onPlayItem={onPlayItem} onFilter={onFilter} - onStateChange={() => q.refetch()} + // No onStateChange: PlexInfo.setState already invalidates ["plex-item", id] (this very + // query), so q refetches automatically — a manual refetch here just double-fetched. /> )} @@ -845,7 +840,7 @@ function EpisodeCard({ {!withShowTitle && {ep.episode_number}.} {ep.title} -
{dur(ep.duration_seconds)}
+
{formatRuntime(ep.duration_seconds)}
{onAdd && (