Websites have a dark theme, but decide to default to light theme anyway, even though detecting which theme to use is easily doable. This userscript automatically changes website theme to match browser theme settings.
// ==UserScript==
// @name Follow browser theme
// @namespace Violentmonkey Scripts
// @version 1.0.1
// @description Websites have a dark theme, but decide to default to light theme anyway, even though detecting which theme to use is easily doable. This userscript automatically changes website theme to match browser theme settings.
// @author https://greasyfork.org/en/users/85040-d-a-n
// @license GNU GPLv2 ; https://choosealicense.com/licenses/gpl-2.0/
// @match *://*/*
// @run-at document-start
// @grant none
// ==/UserScript==
(() => {
if (self != top) {
return;
}
const browserThemeIsDarkTheme = (() => {
// for sites that have a button to change from light to dark, but no automatic button
// https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/prefers-color-scheme
// https://stackoverflow.com/questions/56393880/how-do-i-detect-dark-mode-using-javascript#answer-57795495
const darkModeMediaMatch = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)');
return darkModeMediaMatch && darkModeMediaMatch.matches;
})();
async function sleep(duration) {
return await new Promise((resolve) => {
setTimeout(resolve, duration)
});
}
async function getElement(queryString) {
// stop automatically rechecking after 30 secs for performance reasons
// would keep checking for an element that doesnt exist
// which can happen if already on the correct theme
const endTime = (new Date()).getTime() + 30000;
while (true) {
el = window.document.querySelector(queryString);
if (el) {
return el;
}
await sleep(10);
if ((new Date()).getTime() > endTime) {
return;
}
}
}
function setCookie(name, value, domain, path, expires, samesite) {
// for times when changing theme automatically doesnt work
const yum = `\
${name}=${value}; \
domain=${domain}; \
path=${path}; \
expires=${expires}; \
SameSite=${samesite};`
document.cookie = yum;
}
function getCookie(name) {
// for times when changing theme automatically doesnt work
// prevent infinate page reload loop because of reloading the page after setting theme cookie
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
if (match) {
return match[2];
}
}
function onOneOf(domains) {
return location.hostname.match(new RegExp('(\\.|^)(' + domains.join('|') + ')$'));
}
function onWiki() {
return onOneOf([
'wikipedia\\.org',
'mediawiki\\.org',
'wikidata\\.org',
'wikisource\\.org'
]);
}
async function applyAutoTheme() {
if (onWiki()) {
return (await getElement('#skin-client-prefs-skin-theme input#skin-client-pref-skin-theme-value-os')).click();
}
if (onOneOf(['deepwiki\\.com'])) {
const btnType = browserThemeIsDarkTheme ? 'dark' : 'light';
return (await getElement(`button[aria-label="Switch to ${btnType} mode"]`)).click();
}
if (onOneOf(['fandom\\.com'])) {
// using this doesnt work:
// const btnType = browserThemeIsDarkTheme ? 'Dark' : 'Light';
// return (await getElement(`a[aria-label="Switch to ${btnType} Theme"]`))?.click();
// so set the cookie instead
const theme = getCookie('theme');
const expires = (new Date((new Date()).getTime() + (1 * 365 * 24 * 60 * 60 * 100))).toUTCString();
if (browserThemeIsDarkTheme && theme != 'dark') {
setCookie('theme', 'dark', '.fandom.com', '/', expires, 'Lax');
location.reload();
}
else if (!browserThemeIsDarkTheme && theme == 'dark') {
setCookie('theme', 'light', '.fandom.com', '/', expires, 'Lax');
location.reload();
}
}
}
applyAutoTheme();
})();