// ==UserScript== // @name AutoDarkMode // @namespace airbash/Rocy-June/AutoDarkMode // @homepage https://github.com/AirBashX/UserScript // @version 25.04.07.01 // @description Automatically switch to Dark Mode // @author airbash / Rocy-June // @match *://*/* // @icon // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @license GPL-3.0 // @downloadURL none // ==/UserScript== (function () { "use strict"; // 日志函数 const log = console.log.bind(console, "[AutoDarkMode Script]"); const error = console.error.bind(console, "[AutoDarkMode Script]"); log("脚本开始运行"); // 设置对象 const settings = { light_time: "08:00", dark_time: "18:00", light_menu_id: null, dark_menu_id: null, }; // 初始化设置 initSettings(); // 所有适配的站点 /* { "domain (站点域名匹配, 防止后续匹配项过多, 提高加载速度)": [{ url: 匹配站点正则, check: 检查当前主题函数(返回 "dark" 或 "light"), toggle: 切换主题函数(可选, 为 null 时 toLight 和 toDark 函数会被调用), toLight: 切换到明亮主题函数(可选, toggle 为 null 时必需设定), toDark: 切换到黑夜主题函数(可选, toggle 为 null 时必需设定), checkTime: 检查主题间隔时间(可选, 为 null 时默认 5 秒), }] } */ const sites = { "pixiv.net": [ { url: /^https?:\/\/.*?pixiv\.net.*/, check: () => document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light", toggle: () => { const button = document.querySelector( "button.ccl__sc-1lxyknw-0.hZvyDT.sc-pkfh0q-1.ikiFYU" ); button.click(); nextTick(() => { document .querySelector("div.sc-1o6692m-0.lerGVa.sc-gmfqyv-1.jdCrQO") .click(); button.click(); }); }, }, ], "fengchedmp.com": [ { url: /^https?:\/\/.*?fengchedmp\.com.*/, check: () => document .querySelector("#cssFile") .getAttribute("href") .includes("black") ? "dark" : "light", toLight: () => { document.querySelector("i.icon-rijian").click(); }, toDark: () => { document.querySelector("i.icon-yejian").click(); }, }, ], }; // 匹配到的域名设置 const no_www_domain = location.hostname.replace(/^www\./, ""); const domain_setting = sites[no_www_domain]; if (!domain_setting) { return; } // 匹配到的网站设置 const site_setting = domain_setting.find((s) => s.url.test(location.href)); if (!site_setting) { return; } // 加载完成后开始检查主题 addEventListener("load", () => { // 创建一个定时器, 每隔 5 秒检查当前时间是否已超过时间设置 setInterval(checkTheme, site_setting.checkTime || 5000); // 立刻检查 checkTheme(); }); // 初始化设置 function initSettings() { log("初始化设置"); settings.light_time = GM_getValue("light_time", settings.light_time); settings.dark_time = GM_getValue("dark_time", settings.dark_time); refreshMenuCommand(); } // 检查当前时间是否需要切换主题 function checkTheme() { log("开始检查主题"); const light_minutes = timeToMinutes(settings.light_time); const dark_minutes = timeToMinutes(settings.dark_time); const now = nowMinutes(); const current_theme = site_setting.check(); log(`当前主题:${current_theme}`); if (now >= light_minutes && now < dark_minutes) { if (current_theme === "light") { log("当前时间为明亮主题时间, 无需切换"); return; } if (site_setting.toggle) { log("切换到明亮主题 - toggle"); site_setting.toggle(); return; } if (site_setting.toLight) { log("切换到明亮主题 - toLight"); site_setting.toLight(); return; } error("切换到明亮主题 - 未指定切换函数"); } else { if (current_theme === "dark") { log("当前时间为黑夜主题时间, 无需切换"); return; } if (site_setting.toggle) { log("切换到黑夜主题 - toggle"); site_setting.toggle(); return; } if (site_setting.toDark) { log("切换到黑夜主题 - toDark"); site_setting.toDark(); return; } error("切换到黑夜主题 - 未指定切换函数"); } } // 刷新菜单 function refreshMenuCommand() { log("刷新脚本菜单"); if (settings.light_menu_id) { GM_unregisterMenuCommand(settings.light_menu_id); } if (settings.dark_menu_id) { GM_unregisterMenuCommand(settings.dark_menu_id); } settings.light_menu_id = GM_registerMenuCommand( `设置明亮时间 (${settings.light_time})`, () => setTimePrompt("light_time", "明亮时间") ); settings.dark_menu_id = GM_registerMenuCommand( `设置黑夜时间 (${settings.dark_time})`, () => setTimePrompt("dark_time", "黑夜时间") ); } // 设置时间提示框 function setTimePrompt(key, label) { log(`设置${label}提示框`); const old_val = GM_getValue(key, settings[key]); log(`旧${label}:${old_val}`); const new_val = prompt(`设置${label}(格式 HH:mm):`, old_val); log(`用户输入: ${new_val}`); if (!new_val) { return; } if ( !new_val || !/^(?:[0-9]|1[0-9]|2[0-3])[::](?:[0-9]|[0-5][0-9])$/.test(new_val) ) { alert('格式不正确, 时间格式为 "08:00"'); return; } const standard_new_val = new_val.replace(":", ":"); log(`新${label}:${standard_new_val}`); const tmp = standard_new_val; settings[key] = standard_new_val; if ( timeToMinutes(settings.light_time) > timeToMinutes(settings.dark_time) ) { log("黑夜时间不能早于明亮时间"); settings[key] = tmp; alert("黑夜时间不能早于明亮时间"); return; } GM_setValue(key, standard_new_val); log(`${label} 已设置为:${standard_new_val}`); alert(`${label} 已设置为:${standard_new_val}`); refreshMenuCommand(); } // 将时间字符串转为分钟 function timeToMinutes(time) { const [hour, minute] = time.split(":").map(Number); return hour * 60 + minute; } // 获取当前时间的分钟数 function nowMinutes() { const now = new Date(); return now.getHours() * 60 + now.getMinutes(); } // 将函数加入下一轮事件循环 function nextTick(func) { Promise.resolve().then(func); } })();