Last active
March 22, 2021 03:28
-
-
Save b0o/acf9a27bce427f4d456b9a12acb92fe3 to your computer and use it in GitHub Desktop.
auto-darkmode.user.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Auto darkmode | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description Toggle darkmode on supported sites based on your OS's darkmode setting | |
// @author You | |
// @match https://www.tradingview.com/chart/* | |
// @match https://www.coinex.com/* | |
// @exclude https://www.coinex.com/assets/trading_chart/* | |
// @grant none | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
const sites = [] | |
/*** CoinEx ***/ | |
sites.push({ | |
hostnames: ["www.coinex.com"], | |
fn: async (state) => { | |
const checkDarkmode = () => document.children[0].classList.contains("theme-night") == state | |
if (checkDarkmode()) return | |
const switchMode = async (themeSwitcher) => { | |
if (checkDarkmode()) return true | |
themeSwitcher.click() | |
return until(checkDarkmode) | |
} | |
const getThemeSwitcher = async () => until( | |
() => document.querySelector(".icon-day, .icon-night"), { interval: 20, maxAttempts: 10 }) | |
const themeSwitcher = await getThemeSwitcher() | |
return switchMode(themeSwitcher) | |
} | |
}) | |
/*** TradingView ***/ | |
sites.push({ | |
hostnames: ["www.tradingview.com"], | |
fn: async (state) => { | |
const checkDarkmode = () => document.children[0].classList.contains("theme-dark") == state | |
if (checkDarkmode()) return | |
const switchMode = async (themeSwitcher) => { | |
if (checkDarkmode()) return true | |
themeSwitcher.click() | |
return until(checkDarkmode) | |
} | |
const toggleMenu = async (menuButton, state) => { | |
const query = () => !!document.querySelector("#theme-switcher") === !!state | |
const q = query() | |
if (q) return q | |
menuButton.click() | |
return until(query) | |
} | |
const tryGetThemeSwitcher = () => document.querySelector("#theme-switcher") | |
const getThemeSwitcher = async () => until(tryGetThemeSwitcher) | |
const getMenuButton = async () => until( | |
() => document.querySelector("*[class*='topLeftButton-'] div[data-role=button]"), { interval: 100, maxAttempts: 300 }) | |
const menuButton = await getMenuButton() | |
let themeSwitcher = tryGetThemeSwitcher() | |
const initialMenuState = !!themeSwitcher | |
if (!initialMenuState) { | |
await toggleMenu(menuButton, true) | |
themeSwitcher = await getThemeSwitcher() | |
} | |
await switchMode(themeSwitcher) | |
if (!initialMenuState) await toggleMenu(menuButton, false) | |
} | |
}) | |
const until = (check, options = {}) => new Promise((resolve, reject) => { | |
const opts = { | |
test: (a) => a, | |
maxAttempts: 50, | |
interval: 50, | |
...options, | |
} | |
const f = (attempts = 0) => { | |
const res = check() | |
if (!opts.test(res)) { | |
if (attempts > opts.maxAttempts) { | |
reject(new Error(`until: timeout: ${check}`)) | |
} else { | |
setTimeout(() => f(attempts + 1), opts.interval) | |
} | |
return | |
} | |
resolve(res) | |
} | |
f() | |
}) | |
const getSite = (hostname = location.hostname) => { | |
for (let s of sites) { | |
for (let h of s.hostnames) { | |
switch (h.constructor.name) { | |
case "String": | |
if (h === hostname) return s | |
break | |
case "RegExp": | |
if (h.test(hostname)) return s | |
break | |
case "URL": | |
if (h.hostname === hostname) return s | |
break | |
} | |
} | |
} | |
} | |
const run = () => { | |
const site = getSite() | |
if (!site) return | |
const mq = window.matchMedia('(prefers-color-scheme: dark)') | |
mq.addEventListener("change", (e) => site.fn(e.matches)) | |
site.fn(mq.matches) | |
} | |
run() | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment