From 1c04ce80c396933a8309aa5f8e83ef61a1f84e24 Mon Sep 17 00:00:00 2001 From: TwistedUmbrellaX Date: Tue, 5 Mar 2024 10:08:29 -0500 Subject: [PATCH] Reduce script overhead for injection --- .../Configuration/inject.js | 65 +++---------------- ...nfusedPolarBear.Plugin.IntroSkipper.csproj | 4 +- 2 files changed, 10 insertions(+), 59 deletions(-) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/inject.js b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/inject.js index 1154dcb..1e5ed00 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/inject.js +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/inject.js @@ -1,51 +1,39 @@ let introSkipper = { skipSegments: {}, videoPlayer: {}, - // .bind() is used here to prevent illegal invocation errors originalFetch: window.fetch.bind(window), }; - introSkipper.d = function (msg) { - console.debug("[intro skipper]", msg); + console.debug("[intro skipper] ", msg); } - /** Setup event listeners */ introSkipper.setup = function () { document.addEventListener("viewshow", introSkipper.viewShow); window.fetch = introSkipper.fetchWrapper; introSkipper.d("Registered hooks"); } - /** Wrapper around fetch() that retrieves skip segments for the currently playing item. */ introSkipper.fetchWrapper = async function (...args) { // Based on JellyScrub's trickplay.js let [resource, options] = args; let response = await introSkipper.originalFetch(resource, options); - // Bail early if this isn't a playback info URL try { let path = new URL(resource).pathname; - if (!path.includes("/PlaybackInfo")) { - return response; - } - - introSkipper.d("retrieving skip segments from URL"); + if (!path.includes("/PlaybackInfo")) { return response; } + introSkipper.d("Retrieving skip segments from URL"); introSkipper.d(path); - let id = path.split("/")[2]; introSkipper.skipSegments = await introSkipper.secureFetch(`Episode/${id}/IntroSkipperSegments`); - - introSkipper.d("successfully retrieved skip segments"); + introSkipper.d("Successfully retrieved skip segments"); introSkipper.d(introSkipper.skipSegments); } catch (e) { - console.error("unable to get skip segments from", resource, e); + console.error("Unable to get skip segments from", resource, e); } - return response; } - /** * Event handler that runs whenever the current view changes. * Used to detect the start of video playback. @@ -53,21 +41,17 @@ introSkipper.fetchWrapper = async function (...args) { introSkipper.viewShow = function () { const location = window.location.hash; introSkipper.d("Location changed to " + location); - if (location !== "#!/video") { introSkipper.d("Ignoring location change"); return; } - introSkipper.d("Adding button CSS and element"); introSkipper.injectCss(); introSkipper.injectButton(); - introSkipper.d("Hooking video timeupdate"); introSkipper.videoPlayer = document.querySelector("video"); introSkipper.videoPlayer.addEventListener("timeupdate", introSkipper.videoPositionChanged); } - /** * Injects the CSS used by the skip intro button. * Calling this function is a no-op if the CSS has already been injected. @@ -77,9 +61,7 @@ introSkipper.injectCss = function () { introSkipper.d("CSS already added"); return; } - introSkipper.d("Adding CSS"); - let styleElement = document.createElement("style"); styleElement.id = "introSkipperCss"; styleElement.innerText = ` @@ -130,7 +112,6 @@ introSkipper.injectCss = function () { `; document.querySelector("head").appendChild(styleElement); } - /** * Inject the skip intro button into the video player. * Calling this function is a no-op if the CSS has already been injected. @@ -141,20 +122,16 @@ introSkipper.injectButton = async function () { if (preExistingButton) { preExistingButton.style.display = "none"; } - if (introSkipper.testElement(".btnSkipIntro.injected")) { introSkipper.d("Button already added"); return; } - introSkipper.d("Adding button"); - let config = await introSkipper.secureFetch("Intros/UserInterfaceConfiguration"); if (!config.SkipButtonVisible) { introSkipper.d("Not adding button: not visible"); return; } - // Construct the skip button div const button = document.createElement("div"); button.id = "skipIntro" @@ -168,25 +145,21 @@ introSkipper.injectButton = async function () { `; button.dataset["intro_text"] = config.SkipButtonIntroText; button.dataset["credits_text"] = config.SkipButtonEndCreditsText; - /* * Alternative workaround for #44. Jellyfin's video component registers a global click handler * (located at src/controllers/playback/video/index.js:1492) that pauses video playback unless * the clicked element has a parent with the class "videoOsdBottom" or "upNextContainer". */ button.classList.add("upNextContainer"); - // Append the button to the video OSD let controls = document.querySelector("div#videoOsdPage"); controls.appendChild(button); } - /** Tests if the OSD controls are visible. */ introSkipper.osdVisible = function () { const osd = document.querySelector("div.videoOsdBottom"); return osd ? !osd.classList.contains("hide") : false; } - /** Get the currently playing skippable segment. */ introSkipper.getCurrentSegment = function (position) { for (let key in introSkipper.skipSegments) { @@ -196,71 +169,49 @@ introSkipper.getCurrentSegment = function (position) { return segment; } } - return { "SegmentType": "None" }; } - /** Playback position changed, check if the skip button needs to be displayed. */ introSkipper.videoPositionChanged = function () { const skipButton = document.querySelector("#skipIntro"); if (!skipButton) { return; } - const segment = introSkipper.getCurrentSegment(introSkipper.videoPlayer.currentTime); switch (segment["SegmentType"]) { case "None": skipButton.classList.add("hide"); return; - case "Introduction": skipButton.querySelector("#btnSkipSegmentText").textContent = skipButton.dataset["intro_text"]; break; - case "Credits": skipButton.querySelector("#btnSkipSegmentText").textContent = skipButton.dataset["credits_text"]; break; } - skipButton.classList.remove("hide"); } - /** Seeks to the end of the intro. */ introSkipper.doSkip = function (e) { introSkipper.d("Skipping intro"); introSkipper.d(introSkipper.skipSegments); - const segment = introSkipper.getCurrentSegment(introSkipper.videoPlayer.currentTime); if (segment["SegmentType"] === "None") { console.warn("[intro skipper] doSkip() called without an active segment"); return; } - introSkipper.videoPlayer.currentTime = segment["IntroEnd"]; } - /** Tests if an element with the provided selector exists. */ introSkipper.testElement = function (selector) { return document.querySelector(selector); } - /** Make an authenticated fetch to the Jellyfin server and parse the response body as JSON. */ introSkipper.secureFetch = async function (url) { url = ApiClient.serverAddress() + "/" + url; - - const reqInit = { - headers: { - "Authorization": "MediaBrowser Token=" + ApiClient.accessToken() - } - }; - + const reqInit = { headers: { "Authorization": "MediaBrowser Token=" + ApiClient.accessToken() } }; const res = await fetch(url, reqInit); - - if (res.status !== 200) { - throw new Error(`Expected status 200 from ${url}, but got ${res.status}`); - } - + if (res.status !== 200) { throw new Error(`Expected status 200 from ${url}, but got ${res.status}`); } return await res.json(); } - -introSkipper.setup(); +introSkipper.setup(); \ No newline at end of file diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ConfusedPolarBear.Plugin.IntroSkipper.csproj b/ConfusedPolarBear.Plugin.IntroSkipper/ConfusedPolarBear.Plugin.IntroSkipper.csproj index 1f3c386..254bf30 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ConfusedPolarBear.Plugin.IntroSkipper.csproj +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ConfusedPolarBear.Plugin.IntroSkipper.csproj @@ -2,8 +2,8 @@ net6.0 ConfusedPolarBear.Plugin.IntroSkipper - 0.1.15.0 - 0.1.15.0 + 0.1.16.0 + 0.1.16.0 true true enable