Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Disable Infinite Scroll
- // @namespace http://tampermonkey.net/
- // @version 0.1
- // @description disable infinite scrolling on youtube
- // @author You
- // @match *://*.youtube.com/*
- // @match *://*.youtu.be/*
- // @grant GM_addStyle
- // @grant GM_getValue
- // @grant GM.getValue
- // @grant GM.setValue
- // @grant GM_setValue
- // @grant GM_registerMenuCommand
- // @grant unsafeWindow
- // @run-at document-start
- // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
- // ==/UserScript==
- 'use strict';
- /* PAGE LOCATION STATE */
- let pageLocation = PAGE_LOCATION.Home;
- const getPageLocation = () => {
- const location = window.location;
- if (location.pathname === '/') {
- return PAGE_LOCATION.Home;
- } else if (location.href.includes('/watch?')) {
- return PAGE_LOCATION.Video;
- } else if (location.pathname.startsWith('/user/') || location.pathname.startsWith('/c/')) {
- return PAGE_LOCATION.Channel;
- } else if (location.href.includes('/feed/trending')) {
- return PAGE_LOCATION.Trending;
- } else if (location.href.includes('/feed/explore')) {
- return PAGE_LOCATION.Explore;
- } else if (location.href.includes('/results?')) {
- return PAGE_LOCATION.SearchResults;
- } else if (location.href.includes('/shorts/')) {
- return PAGE_LOCATION.Shorts;
- }
- };
- const setPageLocation = () => {
- pageLocation = getPageLocation();
- };
- /* OBSERVERS */
- let homeObserver = null;
- let playerObserver = null;
- const PAGE_LOCATION = {
- "Home": 0,
- "Video": 1,
- "Channel": 2,
- "Trending": 3,
- "Explore": 4,
- "SearchResults": 5,
- "Shorts": 6
- };
- const extensionName ="YouTube Redux";
- const logStyle = `background-image: linear-gradient(135deg, #e2e2e2 0%, rgba(255,255,255,1) 50%, rgba(255,255,255,1) 100%); color: black; padding: 5px; border-radius: 5px;`;
- const log = (input, isError) => {
- if (typeof input === "object") {
- console.log(`%c${extensionName}: ${typeof input}`, logStyle);
- isError? console.error(input) : console.log(input);
- } else {
- console.log(`%c${extensionName}: ${input}`, logStyle);
- }
- };
- const INFINITE_SCROLLING_MODE = {
- "Comments": 0,
- "Related": 1
- };
- let reduxSettings = {
- "autoConfirm":true,
- "disableInfiniteScrolling": true,
- "fixHomepage":true,
- };
- const defaultSettings = {
- "gridItems": 6,
- "hideAutoplayButton": false,
- "hideCastButton": false,
- "darkPlaylist": true,
- "smallPlayer": true,
- "smallPlayerWidth": 853,
- "showRawValues": true,
- "classicLikesColors": false,
- "autoConfirm": true,
- "disableInfiniteScrolling": true,
- "blackBars": false,
- "rearrangeInfoRe": true,
- "rearrangeInfoNew": true,
- "classicLogoChoice": 2017,
- "filterMainRe": false,
- "filterVideo": true,
- "filterMiniRe": true,
- "extraLayout": true,
- "darkerRed": false,
- "trueFullscreen": false,
- "favicon": 3,
- "channelListView": false,
- "squareAvatar": true,
- "squareSubs": true,
- "hideHomeAvatars": false,
- "noHomeScalingRe": true,
- "squareSearch": false,
- "extraSidebarStyles": true,
- "altVideoLayout": false,
- "altVideoLayoutExtra": false,
- "playlistsFirst": true,
- "sortFoundPlaylists": true,
- "customTitleFont": false,
- "titleFontValue": "Arial",
- "hideVoiceSearch": false,
- "subBorder": true,
- "classicLikesStyle": true,
- "hideApps": false,
- "classicLikesIconColors": false,
- "hideJoinButton": false,
- "hideClip": false,
- "hidePeopleSearch": true,
- "trimSubs": false,
- "trimViews": false,
- "altStrings": false,
- "extraChannel": true,
- "noPlayerActionAnimations": false,
- "altLoader": false,
- "altLoaderSmaller": false,
- "showChangelog": true,
- "oldIcons": true,
- "myChannel": false,
- "myChannelCustomText": "My channel",
- "extraComments": true,
- "collapseSidebar": false,
- "hideRelatedVideoAge": true,
- "hideVideoCategory": true,
- "hideLicensingInfo": true,
- "moveAutoplay": true,
- "disableMiniplayer": false,
- "hideCountryCode": false,
- "hideCollapsedChat": false,
- "disableVideoPreview": false,
- "autoExpandPlaylists": false,
- "autoExpandSubs": false,
- "fixHomepage": true,
- "compatibleDislikesRe": true,
- "hideDislikes": false,
- "hideDownload": false,
- "hideChaptersInDescription": true,
- "hideMusicInDescription": false,
- "hideHeatmap": false
- };
- let flags = {
- "likesChanged":false,
- "stylesChanged":false,
- "isRearranged":false,
- "isRearrangedNew":false,
- "likesTracked":false,
- "recalcListenersAdded":false,
- "trueFullscreenListenersAdded":false,
- "homeObserverAdded": false
- };
- let alignRetry = {
- startCount: 0,
- maxCount: 5,
- timeout: 20
- };
- let YTReduxURLPath;
- let YTReduxURLSearch;
- let confirmInterval;
- let observerComments;
- let observerRelated;
- let intervalsArray = [];
- let isCheckingRecalc = false;
- function startObservingScrolling(mode) {
- let maxComments = 20;
- let commentsInterval = 20;
- let commentsContElement;
- let maxRelated;
- let relatedInterval = 20;
- let relatedElement;
- let related;
- let relatedContinuation;
- function disableInfiniteComments() {
- let comments = document.querySelectorAll('#contents > ytd-comment-thread-renderer');
- commentsContElement = document.querySelector('ytd-comments#comments ytd-item-section-renderer > #contents > ytd-comment-thread-renderer + ytd-continuation-item-renderer');
- if (comments.length >= maxComments && commentsContElement != null) {
- observerComments.disconnect();
- commentsContElement.remove();
- if (document.querySelector('#show-more-comments') == null) {
- addCommentsButton();
- }
- }
- }
- function disableInfiniteRelated() {
- setLayoutDifferences();
- if (related.length >= maxRelated && relatedContinuation != null) {
- observerRelated.disconnect();
- relatedContinuation.remove();
- if (document.querySelector('#show-more-related') == null) {
- addRelatedButton();
- }
- }
- }
- function addCommentsButton() {
- let showMoreComments = document.createElement('div');
- let continueElement = commentsContElement;
- let showMoreText = document.querySelector('.more-button.ytd-video-secondary-info-renderer') == null ? 'SHOW MORE' : document.querySelector('.more-button.ytd-video-secondary-info-renderer').textContent;
- showMoreComments.id = 'show-more-comments';
- showMoreComments.style = 'text-align:center; margin-bottom: 16px; margin-right: 15px;';
- showMoreComments.innerHTML = '<input type="button" style="font-family: Roboto, Arial, sans-serif; padding-top: 9px; width: 100%; border-top: 1px solid #e2e2e2; border-bottom: none; border-left: none; border-right: none; background:none; font-size: 1.1rem; outline: none; cursor:pointer; text-transform: uppercase; font-weight: 500; color: var(--redux-spec-text-secondary); letter-spacing: 0.007px; padding-bottom: 8px;"></input>';
- showMoreComments.querySelector('input').value = showMoreText;
- contentsElement.append(showMoreComments);
- document.querySelector('#show-more-comments').onclick = function() {
- let comments = document.querySelector('ytd-comments#comments ytd-item-section-renderer > #contents');
- comments.append(continueElement);
- window.scrollBy({top: 50, left: 0, behavior: "smooth"});
- this.remove();
- maxComments += commentsInterval;
- observerComments.observe(contentsElement, observerConfig);
- };
- }
- function addRelatedButton() {
- let showMoreRelated = document.createElement('div');
- let continueElement = relatedContinuation;
- let showMoreText = document.querySelector('.more-button.ytd-video-secondary-info-renderer') == null ? 'SHOW MORE' : document.querySelector('.more-button.ytd-video-secondary-info-renderer').textContent;
- showMoreRelated.id = 'show-more-related';
- showMoreRelated.style = 'text-align:center; margin-top: 4px; margin-right: 15px';
- showMoreRelated.innerHTML = '<input type="button" style="font-family: Roboto, Arial, sans-serif; padding-top: 9px; width: 100%; border-top: 1px solid #e2e2e2; border-bottom: none; border-left: none; border-right: none; background:none; font-size: 1.1rem; outline: none; cursor:pointer; text-transform: uppercase; font-weight: 500; color: var(--redux-spec-text-secondary); letter-spacing: 0.007px;"></input>';
- showMoreRelated.querySelector('input').value = showMoreText;
- relatedElement.append(showMoreRelated);
- document.querySelector('#show-more-related').onclick = function() {
- relatedElement.append(continueElement);
- window.scrollBy({top: 50, left: 0, behavior: "smooth"});
- this.remove();
- maxRelated += relatedInterval;
- observerRelated.observe(relatedElement, observerConfig);
- };
- }
- function setLayoutDifferences() {
- if (document.querySelector('#secondary > #secondary-inner > #related > ytd-watch-next-secondary-results-renderer > #items').childElementCount <= 3) { //condition for differences in layout between YT languages
- relatedElement = document.querySelector('#secondary > #secondary-inner > #related > ytd-watch-next-secondary-results-renderer > #items > ytd-item-section-renderer > #contents');
- related = relatedElement.querySelectorAll('ytd-compact-video-renderer, ytd-compact-radio-renderer, ytd-compact-playlist-renderer'); //normal video + mix + playlist
- relatedContinuation = relatedElement.querySelector('ytd-continuation-item-renderer');
- } else {
- relatedElement = document.querySelector('#secondary > #secondary-inner > #related > ytd-watch-next-secondary-results-renderer > #items');
- related = relatedElement.querySelectorAll('.ytd-watch-next-secondary-results-renderer');
- relatedContinuation = relatedElement.querySelector('ytd-continuation-item-renderer');
- }
- }
- const observerConfig = {
- childList: true
- };
- const contentsElement = document.querySelector('#comments > #sections > #contents.style-scope.ytd-item-section-renderer');
- if (mode === INFINITE_SCROLLING_MODE.Comments) {
- if (!!document.querySelector('#show-more-comments')) {document.querySelector('#show-more-comments').remove();}
- observerComments = new MutationObserver(disableInfiniteComments);
- observerComments.observe(contentsElement, observerConfig);
- const sortButtons = document.querySelectorAll('div[slot="dropdown-content"] > #menu > a');
- sortButtons.forEach(element => {
- element.onclick = resetCommentsObserver;
- });
- } else if (mode === INFINITE_SCROLLING_MODE.Related) {
- if (!!document.querySelector('#show-more-related')) {document.querySelector('#show-more-related').remove();}
- setLayoutDifferences();
- maxRelated = related.length >= 39 ? 20 : related.length; //to reset max on url change;
- if (related.length >= maxRelated && relatedContinuation != null) {
- relatedContinuation.remove();
- addRelatedButton();
- }
- observerRelated = new MutationObserver(disableInfiniteRelated);
- observerRelated.observe(relatedElement, observerConfig);
- }
- function resetCommentsObserver() {
- const comments = document.querySelectorAll('#contents > ytd-comment-thread-renderer');
- comments.forEach(element => {
- element.remove();
- });
- if (!!document.querySelector('#show-more-comments')) {document.querySelector('#show-more-comments').remove();}
- maxComments = 20;
- observerComments.observe(contentsElement, observerConfig);
- }
- }
- function confirmIt() {
- let confirmButton = document.querySelector('paper-dialog > yt-confirm-dialog-renderer > div:last-child > div > #confirm-button') || document.querySelector('ytd-popup-container yt-confirm-dialog-renderer > #main > div.buttons > #confirm-button');
- if (!confirmButton) return;
- let buttonParent = confirmButton.closest('tp-yt-paper-dialog');
- let buttonParentVisible = buttonParent.style.display !== 'none';
- let buttonVisible = document.querySelector('ytd-popup-container tp-yt-paper-dialog:not([aria-hidden="true"])');
- let popupElement = document.querySelector('ytd-popup-container yt-confirm-dialog-renderer > #main > div.buttons > yt-button-renderer');
- let popupTypeCheck = popupElement == null ? false : popupElement.hasAttribute('hidden');
- if (confirmButton != null && !!buttonVisible && popupTypeCheck && buttonParentVisible) {
- confirmButton.click();
- document.querySelector('video').play();
- //log('Clicked at: ' + new Date());
- }
- }
- function waitForElement(selector, interval, callback) {
- let wait = setInterval(() => {
- let element = document.querySelector(selector);
- if (element != null) {
- clearInterval(wait);
- let index = intervalsArray.indexOf(wait); //get index of and remove the previously added interval from array when it's cleared
- intervalsArray.splice(index, 1);
- callback();
- }
- }, interval);
- intervalsArray.push(wait); //add current interval to array
- }
- function changeGridWidth() {
- let styleItem;
- const changeGridAction = () => {
- if (flags.homeObserverAdded) {
- homeObserver.disconnect();
- }
- styleItem = document.querySelector('#primary > ytd-rich-grid-renderer');
- if (!styleItem) return;
- let currentStyle = styleItem.style.cssText;
- let currentStyleArray = currentStyle.split(";");
- for (let i = 0; i < currentStyleArray.length-1; i++) { //split, replace and join settings on the fly
- if (currentStyleArray[i].includes('--ytd-rich-grid-items-per-row')) {
- let splitElement = currentStyleArray[i].split(":");
- splitElement[1] = reduxSettings.gridItems + '!important'; //to override different important from css
- currentStyleArray[i] = splitElement.join(":");
- }
- }
- styleItem.style.cssText = currentStyleArray.join(";");
- if (flags.homeObserverAdded) {
- homeObserver.observe(styleItem, {attributes: true, attributeFilter: ['style']});
- }
- };
- changeGridAction();
- if (pageLocation === PAGE_LOCATION.Home) {
- if (!flags.homeObserverAdded) {
- //observe since YT keeps restoring grid values on page navigation
- homeObserver = new MutationObserver(() => {
- changeGridAction();
- });
- homeObserver.observe(styleItem, {attributes: true, attributeFilter: ['style']});
- flags.homeObserverAdded = true;
- }
- }
- }
- function main() {
- if (reduxSettings.autoConfirm) {
- if (confirmInterval == undefined) {
- confirmInterval = setInterval(confirmIt, 500);
- setInterval(() => {
- let keyboardEvent = document.createEvent('KeyboardEvent');
- let initMethod = typeof keyboardEvent.initKeyboardEvent !== 'undefined' ? 'initKeyboardEvent' : 'initKeyEvent';
- keyboardEvent[initMethod](
- 'keydown', // event type: keydown, keyup, keypress
- true, // bubbles
- true, // cancelable
- window, // view: should be window
- false, // ctrlKey
- false, // altKey
- false, // shiftKey
- false, // metaKey
- 113, // keyCode: unsigned long - the virtual key code, else 0
- 0, // charCode: unsigned long - the Unicode character associated with the depressed key, else 0
- );
- document.dispatchEvent(keyboardEvent);
- }, 60000*10);
- }
- }
- if (reduxSettings.disableInfiniteScrolling && pageLocation === PAGE_LOCATION.Video) {
- waitForElement('#contents > ytd-comment-thread-renderer, #contents > ytd-message-renderer', 10, () => { startObservingScrolling(INFINITE_SCROLLING_MODE.Comments); }); // additional element in selector for videos with disabled comments
- }
- if (reduxSettings.disableInfiniteScrolling && pageLocation === PAGE_LOCATION.Video) {
- waitForElement('#secondary > #secondary-inner > #related > ytd-watch-next-secondary-results-renderer > #items ytd-continuation-item-renderer', 10, () => { startObservingScrolling(INFINITE_SCROLLING_MODE.Related); });
- }
- if (pageLocation === PAGE_LOCATION.Home) {
- waitForElement('#primary > ytd-rich-grid-renderer', 10, changeGridWidth);
- }
- }
- function addClearHomepageEvent(selector, clearPlaylists) {
- const elements = document.querySelectorAll(selector);
- for (const element of elements) {
- element.addEventListener('click', () => {
- const reduxHomeContainerItems = document.querySelectorAll('.redux-home-container > ytd-rich-item-renderer');
- const reduxPlaylistContainerItems = document.querySelectorAll('.redux-playlist > ytd-rich-item-renderer');
- const containerItems = clearPlaylists ? [...reduxHomeContainerItems, ...reduxPlaylistContainerItems] : reduxHomeContainerItems;
- for (const item of containerItems) {
- item.style.opacity = '0';
- }
- setTimeout(() => {
- for (const item of containerItems) {
- item.remove();
- }
- }, 1000);
- });
- }
- }
- function moveTopLevelItems() {
- let topLevelElements = document.querySelectorAll('.ytd-video-primary-info-renderer > #top-level-buttons-computed > *:not(ytd-toggle-button-renderer):not([is-hidden]), #info #flexible-item-buttons > *');
- let infoContents = document.querySelector('#info-contents > ytd-video-primary-info-renderer');
- let infoDiv = document.querySelector('#info-contents div#info');
- let miscButton = document.querySelector('#info-contents ytd-video-primary-info-renderer > yt-icon-button');
- let existingMovedItem = document.querySelector('[redux-last-top-stream]')
- || document.querySelector('yt-icon-button[redux-last-top]')
- || document.querySelector('ytd-button-renderer[redux-last-top]');
- if (reduxSettings.altVideoLayout) {
- document.querySelector('ytd-video-primary-info-renderer').style = 'padding-left: 15px !important; padding-top: 15px !important';
- if (miscButton != null) {
- infoDiv.prepend(miscButton);
- miscButton.style = 'transform: translateY(0px)';
- }
- for (let i = 0; i < topLevelElements.length; i++) {
- infoDiv.prepend(topLevelElements[i]);
- topLevelElements[i].classList.add('redux-moved-info');
- topLevelElements[i].setAttribute('redux-url-check', window.location.search);
- }
- if (reduxSettings.altVideoLayoutExtra) {
- let remainingTopLevel = document.querySelector('#info #top-level-buttons-computed');
- let likesValues = [
- document.querySelectorAll('ytd-toggle-button-renderer #text.ytd-toggle-button-renderer')[0].getAttribute('aria-label'),
- document.querySelectorAll('ytd-toggle-button-renderer #text.ytd-toggle-button-renderer')[1].getAttribute('aria-label')
- ];
- let separator = ", ";
- if (likesValues[0] == null) {
- likesValues[0] = "";
- separator = "";
- }
- if (likesValues[1] == null) {
- likesValues[1] = "";
- separator = "";
- }
- let menu = document.querySelector('#menu.ytd-video-primary-info-renderer');
- let likesText = document.createTextNode(`${likesValues[0]}${separator}${likesValues[1]}`);
- document.querySelector('#info.ytd-video-primary-info-renderer > #menu-container').style = 'transform: translateY(0px) !important;';
- for (let i = 0; i < menu.childNodes.length; i++) { //remove existing text nodes
- if (menu.childNodes[i].nodeType == 3) {
- menu.childNodes[i].remove();
- }
- }
- menu.prepend(likesText);
- infoDiv.prepend(remainingTopLevel);
- }
- } else {
- for (let i = topLevelElements.length-1; i >= 0; i--) {
- infoContents.insertBefore(topLevelElements[i], existingMovedItem);
- topLevelElements[i].classList.add('redux-moved-info');
- topLevelElements[i].setAttribute('redux-url-check', window.location.search);
- }
- }
- }
- function clearStoredIntervals() {
- intervalsArray.forEach(element => {
- clearInterval(element);
- intervalsArray.shift();
- });
- }
- function clearMovedInfo() {
- let moveInfo = document.querySelectorAll('.redux-moved-info');
- moveInfo.forEach(element => element.remove());
- waitForElement('.ytd-video-primary-info-renderer > #top-level-buttons-computed > *:not(ytd-toggle-button-renderer):not([is-hidden])', 10, moveTopLevelItems);
- }
- (() => {
- setPageLocation();
- try {
- main();
- } catch (error) {
- log(error, true);
- }
- if (reduxSettings.fixHomepage) {
- const logoSelector = 'ytd-topbar-logo-renderer#logo';
- waitForElement(logoSelector, 10, () => {
- addClearHomepageEvent(logoSelector);
- });
- const filtersSelector = '[page-subtype="home"] #chips yt-chip-cloud-chip-renderer';
- waitForElement(filtersSelector, 10, () => {
- addClearHomepageEvent(filtersSelector, true);
- });
- }
- YTReduxURLPath = location.pathname;
- YTReduxURLSearch = location.search;
- setInterval(function() {
- if (location.pathname != YTReduxURLPath || location.search != YTReduxURLSearch) {
- setPageLocation();
- YTReduxURLPath = location.pathname;
- YTReduxURLSearch = location.search;
- flags.likesChanged = false;
- if (reduxSettings.disableInfiniteScrolling) {
- if (observerComments != undefined) {
- observerComments.disconnect();
- }
- if (observerRelated != undefined) {
- observerRelated.disconnect();
- }
- let comments = document.querySelectorAll('#contents > ytd-comment-thread-renderer');
- comments.forEach(element => { //remove comments because YT sometimes keeps old ones after url change which messes with comments observer checking their length; also applied when sorting
- element.remove();
- });
- }
- clearStoredIntervals();
- if (!!document.querySelector('.redux-moved-info')
- && pageLocation === PAGE_LOCATION.Video
- && document.querySelector('.redux-moved-info').getAttribute('redux-url-check') != window.location.search) {
- clearMovedInfo(); //contains an interval
- }
- try {
- main();
- } catch (error) {
- log(error, true);
- }
- }
- }, 100);
- })();
Add Comment
Please, Sign In to add comment