From fff0ebe85de3f7bd36c92f0472047ee90fe32486 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Mon, 19 May 2025 17:02:32 +0300 Subject: [PATCH 1/6] fix(Player): workaround for binge watching --- src/routes/Player/Player.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 740ed46d4..ce4cd3c3e 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -103,7 +103,7 @@ const Player = ({ urlParams, queryParams }) => { video.setProp('extraSubtitlesOutlineColor', settings.subtitlesOutlineColor); }, [settings.subtitlesSize, settings.subtitlesOffset, settings.subtitlesTextColor, settings.subtitlesBackgroundColor, settings.subtitlesOutlineColor]); - const handleNextVideoNavigation = React.useCallback((deepLinks) => { + const handleNextVideoNavigation = (deepLinks) => { if (deepLinks.player) { isNavigating.current = true; window.location.replace(deepLinks.player); @@ -111,20 +111,16 @@ const Player = ({ urlParams, queryParams }) => { isNavigating.current = true; window.location.replace(deepLinks.metaDetailsStreams); } - }, []); - - const onEnded = React.useCallback(() => { - if (isNavigating.current) { - return; - } + }; + const onEnded = () => { ended(); - if (player.nextVideo !== null) { + if (window.playerNextVideo !== null) { onNextVideoRequested(); } else { window.history.back(); } - }, [player.nextVideo, onNextVideoRequested]); + }; const onError = React.useCallback((error) => { console.error('Player', error); @@ -229,14 +225,14 @@ const Player = ({ urlParams, queryParams }) => { nextVideoPopupDismissed.current = true; }, []); - const onNextVideoRequested = React.useCallback(() => { - if (player.nextVideo !== null) { + const onNextVideoRequested = () => { + if (window.playerNextVideo !== null) { nextVideo(); - const deepLinks = player.nextVideo.deepLinks; + const deepLinks = window.playerNextVideo.deepLinks; handleNextVideoNavigation(deepLinks); } - }, [player.nextVideo, handleNextVideoNavigation]); + }; const onVideoClick = React.useCallback(() => { if (video.state.paused !== null) { @@ -394,6 +390,12 @@ const Player = ({ urlParams, queryParams }) => { closeNextVideoPopup(); } } + if (player.nextVideo) { + // This is a workaround for the fact that when we call onEnded nextVideo from the player is already set to null since core unloads the stream + // we explicitly set it to a global variable so we can access it in the onEnded function + // this is not a good solution but it works for now + window.playerNextVideo = player.nextVideo; + } }, [player.nextVideo, video.state.time, video.state.duration]); React.useEffect(() => { @@ -429,6 +431,7 @@ const Player = ({ urlParams, queryParams }) => { defaultSubtitlesSelected.current = false; defaultAudioTrackSelected.current = false; nextVideoPopupDismissed.current = false; + isNavigating.current = false; }, [video.state.stream]); React.useEffect(() => { From b4c0ab551ecbb73ea074e035ea4b294b0755c15b Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 20 May 2025 15:09:50 +0300 Subject: [PATCH 2/6] fix(Player): binge watching --- src/routes/Player/Player.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index ce4cd3c3e..1ddb14599 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -103,7 +103,7 @@ const Player = ({ urlParams, queryParams }) => { video.setProp('extraSubtitlesOutlineColor', settings.subtitlesOutlineColor); }, [settings.subtitlesSize, settings.subtitlesOffset, settings.subtitlesTextColor, settings.subtitlesBackgroundColor, settings.subtitlesOutlineColor]); - const handleNextVideoNavigation = (deepLinks) => { + const handleNextVideoNavigation = React.useCallback((deepLinks) => { if (deepLinks.player) { isNavigating.current = true; window.location.replace(deepLinks.player); @@ -111,16 +111,23 @@ const Player = ({ urlParams, queryParams }) => { isNavigating.current = true; window.location.replace(deepLinks.metaDetailsStreams); } - }; + }, []); + + const onEnded = React.useCallback(() => { + if (isNavigating.current) { + return; + } - const onEnded = () => { ended(); if (window.playerNextVideo !== null) { - onNextVideoRequested(); + nextVideo(); + + const deepLinks = window.playerNextVideo.deepLinks; + handleNextVideoNavigation(deepLinks); } else { window.history.back(); } - }; + }, []); const onError = React.useCallback((error) => { console.error('Player', error); @@ -225,14 +232,14 @@ const Player = ({ urlParams, queryParams }) => { nextVideoPopupDismissed.current = true; }, []); - const onNextVideoRequested = () => { - if (window.playerNextVideo !== null) { + const onNextVideoRequested = React.useCallback(() => { + if (player.nextVideo !== null) { nextVideo(); - const deepLinks = window.playerNextVideo.deepLinks; + const deepLinks = player.nextVideo.deepLinks; handleNextVideoNavigation(deepLinks); } - }; + }, [player.nextVideo, handleNextVideoNavigation]); const onVideoClick = React.useCallback(() => { if (video.state.paused !== null) { @@ -431,7 +438,6 @@ const Player = ({ urlParams, queryParams }) => { defaultSubtitlesSelected.current = false; defaultAudioTrackSelected.current = false; nextVideoPopupDismissed.current = false; - isNavigating.current = false; }, [video.state.stream]); React.useEffect(() => { From 365294946a8a68d321bebe8cfb11f3f36301cc30 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 20 May 2025 15:12:29 +0300 Subject: [PATCH 3/6] chore(Player): add logs --- src/routes/Player/Player.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 1ddb14599..c0443ac74 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -114,6 +114,8 @@ const Player = ({ urlParams, queryParams }) => { }, []); const onEnded = React.useCallback(() => { + // here we need to explicitly check for isNavigating.current + // because the ended event can be calleb multiple times by MPV inside Shell if (isNavigating.current) { return; } From 38f7e5a0f805bc0192934e4d39fa53de984e5c20 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 20 May 2025 15:32:02 +0300 Subject: [PATCH 4/6] chore(Player): update logs --- src/routes/Player/Player.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index c0443ac74..7a4d5b035 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -115,7 +115,7 @@ const Player = ({ urlParams, queryParams }) => { const onEnded = React.useCallback(() => { // here we need to explicitly check for isNavigating.current - // because the ended event can be calleb multiple times by MPV inside Shell + // the ended event can be called multiple times by MPV inside Shell if (isNavigating.current) { return; } From 440713ee680fa034fe981e0119777480030464a3 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 20 May 2025 15:54:20 +0300 Subject: [PATCH 5/6] fix(Player): reset the flag back to false --- src/routes/Player/Player.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 7a4d5b035..f1e0657d9 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -440,6 +440,9 @@ const Player = ({ urlParams, queryParams }) => { defaultSubtitlesSelected.current = false; defaultAudioTrackSelected.current = false; nextVideoPopupDismissed.current = false; + // we need a timeout here to make sure that previous page unloads and the new one loads + // avoiding race conditions and flickering + setTimeout(() => isNavigating.current = false, 1000); }, [video.state.stream]); React.useEffect(() => { From 28578e1deac922fe8e1e81d388ccc967d7304b30 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Wed, 21 May 2025 15:11:32 +0300 Subject: [PATCH 6/6] refactor(Player): reset global var --- src/routes/Player/Player.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index f1e0657d9..48218d126 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -404,6 +404,8 @@ const Player = ({ urlParams, queryParams }) => { // we explicitly set it to a global variable so we can access it in the onEnded function // this is not a good solution but it works for now window.playerNextVideo = player.nextVideo; + } else { + window.playerNextVideo = null; } }, [player.nextVideo, video.state.time, video.state.duration]);