De-annoyancing the YouTube subscriptions page (UPDATE: added visual video duration indicators)
Categories
YouTube is continuing to get more irritating to use. And water is still wet and the sky, between the chemtrails/clouds, is still blue(ish). Nothing new. Unfortunately, the content creators whose work I enjoy are still uploading there more than anywhere else. Many are still posting to Facebook’s Instagram, as well, for that matter.
“Shorts” (TikTok-alike portrait-mode phonecam vids with different controls than regular videos and no duration numbers given on the subs page), “upcoming” videos that show up in the subs page but aren’t yet viewable, hidden “watch later” overlays one sometimes triggers inadvertently when mousing over a video thumbnail before clicking on it to watch that video, and the number over the bell icon at the top of the page are the YouTube subscriptions-page features which I currently do not admire.
So I wrote a userscript to get rid of the last two (the notifications tally and the treacherous overlays) and gray-out the first two (upcoming vids and shorts): YouTube-Subscriptions-Better-er.user.js. The animated GIF below is from a screen recording I made when making sure the script could keep up with YouTube’s mechanism for loading more content on the fly as one scrolls.
The video thumbnails and some other bits of content are blacked out and the video durations, when provided by YouTube, are Xed out using a second userscript: YouTube-Subscriptions-Blackout.user.js.
AlphaGoogTube’s army of flying monkeys will keep fiddling with the design of YouTube and the design of the tools that, I suspect, generate the tools that generate the tools that, some number of levels of turtles down, eventually generate the yucky markup (e.g. the same id
attribute value appears numerous times in the source) for YouTube’s subs page. Expect these userscripts, which rely heavily on CSS selectors (employed via querySelectorAll()
& querySelector()
) to stop working partially or completely at some point in the not-too-distant future. Useful in the meantime, however.
UPDATE: Visual Video Duration Indicators
The numeric video durations provided in overlays for non-‘short’ videos are nice, but not very useful if one is glancing at one’s subscriptions page and looking for videos of a certain length (e.g. something long to play as background noise during tedious household chores), so I added visual indicators of video duration. Videos shorter than one minute get nothing, videos under sixty minutes long get a red horizontal bar (length proportional to their fraction of an hour), and any video longer than an hour gets a full-length orange bar:
I’ve linked both userscripts already but will include them in their totality below (2 versions of the subscriptions page de-annoyancer are included: with and without video duration graphics). As always, user beware, I give no warranties or assurances of usability, merchantability, safety, etc.
YouTube Subscriptions Better-er (full text)
// ==UserScript== // @name YouTube Subscriptions Better-er // @namespace http://www.eatdirtshit.rocks/ // @version 0.03 // @downloadURL http://eatdirtshit.rocks/userscripts/YouTube-Subscriptions-Better-er.user.js // @description Adds some helpful functionality to the YouTube Subscriptions page. // @author Brian Donovan // @match https://www.youtube.com/feed/subscriptions // @grant none // @run-at document-idle // ==/UserScript== 'use strict'; // --- 0. Create STYLE element to which rules we need will be added later var ndStyleElement = document.createElement('style'); document.head.appendChild(ndStyleElement); var ndStylesheet = ndStyleElement.sheet; // --- 3. Obscure shorts --- 3a create animation var strHoverClassDef1 = `.hoverfadein { filter:opacity(10%); transition: 0.5s ease-out 100ms; }`; var strHoverClassDef2 = `.hoverfadein:hover { filter:opacity(100%); }`; ndStylesheet.insertRule(strHoverClassDef1, ndStylesheet.cssRules.length); ndStylesheet.insertRule(strHoverClassDef2, ndStylesheet.cssRules.length); // --- 5. Duration indicators --- 5a create styles var strVidDurationShellClassDef = `.vid-duration-shell { height: 5px; width: 100%; position: absolute; top: 88%; left: 0px; }`; var strVidDurationBarHolderClassDef = `.vid-duration-bar-holder { background-color: rgb(0,0,0,0.75); width: 80%; height: 100%; border: 1px solid black; border-radius: 2px; margin: 5px auto; }`; var strVidDurationBarClassDef = `.vid-duration-bar { background-color: red; height: 100%; width: 0px; border: 1px solid white; }`; ndStylesheet.insertRule(strVidDurationShellClassDef, ndStylesheet.cssRules.length); ndStylesheet.insertRule(strVidDurationBarHolderClassDef, ndStylesheet.cssRules.length); ndStylesheet.insertRule(strVidDurationBarClassDef, ndStylesheet.cssRules.length); // ----------------------------------------------------------------------------- function rtnNodeDurationIndicator(){ var ndVidDurationIndicator = document.createElement('div'); ndVidDurationIndicator.className = 'vid-duration-shell'; var ndVidDurationIndicatorBarHolder = document.createElement('div'); ndVidDurationIndicatorBarHolder.className = 'vid-duration-bar-holder'; var ndVidDurationIndicatorBar = document.createElement('div'); ndVidDurationIndicatorBar.className = 'vid-duration-bar'; ndVidDurationIndicatorBarHolder.appendChild(ndVidDurationIndicatorBar); ndVidDurationIndicator.appendChild(ndVidDurationIndicatorBarHolder); return ndVidDurationIndicator; } (function() { var mutationObserver = new MutationObserver(function(mutations) { // --- 1. Get rid of numeric overlay above the bell icon var ndNumberOverBellIcon = document.querySelector('.yt-spec-icon-badge-shape__badge'); if (ndNumberOverBellIcon !== null) { ndNumberOverBellIcon.remove(); } // --- 2. Remove hover overlays var ndlstVideoHoverOverlays = document.querySelectorAll('#hover-overlays'); for (var i=0; i<ndlstVideoHoverOverlays.length; i++) { ndlstVideoHoverOverlays[i].remove(); } // --- Obscure shorts --- 3b. identify shorts and apply style changes var ndlstShortsOverlays = document.querySelectorAll('[overlay-style="SHORTS"]'); for (var i=0; i<ndlstShortsOverlays.length; i++) { var ndOneVideoShort = ndlstShortsOverlays[i].closest('ytd-grid-video-renderer'); if (!ndOneVideoShort.classList.contains('hoverfadein')) { ndOneVideoShort.className += ' hoverfadein'; } } // --- 4. Obscure 'upcoming' videos which can't yet be watched var ndlstTimeStatusUpcoming = document.querySelectorAll('[aria-label="Upcoming"]'); for (var i=0; i<ndlstTimeStatusUpcoming.length; i++) { var ndOneVideoUpcoming = ndlstTimeStatusUpcoming[i].closest('ytd-grid-video-renderer'); if (!ndOneVideoUpcoming.classList.contains('hoverfadein')) { ndOneVideoUpcoming.className += ' hoverfadein'; } } // --- 5. Duration indicators --- 5c figure out the duration of each video and insert their duration indicator var ndlstVideoDurations = document.querySelectorAll('ytd-thumbnail-overlay-time-status-renderer'); for (var i=0; i<ndlstVideoDurations.length; i++) { var ndThisVideoOverlays = ndlstVideoDurations[i].closest('#overlays'); if (ndThisVideoOverlays.querySelectorAll('.vid-duration-shell').length > 0) { continue; } var strDuration = ndlstVideoDurations[i].textContent.trim(); var arrDurationParts = strDuration.trim().split(':'); if ( (arrDurationParts.length <= 1) || !( arrDurationParts.every( (strPart) => !isNaN(strPart) ) ) ){ // Something not right (not a traditional style video duration) continue; } // ----------------------------------------------------------------------- if (arrDurationParts.length === 2) { var intMinutes = parseInt(arrDurationParts[0]); if (intMinutes === 0) { // Duration has 2 parts but 1st is zero, so video is mere seconds long continue; } else { // Duration has 2 parts and 1st (minutes) is nonzero var intPercentOfHour = Math.round( (intMinutes/60)*100 ); ndThisVideoOverlays.appendChild(rtnNodeDurationIndicator()); var ndBar = ndThisVideoOverlays.querySelector('.vid-duration-bar'); if (ndBar !== null) { ndBar.style.width = intPercentOfHour.toString()+'%'; // fractional bar } } } else { // Duration has 3 parts, so an hour-plus ndThisVideoOverlays.appendChild(rtnNodeDurationIndicator()); var ndBar = ndThisVideoOverlays.querySelector('.vid-duration-bar'); if (ndBar !== null) { ndBar.style.width = '100%'; // full-length bar ndBar.style.backgroundColor = 'orange'; ndBar.style.border = '1px solid yellow'; } } //----------------------------------------------- } }); mutationObserver.observe(document.documentElement, {childList: true, subtree: true}); })();
YouTube Subscriptions Better-er [OLD, NO VIDEO DURATION VISUALIZATIONS] (full text)
// ==UserScript== // @name YouTube Subscriptions Better-er // @namespace http://www.eatdirtshit.rocks/ // @version 0.02c // @downloadURL http://eatdirtshit.rocks/userscripts/YouTube-Subscriptions-Better-er.user.js // @description Adds some helpful functionality to the YouTube Subscriptions page. // @author Brian Donovan // @match https://www.youtube.com/feed/subscriptions // @grant none // @run-at document-idle // ==/UserScript== 'use strict'; // --- 0. Create STYLE element to which rules we need will be added later var ndStyleElement = document.createElement('style'); document.head.appendChild(ndStyleElement); var ndStylesheet = ndStyleElement.sheet; // --- 3. Obscure shorts --- 3a create animation var strHoverClassDef1 = `.hoverfadein { filter:opacity(10%); transition: 0.5s ease-out 100ms; }`; var strHoverClassDef2 = `.hoverfadein:hover { filter:opacity(100%); }`; ndStylesheet.insertRule(strHoverClassDef1, ndStylesheet.cssRules.length); ndStylesheet.insertRule(strHoverClassDef2, ndStylesheet.cssRules.length); (function() { var mutationObserver = new MutationObserver(function(mutations) { // --- 1. Get rid of numeric overlay above the bell icon var ndNumberOverBellIcon = document.querySelector('.yt-spec-icon-badge-shape__badge'); if (ndNumberOverBellIcon !== null) { ndNumberOverBellIcon.remove(); } // --- 2. Remove hover overlays var ndlstVideoHoverOverlays = document.querySelectorAll('#hover-overlays'); for (var i=0; i<ndlstVideoHoverOverlays.length; i++) { ndlstVideoHoverOverlays[i].remove(); } // --- Obscure shorts --- 3b. identify shorts and apply style changes var ndlstShortsOverlays = document.querySelectorAll('[overlay-style="SHORTS"]'); for (var i=0; i<ndlstShortsOverlays.length; i++) { var ndOneVideoShort = ndlstShortsOverlays[i].closest('ytd-grid-video-renderer'); if (!ndOneVideoShort.classList.contains('hoverfadein')) { ndOneVideoShort.className += ' hoverfadein'; } } // --- 4. Obscure 'upcoming' videos which can't yet be watched var ndlstTimeStatusUpcoming = document.querySelectorAll('[aria-label="Upcoming"]'); for (var i=0; i<ndlstTimeStatusUpcoming.length; i++) { var ndOneVideoUpcoming = ndlstTimeStatusUpcoming[i].closest('ytd-grid-video-renderer'); if (!ndOneVideoUpcoming.classList.contains('hoverfadein')) { ndOneVideoUpcoming.className += ' hoverfadein'; } } }); mutationObserver.observe(document.documentElement, {childList: true, subtree: true}); })();
Note that the blackout script doesn’t run automatically, because context-menu
is specified for @run-at
. It has to be invoked when you’re on the YT subs page, via right-click > Tampermonkey > YouTube Subscriptions Blackout or the Greasemonkey-equivalent actions. Once triggered, it will work on the page as needed until you leave or refresh.
YouTube Subscriptions Blackout (full text)
// ==UserScript== // @name YouTube Subscriptions Blackout // @namespace http://www.eatdirtshit.rocks/ // @version 0.01 // @downloadURL http://eatdirtshit.rocks/userscripts/YouTube-Subscriptions-Blackout.user.js // @description Blacks out content, nukes vid duratios, etc. // @author Brian Donovan // @match https://www.youtube.com/feed/subscriptions // @grant none // @run-at context-menu // ==/UserScript== 'use strict'; var ndStyleElement = document.createElement('style'); document.head.appendChild(ndStyleElement); var ndStylesheet = ndStyleElement.sheet; var arrRules = [`div#meta > * > * { filter: brightness(0%) !important; background-color: black !important; }`, `img#img { filter: brightness(0%) !important; background-color: black !important; }`, `span#country-code { display:none; }`, `ytd-guide-section-renderer.style-scope.ytd-guide-renderer:nth-of-type(2) div#items > * { filter: brightness(0%) !important; }`, `ytd-guide-section-renderer.style-scope.ytd-guide-renderer:nth-of-type(2) div#items yt-formatted-string { background-color:black !important; }`, `img.yt-core-image--fill-parent-height.yt-core-image--fill-parent-width.yt-core-image.yt-core-image--content-mode-scale-aspect-fill.yt-core-image--loaded { filter: brightness(0%) !important; }`]; for (var i=0; i<arrRules.length; i++) { ndStylesheet.insertRule(arrRules[i], ndStylesheet.cssRules.length); } function XOutVidDurations() { var ndlstVidDurationHolder = document.querySelectorAll('span#text.ytd-thumbnail-overlay-time-status-renderer'); for (var i=0; i<ndlstVidDurationHolder.length; i++) { var strContentVidDur = ndlstVidDurationHolder[i].textContent; var intIndexColonChar = strContentVidDur.indexOf(':'); if (intIndexColonChar > 0){ if (!isNaN(strContentVidDur[intIndexColonChar+1])){ ndlstVidDurationHolder[i].textContent = 'XX:XX'; } } } } XOutVidDurations(); (function() { var mutationObserver = new MutationObserver(function(mutations) { XOutVidDurations(); }); mutationObserver.observe(document.documentElement, {childList: true, subtree: true}); })();