From c0c3a2ea5f2039eb5d41ae96d1429169f7b445cf Mon Sep 17 00:00:00 2001 From: Anarios Date: Wed, 29 Oct 2025 16:17:22 +0100 Subject: [PATCH] #1156 and #1149 - firx for shorts --- Extensions/combined/ryd.content-script.js | 112 ++++++++++++++++++---- Extensions/combined/src/buttons.js | 42 +++++--- Extensions/combined/src/config.js | 2 +- Extensions/combined/src/state.js | 3 + 4 files changed, 125 insertions(+), 34 deletions(-) diff --git a/Extensions/combined/ryd.content-script.js b/Extensions/combined/ryd.content-script.js index 99a0a40..5206532 100644 --- a/Extensions/combined/ryd.content-script.js +++ b/Extensions/combined/ryd.content-script.js @@ -9,35 +9,105 @@ initPatreonFeatures(); let jsInitChecktimer = null; let isSetInitialStateDone = false; +let isStorageListenerRegistered = false; +let shortsNavigationObserver = null; +let shortsNavigationObserverTarget = null; -async function setEventListeners(evt) { - async function checkForJS_Finish() { - try { - if ((isShorts() && isVideoLoaded()) || (getButtons()?.offsetParent && isVideoLoaded())) { - clearInterval(jsInitChecktimer); - jsInitChecktimer = null; - createSmartimationObserver(); - addLikeDislikeEventListener(); - await setInitialState(); - isSetInitialStateDone = true; - getBrowser().storage.onChanged.addListener(storageChangeHandler); - } - } catch (exception) { - if (!isSetInitialStateDone) { - console.log("error"); - await setInitialState(); - } - } +function ensureShortsNavigationObserver() { + if (!isShorts()) { + return; } - if (jsInitChecktimer !== null) clearInterval(jsInitChecktimer); - jsInitChecktimer = setInterval(await checkForJS_Finish, 111); + const shortsRoot = document.querySelector("ytd-shorts"); + if (!shortsRoot) { + return; + } + + if (!shortsNavigationObserver) { + shortsNavigationObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if ( + mutation.type === "attributes" && + mutation.attributeName === "is-active" && + mutation.target.tagName === "YTD-REEL-VIDEO-RENDERER" && + mutation.target.hasAttribute("is-active") + ) { + triggerInitializationCycle(); + break; + } + } + }); + } + + if (shortsNavigationObserverTarget !== shortsRoot) { + shortsNavigationObserver.disconnect(); + shortsNavigationObserver.observe(shortsRoot, { + attributes: true, + subtree: true, + attributeFilter: ["is-active"], + }); + shortsNavigationObserverTarget = shortsRoot; + } +} + +async function checkForInitialization() { + try { + if (isShorts()) { + ensureShortsNavigationObserver(); + } + + if ((isShorts() && isVideoLoaded()) || (getButtons()?.offsetParent && isVideoLoaded())) { + if (jsInitChecktimer !== null) { + clearInterval(jsInitChecktimer); + jsInitChecktimer = null; + } + createSmartimationObserver(); + addLikeDislikeEventListener(); + await setInitialState(); + isSetInitialStateDone = true; + if (!isStorageListenerRegistered) { + getBrowser().storage.onChanged.addListener(storageChangeHandler); + isStorageListenerRegistered = true; + } + } + } catch (exception) { + if (!isSetInitialStateDone) { + console.log("error"); + await setInitialState(); + } + } +} + +async function triggerInitializationCycle() { + isSetInitialStateDone = false; + + if (jsInitChecktimer !== null) { + clearInterval(jsInitChecktimer); + jsInitChecktimer = null; + } + + await checkForInitialization(); + + if (!isSetInitialStateDone) { + jsInitChecktimer = setInterval(() => { + checkForInitialization(); + }, 111); + + setTimeout(() => { + if (!isSetInitialStateDone) { + checkForInitialization(); + } + }, 2000); + } +} + +async function setEventListeners() { + await triggerInitializationCycle(); } await setEventListeners(); document.addEventListener("yt-navigate-finish", async function (event) { - if (jsInitChecktimer !== null) clearInterval(jsInitChecktimer); await setEventListeners(); }); diff --git a/Extensions/combined/src/buttons.js b/Extensions/combined/src/buttons.js index 074b8e5..b3ebb15 100644 --- a/Extensions/combined/src/buttons.js +++ b/Extensions/combined/src/buttons.js @@ -15,6 +15,10 @@ function getButtons() { return element; } } + + if (elements.length > 0) { + return elements[0]; + } } //--- If Watching On Mobile: ---// if (isMobile()) { @@ -48,19 +52,33 @@ function getLikeTextContainer() { } function getDislikeButton() { - return getButtons().children[0].tagName === + if ( + getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER" - ? querySelector(extConfig.selectors.buttons.dislikeButton.segmented) ?? - querySelector( - extConfig.selectors.buttons.dislikeButton.segmentedGetButtons, - getButtons(), - ) - : isShorts() - ? querySelector(["#dislike-button"], getButtons()) - : querySelector( - extConfig.selectors.buttons.dislikeButton.notSegmented, - getButtons(), - ); + ) { + return ( + querySelector(extConfig.selectors.buttons.dislikeButton.segmented) ?? + querySelector( + extConfig.selectors.buttons.dislikeButton.segmentedGetButtons, + getButtons(), + ) + ); + } + + const notSegmentedMatch = querySelector( + extConfig.selectors.buttons.dislikeButton.notSegmented, + getButtons(), + ); + + if (notSegmentedMatch != null) { + return notSegmentedMatch; + } + + if (isShorts()) { + return querySelector(["#dislike-button"], getButtons()); + } + + return null; } function createDislikeTextContainer() { diff --git a/Extensions/combined/src/config.js b/Extensions/combined/src/config.js index a861b50..2f732cb 100644 --- a/Extensions/combined/src/config.js +++ b/Extensions/combined/src/config.js @@ -1,4 +1,4 @@ -const DEV_API_URL = "https://returnyoutubedislikeapi.com"; +const DEV_API_URL = "https://localhost:7258"; const PROD_API_URL = "https://returnyoutubedislikeapi.com"; const runtime = typeof chrome !== "undefined" ? chrome.runtime : null; diff --git a/Extensions/combined/src/state.js b/Extensions/combined/src/state.js index 19fe70f..b61f573 100644 --- a/Extensions/combined/src/state.js +++ b/Extensions/combined/src/state.js @@ -238,6 +238,9 @@ function displayError(error) { } async function setState(storedData) { + if (typeof window !== "undefined") { + window.__rydSetStateCalls = (window.__rydSetStateCalls || 0) + 1; + } storedData.previousState = isVideoDisliked() ? DISLIKED_STATE : isVideoLiked() ? LIKED_STATE : NEUTRAL_STATE; let statsSet = false; console.log("Video is loaded. Adding buttons...");