asteriksme / Better Youtube

// ==UserScript==
// @name         Better Youtube
// @namespace    http://tampermonkey.net/
// @version      0.9
// @description  Various improvements
// @author       You
// @match        https://www.youtube.com/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license      MIT
// @updateURL    https://openuserjs.org/meta/asteriksme/Better_Youtube.meta.js
// @downloadURL  https://openuserjs.org/install/asteriksme/Better_Youtube.user.js
// ==/UserScript==

/* jshint esversion: 8 */

(function() {
    'use strict';

    const getRelativeTimeString = (date, lang = navigator.language) => {
        const timeMs = typeof date === "number" ? date : date.getTime();
        const deltaSeconds = Math.round((timeMs - Date.now()) / 1000);
        const cutoffs = [60, 3600, 86400, 86400 * 7, 86400 * 30, 86400 * 365, Infinity];
        const units = ["second", "minute", "hour", "day", "week", "month", "year"];
        const unitIndex = cutoffs.findIndex(cutoff => cutoff > Math.abs(deltaSeconds));
        const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1;
        const rtf = new Intl.RelativeTimeFormat(lang, { numeric: "auto" });
        return rtf.format(Math.floor(deltaSeconds / divisor), units[unitIndex]);
    };

    let running = false;
    const addTimestamps = async () => {
        if (running || !document.querySelector(".ytp-endscreen-content a .ytp-videowall-still-info-author")) {
            return;
        }
        running = true;
        await Promise.all(
            document.querySelector(".ytp-endscreen-content").querySelectorAll("a:not([data-timestamp-added])").map((tag) =>
                fetch(tag.href, {
                    method: 'get',
                }).then((response) => response.text()).then((res) => {
                    const date = new Date(res.match(/publishDate":"([^"]*)"/)[1]);
                    tag.querySelector(".ytp-videowall-still-info-author").innerHTML += ` • ${date.toLocaleDateString()} (${getRelativeTimeString(date)})`;
                    tag.setAttribute("data-timestamp-added", "");
                })
            )
        );
        running = false;
    };
    
    const changeVideosPerRow = (changes, observer) => {
        const MIN_SIZE = 5;
        const renderers = "ytd-rich-item-renderer, .video_card";
        const itemsPerRow = "--ytd-rich-grid-items-per-row";
        document.querySelectorAll(renderers).forEach((renderer) => {
            if (parseInt(getComputedStyle(renderer).getPropertyValue(itemsPerRow), 10) < MIN_SIZE) {
                renderer.style.setProperty(itemsPerRow, MIN_SIZE.toString());
            }
        });
    };
    
    const removeUselessSection = (changes, observer) => {
        const renderer = "ytd-rich-section-renderer";
        const sections = document.querySelectorAll(renderer);
        if (sections.length < 2) {
            return;
        }
        sections.forEach((section, index) => index > 0 && setTimeout(() => section.remove()));
    };
    
    (new MutationObserver(addTimestamps)).observe(document, {childList: true, subtree: true});
    (new MutationObserver(changeVideosPerRow)).observe(document, {childList: true, subtree: true});
    (new MutationObserver(removeUselessSection)).observe(document, {childList: true, subtree: true});
})();