Anarios / return-youtube-dislike

Chrome extension to return youtube dislikes
https://returnyoutubedislike.com/
GNU General Public License v3.0
12.34k stars 548 forks source link

New YouTube UI fix for the latest version 3.0.0.11 #952

Closed tdreams2 closed 1 month ago

tdreams2 commented 9 months ago

I changed this line of code in createDislikeTextContainer() function: const textNodeClone = (getLikeButton().querySelector("button > div[class*='cbox']") || getLikeButton().querySelector('div > span[role="text"]').parentNode).cloneNode(true);

changed to this: const textNodeClone = (getLikeButton() || getLikeButton().parentNode).cloneNode(true);

Selectors: ("button > div[class*='cbox']") and ('div > span[role="text"]') can't be found on the page

tdreams2 commented 9 months ago

I get this error when I open a short video but dislike count still there no issue:

Cannot read properties of undefined (reading 'classList')

getDislikeButton().classList.contains("style-default-active")

From:

function isVideoDisliked() {
  if (isMobile()) {
    return (
      getDislikeButton().querySelector("button").getAttribute("aria-label") === "true"
    );
  }
  return getDislikeButton().classList.contains("style-default-active") || getDislikeButton().querySelector('button')?.getAttribute('aria-pressed') === 'true';
}

Windows 11:

So I think with this error if I dislike a video, it will not count my dislike through API

AminoffZ commented 9 months ago

Cannot read properties of undefined (reading 'classList')

getDislikeButton().classList.contains("style-default-active")

I'm getting it sometimes on both Windows 10 and Windows 11. Both on:

I think this should be fine since if you do:

function getDislikeButton() {
  console.log("getDislikeButton");
  const dislikeButton =
    getButtons().children[0].tagName ===
    "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER"
      ? getButtons().children[0].children[1] === undefined
        ? document.querySelector("#segmented-dislike-button")
        : getButtons().children[0].children[1]
      : getButtons().children[1];
  console.log(dislikeButton);
  return dislikeButton;
}

You end up getting what seems like calls to get the buttons until they exist.

ryd.content-script.js:786 getDislikeButton ryd.content-script.js:788 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'children') at getDislikeButton (ryd.content-script.js:788:17) at isVideoDisliked (ryd.content-script.js:488:10) at setState (ryd.content-script.js:604:30) at setInitialState (ryd.content-script.js:637:3) at checkForJS_Finish (ryd.content-script.js:1021:9) getDislikeButton @ ryd.content-script.js:788 ... ryd.content-script.js:786 getDislikeButton ryd.content-script.js:794 <ytd-toggle-button-renderer id=​"dislike-button" is-shorts class=​"style-scope ytd-like-button-renderer" vertically-aligned button-renderer=​"true">​…​​ ryd.content-script.js:786 getDislikeButton ryd.content-script.js:794 <ytd-toggle-button-renderer id=​"dislike-button" is-shorts class=​"style-scope ytd-like-button-renderer" vertically-aligned button-renderer=​"true">​…​​ ryd.content-script.js:786 getDislikeButton ryd.content-script.js:794 <ytd-toggle-button-renderer id=​"dislike-button" is-shorts class=​"style-scope ytd-like-button-renderer" vertically-aligned button-renderer=​"true">​…​​ ryd.content-script.js:786 getDislikeButton ryd.content-script.js:794 <ytd-toggle-button-renderer id=​"dislike-button" is-shorts class=​"style-scope ytd-like-button-renderer" vertically-aligned button-renderer=​"true">​…​​ ryd.content-script.js:786 getDislikeButton

image

Think there is some underlying logic in state where we re-querySelect if we error or something or it might be some mutationobserver implementation that I haven't looked into. If someone has insight into this, let us know.

To summarize: This should be fine 😅.

EDIT: More importantly, when inspecting the service worker's network tab we can see the request succeeding even if we had the error in the console. API is still getting the info it needs.

tdreams2 commented 9 months ago

Think there is some underlying logic in state where we re-querySelect if we error or something or it might be some mutationobserver implementation that I haven't looked into. If someone has insight into this, let us know.

Actually there is a mutationObserver I think and it causing issues

To produce the error:

  1. go to YouTube home page and refresh the page.
  2. go to any short video from home page and the error will come up. if you go back to the home page and click another short video the error shows and so on.

To stop the error:

  1. go to any short video from home page
  2. refresh the page you can go back and forth without any issue until you refresh the home page again

mutationObserver code:

let mutationObserver = new Object();

  if (isShorts() && mutationObserver.exists !== true) {
  cLog("initializing mutation observer");
  mutationObserver.options = {
    childList: false,
    attributes: true,
    subtree: false,
  };
  mutationObserver.exists = true;
  mutationObserver.observer = new MutationObserver(function (
    mutationList,
    observer
  ) {
    mutationList.forEach((mutation) => {
      if (
        mutation.type === "attributes" &&
        mutation.target.nodeName === "TP-YT-PAPER-BUTTON" &&
        mutation.target.id === "button"
      ) {
        // cLog('Short thumb button status changed');
        if (mutation.target.getAttribute("aria-pressed") === "true") {
          mutation.target.style.color =
            mutation.target.parentElement.parentElement.id === "like-button"
              ? getColorFromTheme(true)
              : getColorFromTheme(false);
        } else {
          mutation.target.style.color = "unset";
        }
        return;
      }
      cLog(
        "unexpected mutation observer event: " + mutation.target + mutation.type
      );
    });
  });
}

for some reason the MutationObserver doesn't initiate if you produce the error steps above, and the only way to initialize it is by refreshing the page while we are on shorts path

AminoffZ commented 9 months ago

Actually there is a mutationObserver I think and it causing issues

Unless there are more issues than the errors in the console from before, I don't think it's a huge priority but something we should look at next.

PatrickG commented 9 months ago

This change doesn't really make any sense, does it? If getLikeButton() returns something, || getLikeButton().parentNode is not used. If getLikeButton() returns nothing, || getLikeButton().parentNode will throw an error. Also, textNodeClone is not supposed to be the whole like button.

I fixed it locally like this:

const textNodeClone = (getLikeButton().querySelector("button > div[class*='cbox']") || (getLikeButton().querySelector('div > span[role="text"]') || document.querySelector('button > div.yt-spec-button-shape-next__button-text-content > span[role="text"]')).parentNode).cloneNode(true);

Since the like button does not have any <span role="text"> elements anymore for me, I simply use any button element on the page (they all have the same structure).

AminoffZ commented 9 months ago

Fair point. It's interesting to note that just const textNodeClone = getLikeButton().cloneNode(true); seems to be working for me now also. Do we know when and why the specific selectors work or don't? In which situations are we using:

Anarios commented 1 month ago

This seems to have been fixed by other PRs, please reopen if experiencing issues with the latest extension version