您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhanced theme management for Twitter/X with native support detection and fallback
// ==UserScript== // @name Twitter/X Auto Dark Theme Switch // @version 0.1.7 // @description Enhanced theme management for Twitter/X with native support detection and fallback // @icon https://raw.githubusercontent.com/TiancongLx/Tempermonkey/refs/heads/main/twitter_auto_dark_theme_switch/icon_X.png // @license WTFPL // @author Original: 13xforever, Enhanced: tianconglx // @match https://twitter.com/* // @match https://x.com/* // @run-at document-start // @namespace https://github.com/TiancongLx // ==/UserScript== (function() { "use strict"; /** * Twitter/X 主题管理器 * - 检测原生自动主题功能 * - 在没有原生支持时提供自动主题切换 * - 支持优雅降级和渐进增强 */ class XThemeManager { constructor() { // 配置常量 this.CONFIG = { THEMES: { LIGHT: "0", // X 的亮色主题值 DIM: "1", // X 的暗色主题值 DARK: "2", // X 的深色主题值(备用) }, COOKIE: { NAME: "night_mode", DOMAINS: ['.twitter.com', '.x.com'], MAX_AGE: 365 * 24 * 60 * 60 // 一年的秒数 }, DETECTION: { INTERVAL: 2000, // 检测间隔(毫秒) MAX_ATTEMPTS: 5 // 最大检测次数 }, DEBUG: false // 是否启用调试日志 }; // 内部状态 this.state = { enabled: false, nativeSupport: false, mediaQuery: null, eventListeners: new Set() }; } /** * 初始化主题管理器 * @returns {Promise<void>} */ async initialize() { this.log('Initializing theme manager...'); try { // 检查浏览器特性支持 if (!this.checkBrowserSupport()) { this.log('Browser features not supported', 'warn'); return; } // 检查是否存在原生自动主题功能 const hasNativeSupport = await this.checkNativeAutoTheme(); if (hasNativeSupport) { this.log('Native auto theme detected, script disabled'); this.state.nativeSupport = true; return; } // 如果没有原生支持,启用脚本功能 this.enableScriptTheme(); this.log('Script theme management enabled'); } catch (error) { this.log(`Initialization failed: ${error.message}`, 'error'); throw error; } } /** * 检查浏览器必要特性支持 * @returns {boolean} */ checkBrowserSupport() { return window.matchMedia && document.cookie !== undefined && window.localStorage; } /** * 检测原生自动主题功能 * @returns {Promise<boolean>} */ async checkNativeAutoTheme() { let checksRemaining = this.CONFIG.DETECTION.MAX_ATTEMPTS; const checkFeatures = () => { return new Promise(resolve => { const check = () => { // 1. 检查设置面板中的自动主题选项 const hasToggle = !!document.querySelector('[data-testid="auto-theme-switch"]'); // 2. 检查主题相关的 CSS 变量 const root = document.documentElement; const hasCSS = window.getComputedStyle(root) .getPropertyValue('--auto-theme-enabled') === 'true'; // 3. 检查可能存在的主题 API const hasAPI = window.__X_THEME_API__?.autoThemeSupported; if (hasToggle || hasCSS || hasAPI) { resolve(true); return; } checksRemaining--; if (checksRemaining > 0) { setTimeout(check, this.CONFIG.DETECTION.INTERVAL); } else { resolve(false); } }; check(); }); }; return await checkFeatures(); } /** * 启用脚本的主题管理功能 */ enableScriptTheme() { // 设置媒体查询 this.state.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); // 创建主题变化处理函数 const handleThemeChange = (e) => { const theme = e.matches ? this.CONFIG.THEMES.DIM : this.CONFIG.THEMES.LIGHT; this.setThemeCookie(theme); }; // 初始设置 handleThemeChange(this.state.mediaQuery); // 添加事件监听 this.state.mediaQuery.addEventListener('change', handleThemeChange); this.state.eventListeners.add({ target: this.state.mediaQuery, type: 'change', handler: handleThemeChange }); this.state.enabled = true; // 添加原生主题支持的 meta 标签 this.addColorSchemeMeta(); } /** * 设置主题 cookie * @param {string} theme - 主题值 */ setThemeCookie(theme) { try { const { NAME, DOMAINS, MAX_AGE } = this.CONFIG.COOKIE; const cookieString = `${NAME}=${theme}; path=/; secure; max-age=${MAX_AGE}`; DOMAINS.forEach(domain => { document.cookie = `${cookieString}; domain=${domain}`; }); this.log(`Theme cookie set to: ${theme}`); } catch (error) { this.log(`Failed to set theme cookie: ${error.message}`, 'error'); } } /** * 添加 color-scheme meta 标签 */ addColorSchemeMeta() { if (!document.querySelector('meta[name="color-scheme"]')) { const meta = document.createElement('meta'); meta.name = 'color-scheme'; meta.content = 'light dark'; document.head.appendChild(meta); this.log('Added color-scheme meta tag'); } } /** * 禁用主题管理器 */ disable() { if (!this.state.enabled) return; // 清理所有事件监听 this.state.eventListeners.forEach(({ target, type, handler }) => { target.removeEventListener(type, handler); }); this.state.eventListeners.clear(); this.state.enabled = false; this.log('Theme manager disabled'); } /** * 日志工具方法 * @param {string} message - 日志消息 * @param {'log'|'warn'|'error'} level - 日志级别 */ log(message, level = 'log') { if (!this.CONFIG.DEBUG) return; const prefix = '[X Theme Manager]'; switch (level) { case 'warn': console.warn(`${prefix} ${message}`); break; case 'error': console.error(`${prefix} ${message}`); break; default: console.log(`${prefix} ${message}`); } } } // 脚本启动逻辑 const startScript = () => { const themeManager = new XThemeManager(); // 将实例绑定到 window 对象,方便调试 if (themeManager.CONFIG.DEBUG) { window.__X_THEME_MANAGER__ = themeManager; } // 初始化主题管理器 themeManager.initialize().catch(error => { console.error('[X Theme Manager] Failed to initialize:', error); }); }; // 根据文档加载状态决定启动时机 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startScript); } else { startScript(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址