YouTube Auto Dislike

Because YouTube no longer displays the number of dislikes, the scripts automatically dislike all videos. Wait 15 seconds to see the effect.

// ==UserScript==
// @name  YouTube Auto Dislike
// @namespace  gqqnbig
// @match  https://www.youtube.com/*
// @grant  none
// @version  1.5
// @author  gqqnbig
// @description  Because YouTube no longer displays the number of dislikes, the scripts automatically dislike all videos. Wait 15 seconds to see the effect.
// @license  GNU General Public License v3.0
// ==/UserScript==


(function () {
    "use strict";

    //from https://github.com/Anarios/return-youtube-dislike/blob/main/Extensions/UserScript/Return%20Youtube%20Dislike.user.js
    const LIKED_STATE = "LIKED_STATE";
    const DISLIKED_STATE = "DISLIKED_STATE";
    const NEUTRAL_STATE = "NEUTRAL_STATE";

    let isShorts = () => location.pathname.startsWith("/shorts");


    function isInViewport(element) {
        const rect = element.getBoundingClientRect();
        const height = innerHeight || document.documentElement.clientHeight;
        const width = innerWidth || document.documentElement.clientWidth;
        return (
            // When short (channel) is ignored, the element (like/dislike AND short itself) is
            // hidden with a 0 DOMRect. In this case, consider it outside of Viewport
            !(rect.top == 0 && rect.left == 0 && rect.bottom == 0 && rect.right == 0) &&
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= height &&
            rect.right <= width
        );
    }

    function getButtons() {
        if (isShorts()) {
            let elements = document.querySelectorAll("#like-button > ytd-like-button-renderer");
            for (let element of elements) {
                if (isInViewport(element)) {
                    return element;
                }
            }
        }
        if (document.getElementById("menu-container")?.offsetParent === null) {
            return (
                document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div") ??
                document.querySelector("ytd-menu-renderer.ytd-video-primary-info-renderer > div")
            );
        } else {
            return document
                .getElementById("menu-container")
                ?.querySelector("#top-level-buttons-computed");
        }
    }

    function getDislikeButton() {
        if (getButtons().children[0].tagName ===
            "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER") {
            if (getButtons().children[0].children[1] === undefined) {
                return document.querySelector("#segmented-dislike-button");
            } else {
                return getButtons().children[0].children[1];
            }
        } else {
            if (getButtons().querySelector("segmented-like-dislike-button-view-model")) {
                const dislikeViewModel = getButtons().querySelector("dislike-button-view-model");
                return dislikeViewModel;
            } else {
                return getButtons().children[1];
            }
        }
    }

    function getLikeButton() {
        return getButtons().children[0].tagName ===
        "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER"
            ? document.querySelector("#segmented-like-button") !== null ? document.querySelector("#segmented-like-button") : getButtons().children[0].children[0]
            : getButtons().querySelector("like-button-view-model") ?? getButtons().children[0];
    }

    function isVideoLiked() {
        return getLikeButton().querySelector('button').getAttribute('aria-pressed') === 'true';
    }

    function isVideoDisliked() {
        return getDislikeButton().querySelector('button').getAttribute('aria-pressed') === 'true';
    }

    function getState() {
        if (isVideoLiked()) {
            return LIKED_STATE;
        }
        if (isVideoDisliked()) {
            return DISLIKED_STATE;
        }
        return NEUTRAL_STATE;
    }


    function isWatchPage() {
        return window.location.pathname.startsWith('/watch');
    }

    const observer = new MutationObserver((mutations) => {
        if (mutations.length > 0 && mutations[0].addedNodes.length > 0 && mutations[0].addedNodes[0].wholeText !== 'YouTube' &&
            isWatchPage()) {
            console.log('start unlike');
            // observer.disconnect(); // Stop observing temporarily

            setTimeout(() => {
                if (getState() === NEUTRAL_STATE) {
                    getDislikeButton().querySelector('button').click();
                }
            }, 15000);

            // observer.observe(head, config);
        }
    });

    // only watch the direct children
    const config = {childList: true};

    let head;
    let getTitleHandle = setInterval(() => {
        head = document.head.querySelector('title');
        if (head) {
            observer.observe(head, config);
            clearInterval(getTitleHandle);
        }
    }, 200);
})();