refactor(player): the Plex session machine is a tested engine, one request per item in flight
PlexPlayer's session logic (generation, pending play intent, clock ownership, session offset, reclaim
budget, listener teardown) moves into lib/hlsEngine.ts, a plain class with hls.js behind lib/hlsPort.ts
and its own unit tests.
- A seek, track change or reclaim asked for while a session request is out replaces the queued
target; it is sent once the in-flight answer settles. A burst of 20 presses past the buffer was 20
requests and 20 ffmpeg spawns; it is now 2-3, and plays again ~2 s sooner.
- The player stops its server session when it leaves the item, closes or the page unloads
(POST /api/plex/stream/{rk}/session/{sid}/stop, identity-aware). A left transcode used to run to
the end of the film first.
- A restart asked for after a new session attached but before it played no longer reads the emptied
media as the viewer's pause.
This commit is contained in:
@@ -16,7 +16,6 @@ import { createRef, type ReactNode, type RefObject } from "react";
|
||||
import { usePlexTracks } from "./plexPlayerHooks";
|
||||
import { api, type PlexItemDetail } from "./api";
|
||||
import { dismissError, getError } from "./errorDialog";
|
||||
import type Hls from "hls.js";
|
||||
|
||||
const RK = "98614";
|
||||
|
||||
@@ -44,15 +43,13 @@ function mount(qc: QueryClient, { sessionK = 0, abs = 3600, loadStart = 0 } = {}
|
||||
sessionK,
|
||||
subOffset: 0,
|
||||
subPos: 88,
|
||||
loadSession: async () => {},
|
||||
restartSession: () => {},
|
||||
setAudioTrack: () => false,
|
||||
patchPrefs: () => {},
|
||||
videoRef: createRef<HTMLVideoElement>(),
|
||||
hlsRef: createRef<Hls>(),
|
||||
multiAudioRef: { current: false },
|
||||
audioRef: { current: 0 } as RefObject<number | null>,
|
||||
aoffRef: { current: 0 },
|
||||
absRef: { current: abs },
|
||||
loadStartRef: { current: loadStart },
|
||||
playhead: () => (abs > 0 ? abs : loadStart),
|
||||
}),
|
||||
{ wrapper, initialProps: { id: RK } },
|
||||
);
|
||||
@@ -320,15 +317,13 @@ function TrackHarness() {
|
||||
sessionK: 0,
|
||||
subOffset: 0,
|
||||
subPos: 88,
|
||||
loadSession: async () => {},
|
||||
restartSession: () => {},
|
||||
setAudioTrack: () => false,
|
||||
patchPrefs: () => {},
|
||||
videoRef: createRef<HTMLVideoElement>(),
|
||||
hlsRef: createRef<Hls>(),
|
||||
multiAudioRef: { current: false },
|
||||
audioRef: { current: 0 } as RefObject<number | null>,
|
||||
aoffRef: { current: 0 },
|
||||
absRef: { current: 3600 },
|
||||
loadStartRef: { current: 0 },
|
||||
playhead: () => 3600,
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/immutability -- a TEST probe: the hook's return has to reach the assertions, and a render-phase ref write is the only way to read it from outside without a wrapper that would change what is being measured.
|
||||
harness.current = tracks;
|
||||
|
||||
Reference in New Issue
Block a user