Greasy Fork is available in English.

Discussions » Development

Help with modifying script

§
Posted: 2024/07/28

I am not well versed on JS, I am good at trial and error. I have a heavily modified script I am trying to make work:


// ==UserScript==
// @name            	Youtube removes clickbait from thumbnails
// @namespace       	https://greasyfork.org/users/821661
// @match           	https://www.youtube.com/*
// @match           	https://m.youtube.com/*
// @author          	hdyzen
// @description     	Removes clickbait from thumbnails changing to middle thumb of video
// @license         	MIT
// ==/UserScript==
'use strict';

const regexThumbName = /https:\/\/i\.ytimg\.com\/(.*)\/(hqdefault|hq720|mqdefault|sddefault)\.jpg/;
const replacedThumb = 'https://i.ytimg.com/$1/hq2.jpg';
const ThumbID = 'hq2.jpg';

function changeThumbsOnInit() {
    document.addEventListener('image-loaded', e => {
        if (!e.target.src.includes(ThumbID)) {
            e.target.src = e.target.src.replace(regexThumbName, replacedThumb);
        }
    });
}

changeThumbsOnInit();

I am trying to replace every thumbnail with a "hq2" version. It works fine on the desktop version of YouTube, but for some reason it does not work on m.youtube.com. I have tested on both Firefox with device mode and on extensions on iOS. Is there something different about the mobile version that would break this?

I think there may be an issue with the event listener as it works in the console for Firefox when adding the code manually. Any help please?

§
Posted: 2024/07/29

Is there something different about the mobile version that would break this?

I guess there is no 'image-loaded' event

it works in the console for Firefox when adding the code manually

Does not work for me, tested on Chrome devtools m.youtube

You can also check these:

https://github.com/pietervanheijningen/clickbait-remover-for-youtube

https://dearrow.ajay.app/

§
Posted: 2024/07/29
I guess there is no 'image-loaded' event

There does appear to be an image-loaded event and it is labelled the same but some of the letters are changed, for the desktop one the function is:


function(r) {
  Ii(r.target, "yt-core-image--loaded");
  b.notifyOnLoaded && r.target.dispatchEvent(new Event("image-loaded", {
    bubbles: !0,
    composed: !0
  }));
  l == null || l(r)
}

for the mobile one the function is


function(n) {
  _.Vs(n.target, "yt-core-image--loaded");
  b.wy && n.target.dispatchEvent(new Event("image-loaded", {
    bubbles: !0,
    composed: !0
  }));
  h == null || h(n)
}

I'm not sure what the differences mean.

I understand on desktop (and on android) it's possible to add extensions that do this for me but I am trying to make it work on iOS. As I said before, loading the desktop site in iOS the script works fine.

§
Posted: 2024/07/29

I'm not sure what the differences mean

They're just obfuscated differently. Functionality is the same. You can see that there is some b.notifyOnLoaded option which decides whether there is going to be an event dispatch or not. I guess this one is false for the mobile version, which means this approach is not going to work for you

§
Posted: 2024/07/29
Edited: 2024/07/29

There does appear to be an image-loaded event

There are might be tons of code. It is irrelevant if it's not being used in the way you can make use of

§
Posted: 2024/07/30

Thank you for your input. I went through every event on the mobile YouTube site and settled on scroll. I also reused the code from the Clickbait Remover extension. Will scroll cause a negative impact on battery life on a phone, for this use case? I'm not well enough versed on mutation observers to start down that path.


// ==UserScript==
// @name        Clickbait remover script
// @namespace   scripts
// @match       https://m.youtube.com/watch*
// @grant       none
// @version     1.0
// @license     MIT
// ==/UserScript==

function updateThumbnails() {
  const imgElements = document.getElementsByTagName('img');

  for (let i = 0; i < imgElements.length; i++) {
    if (imgElements[i].src.match('https://i.ytimg.com/(vi|vi_webp)/.*/(hqdefault|mqdefault|sddefault|hq720)(_custom_[0-9]+)?.jpg?.*')) {
      let url = imgElements[i].src.replace(/(hqdefault|mqdefault|sddefault|hq720)(_custom_[0-9]+)?.jpg/, 'hq2.jpg');

      imgElements[i].src = url;
    }
  }
}

document.addEventListener("scroll", updateThumbnails);
§
Posted: 2024/07/30

https://streamable.com/4l21aj

Looks pretty bad. At least mark the images that are already processed and don't process them again

§
Posted: 2024/07/30
At least mark the images that are already processed and don't process them again

Any input on how I could do this? I'm only good at modifying other peoples code.

I have added a throttle of one second on the script for now


// ==UserScript==
// @name        Clickbait remover script
// @namespace   scripts
// @match       https://m.youtube.com/*
// @grant       none
// @version     1.0
// @license     MIT
// ==/UserScript==

//replace thumbnails
function updateThumbnails() {
  const imgElements = document.getElementsByTagName('img');

  for (let i = 0; i < imgElements.length; i++) {
    if (imgElements[i].src.match('https://i.ytimg.com/(vi|vi_webp)/.*/(hqdefault|mqdefault|sddefault|hq720)(_custom_[0-9]+)?.jpg?.*')) {
      let url = imgElements[i].src.replace(/(hqdefault|mqdefault|sddefault|hq720)(_custom_[0-9]+)?.jpg/, 'hq2.jpg');

      imgElements[i].src = url;
    }
  }
}

//throttle scrolling
function throttle(callback, limit) {
    var wait = false;
    return function () {
        if (!wait) {
            callback.call();
            wait = true;
            setTimeout(function () {
                wait = false;
            }, limit);
        }
    }
}

function onScroll(event) {
  updateThumbnails();
}

window.addEventListener('scroll', throttle(onScroll, 1000), false);
§
Posted: 2024/07/31
// ==UserScript==
// @name          Clickbait remover script
// @description   Clickbait remover script
// @namespace     scripts
// @match         https://m.youtube.com/*
// @match         https://www.youtube.com/*
// @version       1.0
// @require       https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js#sha512-wkU3qYWjenbM+t2cmvw2ADRRh4opbOYBjkhrPGHV7M6dcE/TR0oKpoDkWXfUs3HrulI2JFuTQyqPLRih1V54EQ==
// @grant         none
// ==/UserScript==

(function() {
  'use strict';

  const matchRegex = /https:\/\/i(\d|).ytimg.com\/(vi|vi_webp)\/.*\/(hqdefault|mqdefault|sddefault|hq720)(_custom_[0-9]+)?.jpg?.*/;
  const replaceRegex = /(hqdefault|mqdefault|sddefault|hq720)(_custom_[0-9]+)?.jpg/;

  document.arrive('img', { existing: true }, (img) => {
    if (img.src) {
      if (img.src.match(matchRegex)) img.src = img.src.replace(replaceRegex, 'hq2.jpg');
    } else {
      const observer = new MutationObserver((mutationList, observer) => {
        if (img.src.match(matchRegex)) img.src = img.src.replace(replaceRegex, 'hq2.jpg');

        observer.disconnect();
      });

      observer.observe(img, { attributes: true });
    }
  });
})();
§
Posted: 2024/07/31

Wow that is a far better script than I could have written. I had to paste the library at the top of my version as the extension I use on mobile doesn't support that.

Thank you so much.

§
Posted: 2024/08/19

Any ideas why the script has stopped working recently on m.youtube.com? It works on www.youtube.com still.
Pasting the code in manually into the console runs it on the page, so it seems like an observer issue.

§
Posted: 2024/08/20

That was a little of a bad approach. Just need another one filter for an empty src

// ==UserScript==
// @name          Clickbait remover script
// @description   Clickbait remover script
// @namespace     scripts
// @match         https://m.youtube.com/*
// @match         https://www.youtube.com/*
// @version       1.1
// @require       https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js#sha512-wkU3qYWjenbM+t2cmvw2ADRRh4opbOYBjkhrPGHV7M6dcE/TR0oKpoDkWXfUs3HrulI2JFuTQyqPLRih1V54EQ==
// @grant         none
// ==/UserScript==

(function() {
  'use strict';

  const matchRegex = /https:\/\/i(\d|).ytimg.com\/(vi|vi_webp)\/.*\/(hqdefault|mqdefault|sddefault|hq720)(_custom_[0-9]+)?.jpg?.*/;
  const replaceRegex = /(hqdefault|mqdefault|sddefault|hq720)(_custom_[0-9]+)?.jpg/;

  document.arrive('img', { existing: true }, (img) => {
    if (img.src) {
      if (img.src.match(matchRegex)) img.src = img.src.replace(replaceRegex, 'hq2.jpg');
    } else {
      const observer = new MutationObserver((mutationList, observer) => {
        if (!img.src) return;

        if (img.src.match(matchRegex)) img.src = img.src.replace(replaceRegex, 'hq2.jpg');

        observer.disconnect();
      });

      observer.observe(img, { attributes: true });
    }
  });
})();
§
Posted: 2024/08/20

I mean, I've should of filtered it out in a first place

Post reply

Sign in to post a reply.