fix(plex): the player starts, and resumes after a session-restart seek, when React mounts it twice

The player's "still alive" flag — every play() is gated on it, so a late one cannot start a detached
<video> after Back — was only ever LOWERED, in an effect's cleanup. React may run a cleanup and mount
again (StrictMode does exactly that in development), and then the flag stayed false for the life of
the player: it never started by itself, and a seek back past the loaded region, which restarts the
session, left it paused. Found on localdev (Westworld S01E06: playing → seek back → the picture
settles, paused). Production does not double-mount, which is why only dev showed it — and why
several earlier localdev measurements "stayed paused".

The effect now raises the flag in its setup. A new test renders the real player under StrictMode and
checks it plays once the media is ready; red without the fix. Verified on localdev: it starts by
itself, and keeps playing through a backward session-restart seek.
This commit is contained in:
2026-09-11 03:47:36 +02:00
parent 0b4b268678
commit f7faa19ee2
2 changed files with 107 additions and 0 deletions
+6
View File
@@ -428,7 +428,13 @@ export default function PlexPlayer({ itemId, onClose, queue }: Props) {
// Full media teardown on unmount (Back): stop + detach the <video> and destroy hls, so a late
// play() can't leave audio playing on a detached element after leaving the player.
//
// The setup half matters as much as the cleanup: React may run the cleanup and then MOUNT AGAIN
// (StrictMode does exactly that in development). With the flag only ever lowered, it stayed false
// for the life of the player — every play() is gated on it, so the player never started by itself,
// and a seek that restarts the session left it paused (bug hunt 2026-09, found on localdev).
useEffect(() => {
aliveRef.current = true;
return () => {
aliveRef.current = false;
if (hlsRef.current) {