Youtube Simple URL, Visited and Blacklist

This script is designed to work only on Youtube Trending page. Script cuts the time parameter which is used to continue watching from last position, changes the color of visited links to aqua and most importantly lets you ignore channels on trending page.

Stan na 15-03-2020. Zobacz najnowsza wersja.

// ==UserScript==
// @name         Youtube Simple URL, Visited and Blacklist
// @namespace    http://tampermonkey.net/
// @version      0.51
// @description  This script is designed to work only on Youtube Trending page. Script cuts the time parameter which is used to continue watching from last position, changes the color of visited links to aqua and most importantly lets you ignore channels on trending page.
// @author       taipignas
// @match        https://www.youtube.com/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';
    var ran;
    var startTime;
    if (document.querySelector("ytd-video-renderer"))
        startTime = Date.now();

    // hide single video tile. used when clicking a button
    function hideSingle(e) {
        document.querySelector(`a[href$="${e}"]`).parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.style.display = "none";
    }

    // add channel or user id to localstorage ignorelist
    function ignore(e) {
        hideSingle(e);
        let ignoreList = [];
        ignoreList[0] = localStorage.getItem('ignoreList');
        ignoreList.push(e);
        localStorage.setItem('ignoreList', ignoreList);
        console.log(localStorage.getItem('ignoreList'));
    }

    function Unignore(username) {
        let ignoreList = localStorage.getItem('ignoreList');
        let usernameArray = ignoreList.split(",");
        let index = usernameArray.indexOf(username);
        console.log(index)
        if (index > 0)
            usernameArray.splice(index, 1);
        console.log(usernameArray)
        localStorage.setItem('ignoreList', usernameArray);
        console.log(localStorage.getItem('ignoreList'));
    }

    // hide all video tiles matching id. used in main function to hide all ignored channel on initialization.
    function hideAll(e) {
        document.querySelectorAll(`a[href$="${e}"]`).forEach(element => { element.parentNode.parentNode.parentNode.parentNode.style.display = "none" });
    }

    function ToggleBlacklistedVisability() {
        localStorage.getItem('ignoreListSetting') == 1 ? localStorage.setItem('ignoreListSetting', 0) : localStorage.setItem('ignoreListSetting', 1);
        window.location.reload();
        console.log(localStorage.getItem('ignoreListSetting'));
    }

    function Button(username, func) {
        let button = document.createElement(`button`);
        button.textContent = func.name;
        // (func == ignore) ? `ignore` : `unignore`;
        // button.setAttribute(`style`, `position: absolute; right: 0;`);
        button.className = "hide-button";
        button.value = username;
        button.onclick = function () { func(this.value) };
        return button;
    }
    function ClearPreviousButtons() {
        document.querySelectorAll(".hide-button").forEach(b => b.parentNode.removeChild(b));
    }

    // main function
    function main() {
        if (!window.location.href.includes('trending')) {
            ran = false;
            console.log("wrong window")
        }
        if (window.location.href.includes('trending') && document.querySelector("ytd-video-renderer")) {
            if (ran == false) {
                location.reload();
                ran = true;
            }
            ClearPreviousButtons();
            console.log("youtube ignore script loaded at " + window.location.href + " after " + (Date.now() - startTime) + "ms");
            // leave only simple video link with no properties like time to continue from
            document.querySelectorAll("a#video-title[href^='/watch?v=']").forEach(element => { element.href = element.href.slice(0, 43) });
            let ignoreList = localStorage.getItem('ignoreList');
            // query local storage ignorelist and hide all
            if (localStorage.getItem('ignoreListSetting') == 1 && ignoreList != null) {
                for (let channel of ignoreList.split(',')) {
                    hideAll(channel);
                }
            }

            // query video tiles container and add each a button to send its channel id to ignore function
            var container = document.querySelectorAll("ytd-video-renderer");
            for (let tile of container) {
                let url = tile.querySelector("a[href^='/user/']") ? tile.querySelector("a[href^='/user/']") : tile.querySelector("a[href^='/channel/']");
                let username = url.href.slice(url.href.lastIndexOf('/') + 1);
                tile.firstElementChild.appendChild(Button(username, ignore));
                if (ignoreList != null)
                    if (localStorage.getItem('ignoreListSetting') == 0 && ignoreList.indexOf(username) >= 0)
                        tile.firstElementChild.appendChild(Button(username, Unignore));
            }

            let ignoreListSetting = localStorage.getItem('ignoreListSetting');
            let button = document.createElement(`button`);
            button.textContent = (ignoreListSetting == 1 ? `show` : `hide`) + ` ignored channels`;
            button.className = "hide-button";
            // (ignoreListSetting=="1"? `show` : `hide`) +
            // button.setAttribute(`style`, `position: absolute; right: 0;`);
            button.onclick = function () { ToggleBlacklistedVisability() };
            document.querySelector("ytd-video-renderer").parentNode.prepend(button);

            // css code to change style color of visited links
            var style = document.createElement('style');
            style.innerHTML = `a#video-title:visited {color:aqua  !important;}`;
            document.head.appendChild(style);
        }
        else {
            console.log("youtube ignore script reloaded at " + window.location.href + " after " + (Date.now() - startTime) + "ms");
        }
    }

    // run main function on initialization, not just on title change
    // call main at the beginning
    main();
    // setup title change listener
    var title = document.querySelector('title');
    const config = { attributes: true, childList: true, subtree: true, characterData: true };
    const callback = function (mutationsList, observer) {
        main();
        for (let mutation of mutationsList) {
            if (mutation.type === 'childList') {
                console.log('Mutation detected at: child node, ran status: ' + ran);
            }
            if (mutation.type === 'subtree') {
                console.log('Mutation detected at: subtree, ran status: ' + ran);
            }
            if (mutation.type === 'characterData') {
                console.log('Mutation detected at: characterData, ran status: ' + ran);
            }
            else if (mutation.type === 'attributes') {
                console.log('The ' + mutation.attributeName + ' attribute was modified. ran status: ' + ran);
            }
        }
    };
    const observer = new MutationObserver(callback);
    observer.observe(title, config);
})();