// ==UserScript== // @name 全局字体 // @author gemini // @version 1.07 // @match *://*/* // @run-at document-start // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @namespace https://greasyfork.org/users/22620 // @description 全局修改字体 // @downloadURL none // ==/UserScript== (function() { 'use strict'; // --- 配置常量 --- const DEFAULT_CONFIG = { font: '微软雅黑', exclusions: 'i, [class*="ico"], [class*="fa"], [class*="emoji"]', enabled: true }; const STORAGE_KEYS = { font: 'config_my_new_font', exclusions: 'config_icon_exclusion_selectors', enabled: 'config_font_enabled' }; // --- 状态管理 --- class FontManager { constructor() { this.config = { font: DEFAULT_CONFIG.font, exclusions: DEFAULT_CONFIG.exclusions, enabled: DEFAULT_CONFIG.enabled }; this.styleElement = null; this.configUpdateCallbacks = []; } // 加载配置 loadConfig() { this.config.font = GM_getValue(STORAGE_KEYS.font, DEFAULT_CONFIG.font); this.config.enabled = GM_getValue(STORAGE_KEYS.enabled, DEFAULT_CONFIG.enabled); const storedExclusions = GM_getValue(STORAGE_KEYS.exclusions, DEFAULT_CONFIG.exclusions); this.config.exclusions = storedExclusions; console.log(`⚙️ 配置加载: 字体=${this.config.font}, 启用=${this.config.enabled}, 排除项=${storedExclusions}`); } // 保存配置 saveConfig() { GM_setValue(STORAGE_KEYS.font, this.config.font); GM_setValue(STORAGE_KEYS.exclusions, this.config.exclusions); GM_setValue(STORAGE_KEYS.enabled, this.config.enabled); } // 添加配置更新回调 onConfigUpdate(callback) { this.configUpdateCallbacks.push(callback); } // 触发配置更新回调 triggerConfigUpdate() { this.configUpdateCallbacks.forEach(callback => callback(this.config)); } // 生成排除选择器字符串 getExclusionSelector() { return this.config.exclusions .split(',') .map(s => s.trim()) .filter(Boolean) // 使用 Boolean 函数过滤空值 .map(selector => `:not(${selector})`) .join(''); } // 生成 CSS generateCSS(fontFamily = this.config.font) { const exclusionSelector = this.getExclusionSelector(); return ` /* 全局字体修改 - ${new Date().toLocaleTimeString()} */ *${exclusionSelector} { font-family: ${fontFamily} !important; } `; } // 注入 CSS injectCSS(css) { this.removeCSS(); this.styleElement = GM_addStyle(css); return this.styleElement; } // 移除 CSS removeCSS() { if (this.styleElement?.parentNode) { this.styleElement.parentNode.removeChild(this.styleElement); this.styleElement = null; } } // 应用字体(两个阶段) async applyFont() { if (!this.config.enabled) { this.removeCSS(); return; } // 阶段一:立即注入 const initialCSS = this.generateCSS(this.config.font); this.injectCSS(initialCSS); console.log(`⏱️ 阶段一:注入初始字体: ${this.config.font}`); // 阶段二:等待字体加载完成后更新 try { await document.fonts?.ready; const protectedFonts = new Set(); document.fonts?.forEach?.(fontFace => { const fontFamily = fontFace.family.replace(/"/g, ''); if (fontFamily) protectedFonts.add(`"${fontFamily}"`); }); const protectedFontFamily = [...protectedFonts].join(', '); const finalFontFamily = protectedFontFamily ? `${this.config.font}, ${protectedFontFamily}` : this.config.font; const finalCSS = this.generateCSS(finalFontFamily); this.injectCSS(finalCSS); console.log(`✅ 阶段二:最终字体: ${finalFontFamily}`); } catch (error) { console.warn('⚠️ 字体加载出错,使用初始字体:', error); } } // 更新配置并重新应用 updateConfig(updates) { Object.assign(this.config, updates); this.saveConfig(); this.applyFont(); this.triggerConfigUpdate(); } // 切换启用状态 toggleEnabled() { const newEnabled = !this.config.enabled; this.updateConfig({ enabled: newEnabled }); console.log(newEnabled ? '✅ 字体效果已启用' : '❌ 字体效果已禁用'); } // 重置为默认配置 resetToDefault() { if (confirm('确定要将所有配置恢复为默认值吗?')) { Object.assign(this.config, DEFAULT_CONFIG); this.saveConfig(); this.applyFont(); this.triggerConfigUpdate(); console.log('🔄 配置已重置为默认值'); } } } // --- 菜单管理 --- class MenuManager { constructor(fontManager) { this.fontManager = fontManager; this.commands = new Map(); // 监听配置更新 this.fontManager.onConfigUpdate(() => this.updateMenu()); } // 注册所有菜单命令 registerAll() { this.registerToggleCommand(); this.registerFontConfigCommand(); this.registerExclusionsConfigCommand(); this.registerResetCommand(); } // 注册切换命令 registerToggleCommand() { const label = this.fontManager.config.enabled ? '❌ 禁用字体效果' : '✅ 启用字体效果'; const id = GM_registerMenuCommand(label, () => { this.fontManager.toggleEnabled(); }); this.commands.set('toggle', id); } // 注册字体配置命令 registerFontConfigCommand() { const id = GM_registerMenuCommand('🖋️ 配置字体名称', () => { const currentFont = this.fontManager.config.font; const newFont = prompt( '请输入新的字体名称 (用逗号分隔,例如: "MiSans", system-ui, sans-serif)', currentFont ); if (newFont?.trim()) { this.fontManager.updateConfig({ font: newFont.trim() }); alert('字体名称已保存并立即生效!'); } }); this.commands.set('font', id); } // 注册排除列表配置命令 registerExclusionsConfigCommand() { const id = GM_registerMenuCommand('🚫 配置排除元素列表', () => { const currentExclusions = this.fontManager.config.exclusions; const newExclusions = prompt( '请输入新的排除元素选择器 (用逗号分隔,用于保护图标字体等,例如: i, [class*="ico"])', currentExclusions ); if (newExclusions !== null) { this.fontManager.updateConfig({ exclusions: newExclusions.trim() }); alert('排除列表已保存并立即生效!'); } }); this.commands.set('exclusions', id); } // 注册重置命令 registerResetCommand() { const id = GM_registerMenuCommand('🗑️ 恢复默认设置', () => { this.fontManager.resetToDefault(); }); this.commands.set('reset', id); } // 更新所有菜单 updateMenu() { // 重新注册所有菜单以更新标签 this.commands.forEach(id => { try { GM_unregisterMenuCommand(id); } catch (e) { // 忽略未注册的命令 } }); this.commands.clear(); this.registerAll(); } } // --- 主执行流程 --- const fontManager = new FontManager(); const menuManager = new MenuManager(fontManager); // 初始化 fontManager.loadConfig(); menuManager.registerAll(); // 根据启用状态决定是否应用字体 if (fontManager.config.enabled) { // 延迟执行以确保 DOM 已加载 const applyFont = () => fontManager.applyFont(); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', applyFont); } else { applyFont(); } } // 暴露到全局便于调试 window.GlobalFontManager = fontManager; console.log('🎨 全局字体脚本已加载'); })();