Last active
October 22, 2022 14:14
-
-
Save vaaski/b503fc9687776f09992bc604b82a035a to your computer and use it in GitHub Desktop.
Clean up unnecessary YouTube UI junk
This file contains hidden or 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 cleanup | |
| // @version 1 | |
| // @description cleans up youtube | |
| // @author vaaski | |
| // @match https://youtube.com/* | |
| // @match https://*.youtube.com/* | |
| // @grant none | |
| // @run-at document-end | |
| // @namespace https://gist.github.com/vaaski/b503fc9687776f09992bc604b82a035a | |
| // @updateURL https://gist.github.com/vaaski/b503fc9687776f09992bc604b82a035a/raw | |
| // @downloadURL https://gist.github.com/vaaski/b503fc9687776f09992bc604b82a035a/raw | |
| // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com | |
| // ==/UserScript== | |
| !(async () => { | |
| const toTitleSelector = (/** @type { string } */ s) => `[title='${s}']` | |
| const removeByTitle = [ | |
| "Library", | |
| "Your videos", | |
| "Your movies", | |
| "Purchases", | |
| "Originals", | |
| "YouTube Music", | |
| ] | |
| const removeBySelector = [ | |
| "#guide-wrapper #footer", // footer in sidebar with copyright stuff | |
| "#sections>ytd-guide-section-renderer:nth-child(2)", // list of subscriptions section in sidebar | |
| "ytd-feed-filter-chip-bar-renderer", // "chip filters up top" | |
| "#voice-search-button", // self-explanatory | |
| ...removeByTitle.map(toTitleSelector), | |
| ] | |
| // "[is-post] img:not([width])" are the (often animated) pictures in "YouTube posts" | |
| const customCSS = ` | |
| ${removeBySelector.join()}, | |
| [is-post] img:not([width]) { | |
| display: none !important; | |
| }` | |
| /** | |
| * get an element with querySelector or wait for it using MutationObserver | |
| * @param {string} selector a css selector | |
| * @param {HTMLElement} parent the parent in which to search for | |
| * @returns {Promise<HTMLElement>} | |
| */ | |
| const getElement = (selector, parent = document.querySelector("ytd-app") ?? document.body) => { | |
| return new Promise((res) => { | |
| /** @type { HTMLElement | null } */ | |
| let query = parent.querySelector(selector) | |
| if (query) return res(query) | |
| console.log(`waiting for ${selector}`) | |
| let timeout = 0 | |
| const observer = new MutationObserver((list, obs) => { | |
| for (const mutation of list) { | |
| if (mutation.type === "childList") { | |
| query = parent.querySelector(selector) | |
| if (query) { | |
| obs.disconnect() | |
| clearTimeout(timeout) | |
| return res(query) | |
| } | |
| } | |
| } | |
| }) | |
| observer.observe(parent, { childList: true, subtree: true }) | |
| timeout = setTimeout(() => { | |
| observer.disconnect() | |
| console.log(`observer for ${selector} timed out`) | |
| return res(document.createElement("div")) | |
| }, 5e3) | |
| }) | |
| } | |
| const customStyles = document.createElement("style") | |
| customStyles.innerHTML = customCSS | |
| document.body.appendChild(customStyles) | |
| const showMore = await getElement(toTitleSelector("Show more")) | |
| showMore.click() | |
| const showFewer = await getElement(toTitleSelector("Show fewer")) | |
| showFewer.remove() | |
| const likedVideos = await getElement(toTitleSelector("Liked videos")) | |
| const library = await getElement("#section-items") | |
| library.insertBefore(likedVideos, library.childNodes[1]) | |
| const kids = await getElement(toTitleSelector("YouTube Kids")) | |
| /** @type { HTMLElement | null } */ | |
| const moreFromYoutube = kids.closest("ytd-guide-section-renderer") | |
| if (moreFromYoutube?.style) moreFromYoutube.style.display = "none" | |
| const trending = await getElement(toTitleSelector("Trending")) | |
| /** @type { HTMLElement | null } */ | |
| const explore = trending.closest("ytd-guide-section-renderer") | |
| if (explore?.style) explore.style.display = "none" | |
| })() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment