Last active
May 15, 2021 04:25
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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