chore(plex): dedup frontend formatters + LS key, drop dead wasPlaying pref
- 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.
This commit is contained in:
parent
f17bad9870
commit
97088d5393
5 changed files with 26 additions and 37 deletions
|
|
@ -33,7 +33,8 @@ import {
|
|||
X,
|
||||
} from "lucide-react";
|
||||
import { api, type PlexMarker } from "../lib/api";
|
||||
import { useAccountPersistedObject } from "../lib/storage";
|
||||
import { formatDuration } from "../lib/format";
|
||||
import { LS, useAccountPersistedObject } from "../lib/storage";
|
||||
import { useDismiss } from "../lib/useDismiss";
|
||||
import { useBackToClose } from "../lib/history";
|
||||
|
||||
|
|
@ -63,7 +64,6 @@ function subOrdForLang(subs: SubStream[], lang: string): number | null {
|
|||
type PlexPlayerPrefs = {
|
||||
volume: number; // 0..1
|
||||
muted: boolean;
|
||||
wasPlaying: boolean; // resume-playing intent across reloads (best-effort; browsers may block autoplay)
|
||||
audioLang: string; // "" = default first audio
|
||||
subLang: string; // "" = subtitles off
|
||||
subOffset: number; // seconds, +later / -earlier (client-side cue shift)
|
||||
|
|
@ -90,7 +90,6 @@ type PlexPlayerPrefs = {
|
|||
const DEFAULT_PREFS: PlexPlayerPrefs = {
|
||||
volume: 1,
|
||||
muted: false,
|
||||
wasPlaying: true,
|
||||
audioLang: "",
|
||||
subLang: "",
|
||||
subOffset: 0,
|
||||
|
|
@ -165,13 +164,10 @@ const HLS_SUB_LAG = 1.0;
|
|||
// the queue instead of the item's own episode neighbours.
|
||||
type Props = { itemId: string; onClose: () => void; queue?: string[] };
|
||||
|
||||
// Seekbar clock — same H:MM:SS / M:SS shape as the shared formatDuration, but the live media clock
|
||||
// can be NaN/negative before metadata loads, so clamp to 0 first (formatDuration never sees null here).
|
||||
function fmt(t: number): string {
|
||||
if (!isFinite(t) || t < 0) t = 0;
|
||||
const s = Math.floor(t % 60);
|
||||
const m = Math.floor((t / 60) % 60);
|
||||
const h = Math.floor(t / 3600);
|
||||
const pad = (n: number) => String(n).padStart(2, "0");
|
||||
return h ? `${h}:${pad(m)}:${pad(s)}` : `${m}:${pad(s)}`;
|
||||
return formatDuration(isFinite(t) && t >= 0 ? t : 0);
|
||||
}
|
||||
|
||||
export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
||||
|
|
@ -217,7 +213,7 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
|||
|
||||
// Per-account persisted player prefs — survive F5, carry across items.
|
||||
const [prefs, patchPrefs] = useAccountPersistedObject<PlexPlayerPrefs>(
|
||||
"siftlode.plexPlayerPrefs",
|
||||
LS.plexPlayerPrefs,
|
||||
DEFAULT_PREFS,
|
||||
);
|
||||
const { volume, muted } = prefs;
|
||||
|
|
@ -419,18 +415,12 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
|
|||
/* ignore */
|
||||
}
|
||||
};
|
||||
const onPlay = () => {
|
||||
setPlaying(true);
|
||||
patchPrefs({ wasPlaying: true }); // remember play intent for F5 (best-effort; autoplay may be blocked)
|
||||
};
|
||||
const onPause = () => {
|
||||
setPlaying(false);
|
||||
patchPrefs({ wasPlaying: false });
|
||||
};
|
||||
const onPlay = () => setPlaying(true);
|
||||
const onPause = () => setPlaying(false);
|
||||
// A seek that restarts the hls.js session detaches/re-attaches the media, firing 'emptied' —
|
||||
// which silently flips paused=true WITHOUT a 'pause' event, so the play/pause pair alone let the
|
||||
// button lie (⏸ shown while actually paused). Resync the flag from reality on the settling events
|
||||
// so the icon can never contradict the video. (Does not touch the wasPlaying pref.)
|
||||
// so the icon can never contradict the video.
|
||||
const syncPlaying = () => setPlaying(!video.paused);
|
||||
video.addEventListener("timeupdate", onTime);
|
||||
video.addEventListener("play", onPlay);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue