Automatic Material Dark-Mode for YouTube

A low-tech solution to a high-tech problem! Automatically clicks YouTube's "Dark Mode" button if dark mode isn't already active.

当前为 2017-09-13 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Automatic Material Dark-Mode for YouTube
// @namespace    SteveJobzniak
// @version      1.2
// @description  A low-tech solution to a high-tech problem! Automatically clicks YouTube's "Dark Mode" button if dark mode isn't already active.
// @author       SteveJobzniak
// @match        *://www.youtube.com/*
// @exclude      *://www.youtube.com/tv*
// @exclude      *://www.youtube.com/embed/*
// @run-at       document-end
// @grant        none
// @noframes
// ==/UserScript==

(function() {
    'use strict';

    function enableDark() {
        // Wait a moment so that the whole page menu is loaded and the "dark mode state" is updated...
        var attempt = 0, maxAttempts = 8, waitDelay = 250; // 8*250ms = Max 2 seconds of retries.
        var menuWaitTimer = setInterval( function() {
            // We must find the "settings" menu, otherwise YouTube hasn't fully loaded yet...
            var menuButtons = document.querySelectorAll( 'yt-icon.style-scope.ytd-topbar-menu-button-renderer' );

            // If we've reached max attempts or found success, we must now stop the interval timer.
            if( ++attempt >= maxAttempts || menuButtons.length === 2 ) {
                clearInterval( menuWaitTimer );
            }

            // Failed to find the menu bar. Skip this attempt...
            if( menuButtons.length !== 2 ) {
                return;
            }

            // Check the dark mode state "flag" and only process if dark mode isn't already active.
            if( document.body.getAttribute( 'dark' ) !== 'true' ) {
                // We MUST open the "settings" menu, otherwise nothing will react to the "toggle dark mode" event!
                menuButtons[1].click(); // Click the 2nd menu button.

                // Wait a moment for the settings-menu to open up after clicking...
                setTimeout( function() {
                    // Next, open the "toggle dark mode" settings sub-page.
                    var subButtons = document.querySelectorAll( 'div#label.style-scope.ytd-toggle-theme-compact-link-renderer' );
                    if( subButtons.length === 1 ) {
                        subButtons[0].click(); // Click the "dark mode" sub-page button.

                        // Wait a moment for the sub-page to switch...
                        setTimeout( function() {
                            // Get a reference to the "toggle dark mode" settings sub-page. This only works if we opened the "dark mode" sub-page.
                            var toggleMenuElem = document.querySelectorAll( 'ytd-toggle-item-renderer.style-scope.ytd-multi-page-menu-renderer' );
                            toggleMenuElem = (toggleMenuElem.length === 1 ? toggleMenuElem[0] : undefined); // Always missing unless we visit the page...

                            if( toggleMenuElem ) {
                                // Get a reference to the "activate dark mode" button.
                                var darkModeButton = toggleMenuElem.querySelectorAll( 'paper-toggle-button.style-scope.ytd-toggle-item-renderer' );
                                darkModeButton = (darkModeButton.length === 1 ? darkModeButton[0] : undefined);

                                // Now simply click the button to enable dark mode.
                                darkModeButton.click();

                                // Give keyboard focus to the input serach field.
                                setTimeout( function() {
                                    var searchField = document.querySelectorAll( 'input#search' );
                                    if( searchField.length === 1 ) {
                                        // Clicking the searchfield first is just done to hide the settings-panel.
                                        searchField[0].click();
                                        searchField[0].focus();
                                    }
                                }, 150 );
                            }

                            // Alternative method, which switches using an event instead of clicking the button...
                            // I decided to disable this method, since it relies on intricate internal details...
                            // and requires the menu to be open to work anyway, so we may as well just click it...
                            /*
                                var ytDebugMenu = document.querySelectorAll('ytd-debug-menu');
                                ytDebugMenu = (ytDebugMenu.length === 1 ? ytDebugMenu[0] : undefined);
                                if( ytDebugMenu ) {
                                    ytDebugMenu.fire(
                                        'yt-action',
                                        {
                                            actionName:'yt-signal-action-toggle-dark-theme-on',
                                            optionalAction:false,
                                            args:[
                                                {signalAction:{signal:'TOGGLE_DARK_THEME_ON'}},
                                                toggleMenuElem,
                                                undefined
                                            ],
                                            returnValue: []
                                        },
                                        {}
                                    );
                                }
                                */
                        }, 250 ); // Delay to wait for the dark mode settings subpage to open.
                    }
                }, 500 ); // Delay to wait for the settings menu to fully open.
            }
        }, waitDelay ); // Check-interval after page load to ensure the deferred menu topbar and dark mode state are fully loaded.
    }

    if( document.readyState === 'complete' ) {
        enableDark();
    } else {
        document.addEventListener( 'readystatechange', function( evt ) {
            if( document.readyState === 'complete' ) {
                enableDark();
            }
        } );
    }
})();