您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A low-tech solution to a high-tech problem! Automatically clicks YouTube's "Dark Mode" button if dark mode isn't already active.
当前为
// ==UserScript== // @name Automatic Material Dark-Mode for YouTube // @namespace SteveJobzniak // @version 1.5.0 // @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 // @homepage https://greasyfork.org/scripts/32954-automatic-material-dark-mode-for-youtube // @license https://www.apache.org/licenses/LICENSE-2.0 // @contributionURL https://www.paypal.me/Armindale/0usd // @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'; /* Performs multiple retries of a function call until it either succeeds or has failed all attempts. */ function retryFnCall( fnCallback ) { // If we don't succeed immediately, we'll perform multiple retries. var success = fnCallback(); if( ! success ) { var attempt = 0, maxAttempts = 40, waitDelay = 50; // 40 * 50ms = Max ~2 seconds of retries. var searchTimer = setInterval( function() { var success = fnCallback(); // If we've reached max attempts or found success, we must now stop the interval timer. if( ++attempt >= maxAttempts || success ) { clearInterval( searchTimer ); } }, waitDelay ); } } /* Searches for a specific element. */ function findElement( parentElem, elemQuery, expectedLength, selectItem, fnCallback ) { var elems = parentElem.querySelectorAll( elemQuery ); if( elems.length === expectedLength ) { var item = elems[selectItem]; fnCallback( item ); return true; } //console.log('Debug: Cannot find "'+elemQuery+'".'); return false; } function retryFindElement( parentElem, elemQuery, expectedLength, selectItem, fnCallback ) { // If we can't find the element immediately, we'll perform multiple retries. retryFnCall( function() { return findElement( parentElem, elemQuery, expectedLength, selectItem, fnCallback ); } ); } /* Searches for multiple different elements and uses the earliest match. */ function multiFindElement( queryList, fnCallback ) { for( var i=0, len=queryList.length; i<len; ++i ) { var query = queryList[i]; var success = findElement( query.parentElem, query.elemQuery, query.expectedLength, query.selectItem, fnCallback ); if( success ) { // Don't try any other queries, since we've found a successful match. return true; } } return false; } function retryMultiFindElement( queryList, fnCallback ) { // If we can't find any of the elements immediately, we'll perform multiple retries. retryFnCall( function() { return multiFindElement( queryList, fnCallback ); } ); } /* Automatically enables YouTube's dark mode theme. */ function enableDark() { // Wait until the settings menu is available, to ensure that YouTube's "dark mode state" and code has been loaded... // Note that this particular menu button always exists (both when logged in and when logged out of your account), // but its actual icon and the list of submenu choices differ. However, its "dark mode" submenus are the same in either case. retryFindElement( document, 'button.style-scope.ytd-topbar-menu-button-renderer', 2, 1, function( settingsMenuButton ) { // Check the dark mode state "flag" and abort processing if dark mode is already active. if( document.documentElement.getAttribute( 'dark' ) === 'true' ) { return; } // We MUST open the "settings" menu, otherwise nothing will react to the "toggle dark mode" event! settingsMenuButton.click(); // Wait a moment for the settings-menu to open up after clicking... retryFindElement( document, 'div#label.style-scope.ytd-toggle-theme-compact-link-renderer', 1, 0, function( darkModeSubMenuButton ) { // Next, go to the "toggle dark mode" settings sub-page. darkModeSubMenuButton.click(); // Wait a moment for the settings sub-page to switch... retryFindElement( document, 'ytd-toggle-item-renderer.style-scope.ytd-multi-page-menu-renderer', 1, 0, function( darkModeSubPageContainer ) { // Get a reference to the "activate dark mode" button... retryFindElement( darkModeSubPageContainer, 'paper-toggle-button.style-scope.ytd-toggle-item-renderer', 1, 0, function( darkModeButton ) { // We MUST now use this very ugly, hardcoded sleep-timer to ensure that YouTube's "activate dark mode" code is fully // loaded; otherwise, YouTube will be completely BUGGED OUT and WON'T save the fact that we've enabled dark mode! // Since JavaScript is single-threaded, this timeout simply ensures that we'll leave our current code so that we allow // YouTube's event handlers to deal with loading the settings-page, and then the timeout gives control back to us. setTimeout( function() { // Now simply click YouTube's button to enable their dark mode. darkModeButton.click(); // And lastly, give keyboard focus back to the input search field... (We don't need any setTimeout here...) retryFindElement( document, 'input#search', 1, 0, function( searchField ) { searchField.click(); // First, click the search-field to force the settings-panel to close... searchField.focus(); // ...and finally give the search-field focus! Voila! } ); }, 20 ); // We can use 0ms here for "as soon as possible" instead, but our "at least 20ms" might be safer just in case. } ); } ); } ); } ); // Alternative method, which switches using an internal YouTube event instead of clicking // the menus... I decided to disable this method, since it relies on intricate internal // details, and it still requires their menu to be open to work anyway (because their // code for changing theme isn't active until the Dark Mode settings menu is open), // so we may as well just click the actual menu items. ;-) /* 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: [] }, {} ); } */ // Also note that it may be possible to simply modify the YouTube cookies, by changing // "PREF=f1=50000000;" to "PREF=f1=50000000&f6=400;" (dark mode on) and then reloading the page. // However, a reload is always slower than toggling the settings menu, so I didn't do that. } if( document.readyState === 'complete' ) { enableDark(); } else { document.addEventListener( 'readystatechange', function( evt ) { if( document.readyState === 'complete' ) { enableDark(); } } ); } })();