Skip to content

Instantly share code, notes, and snippets.

@lassekongo83
Last active May 15, 2021 04:25
Show Gist options
  • Save lassekongo83/673088fc85feaaf33bccdfdc111a62a0 to your computer and use it in GitHub Desktop.
Save lassekongo83/673088fc85feaaf33bccdfdc111a62a0 to your computer and use it in GitHub Desktop.
Replace infinite scrolling on the YouTube homepage grid with a "Load More" button
// ==UserScript==
// @name YouTube Load More
// @namespace Violentmonkey Scripts
// @match https://www.youtube.com/*
// @grant none
// @version 1.0
// @author https://github.com/lassekongo83
// @description Replace infinite scrolling on the homepage grid with a "Load More" button
// ==/UserScript==
// Wait for element helper
// https://stackoverflow.com/a/61511955
function waitForElm(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
}
// Check if element was removed from DOM
// https://stackoverflow.com/a/50397148
function onRemove(element, callback) {
const parent = element.parentNode;
if (!parent) throw new Error("The node must already be attached");
const obs = new MutationObserver(mutations => {
for (const mutation of mutations) {
for (const el of mutation.removedNodes) {
if (el === element) {
obs.disconnect();
callback();
}
}
}
});
obs.observe(parent, {
childList: true,
});
}
// Add style
function addStyle(styleString) {
const style = document.createElement('style');
style.textContent = styleString;
document.head.append(style);
}
function homeScroll() {
const homeBtn = document.createElement('button');
homeBtn.classList.add("ytcp-load-more-button");
homeBtn.innerHTML = "Load more";
waitForElm('[role="main"][page-subtype="home"] ytd-rich-grid-renderer').then(function(elm) {
if (elm !== null) {
elm.appendChild(homeBtn);
// Remove newly inserted buttons on yt-navigation-finish, otherwise there will be a lot of buttons. There's probably a better way to do this.
for(const next of document.body.querySelectorAll('.ytcp-load-more-button')) {
if(next.nextElementSibling) {
next.nextElementSibling.remove();
}
}
}
const homeButton = document.querySelector('[page-subtype="home"] .ytcp-load-more-button');
homeButton.onclick = function() {
// Workaround: quickly removing and inserting the element again to make it load new items without the user having to hover a thumbnail for it to start
const homeCont = document.querySelector('[page-subtype="home"] #contents.ytd-rich-grid-renderer > ytd-continuation-item-renderer');
const richGrid = document.querySelector('[page-subtype="home"] #contents.ytd-rich-grid-renderer');
if (homeCont !== null) {
homeCont.remove();
}
if (richGrid !== null) {
richGrid.append(homeCont);
}
if (homeCont !== null) {
document.querySelector('[page-subtype="home"] #contents.ytd-rich-grid-renderer ytd-continuation-item-renderer').style.visibility = 'visible';
// Stop the infinite loading when the user scrolls down
window.addEventListener('scroll', function() {
document.querySelector('[page-subtype="home"] #contents.ytd-rich-grid-renderer ytd-continuation-item-renderer').style.visibility = 'hidden';
});
}
// Remove the button when no more results are available
function removeHomeScrollButton() {
if (document.querySelector('[page-subtype="home"] #contents.ytd-rich-grid-renderer ytd-continuation-item-renderer') === null) {
homeButton.remove();
}
}
onRemove(document.querySelector('[page-subtype="home"] #contents.ytd-rich-grid-renderer ytd-continuation-item-renderer'), () => removeHomeScrollButton());
};
});
}
function stopHomeScroll() { // CSS to always block the infinite scrolling and getting rid of the "ghost-cards"
addStyle(`[page-subtype="home"] #contents.ytd-rich-grid-renderer ytd-continuation-item-renderer{height:1px; visibility:hidden;} [page-subtype="home"] ytd-continuation-item-renderer #ghost-cards{display:none;}`);
}
stopHomeScroll();
homeScroll();
window.addEventListener('yt-navigate-finish', homeScroll, { passive: true });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment