// ==UserScript== // @name 替换网页字体 // @author ai // @version 2.1 // @match *://*/* // @run-at document-start // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @description 替换网页的字体 // @namespace https://greasyfork.org/users/22620 // @downloadURL none // ==/UserScript== (function() { 'use strict'; const CONFIG_KEYS = { FONT: 'config_font', EXCLUSIONS: 'config_exclusions', ENABLED: 'config_enabled' }; const DEFAULT_CONFIG = { font: '微软雅黑', exclusions: 'i, [class*="ico"], [class*="emoji"]', enabled: true }; class FontManager { constructor() { this.config = this.loadConfig(); this.applyFont(); this.initMenu(); } loadConfig() { return { font: GM_getValue(CONFIG_KEYS.FONT, DEFAULT_CONFIG.font), exclusions: GM_getValue(CONFIG_KEYS.EXCLUSIONS, DEFAULT_CONFIG.exclusions), enabled: GM_getValue(CONFIG_KEYS.ENABLED, DEFAULT_CONFIG.enabled) }; } saveConfig(key, value) { const oldValue = GM_getValue(key); if (oldValue !== value) { GM_setValue(key, value); this.config = this.loadConfig(); this.applyFont(); } } generateCSS() { if (!this.config.enabled) return ''; const { font, exclusions } = this.config; let notSelector = ''; if (exclusions) { notSelector = exclusions.split(',') .map(s => s.trim()) .filter(Boolean) .map(s => `:not(${s})`) .join(''); } return `*${notSelector} { font-family: ${font} !important; }`; } async applyFont() { // 移除旧样式 if (this.styleElement) { this.styleElement.remove(); } if (!this.config.enabled) return; // 注入初始字体 this.styleElement = GM_addStyle(this.generateCSS()); console.log(`⏱️ 阶段一:注入初始字体: ${this.config.font}`); // 等待网页字体加载后更新 await document.fonts?.ready; const webFonts = this.getWebFonts(); const finalFonts = webFonts ? `${this.config.font}, ${webFonts}` : this.config.font; this.styleElement.textContent = this.generateCSS(); console.log(`✅ 阶段二:最终字体: ${finalFonts}`); } getWebFonts() { if (!document.fonts) return ''; const fonts = new Set(); document.fonts.forEach(font => { if (font.family) fonts.add(`"${font.family}"`); }); return [...fonts].join(', '); } initMenu() { this.menuCommands = new Map(); this.updateMenu(); } updateMenu() { // 清除旧菜单 this.menuCommands.forEach(id => GM_unregisterMenuCommand(id)); this.menuCommands.clear(); // 注册新菜单 this.menuCommands.set('toggle', GM_registerMenuCommand( this.config.enabled ? '❌ 禁用字体效果' : '✅ 启用字体效果', () => this.toggleEnabled() )); this.menuCommands.set('font', GM_registerMenuCommand('🖋️ 配置字体名称', () => this.promptConfig('font', '请输入新的字体名称') )); this.menuCommands.set('exclusions', GM_registerMenuCommand('🚫 配置排除元素列表', () => this.promptConfig('exclusions', '请输入新的排除元素选择器') )); this.menuCommands.set('reset', GM_registerMenuCommand('🗑️ 恢复默认设置', () => this.resetToDefault() )); } toggleEnabled() { this.saveConfig(CONFIG_KEYS.ENABLED, !this.config.enabled); this.updateMenu(); } promptConfig(type, promptText) { const key = CONFIG_KEYS[type.toUpperCase()]; const current = this.config[type]; const newValue = prompt(`${promptText}:\n(用逗号分隔,例如: ${type === 'font' ? '"微软雅黑", system-ui' : 'i, [class*="ico"]'})`, current); if (newValue?.trim()) { this.saveConfig(key, newValue.trim()); } } resetToDefault() { if (confirm('确定要将所有配置恢复为默认值吗?')) { Object.entries(CONFIG_KEYS).forEach(([key, storageKey]) => { const type = key.toLowerCase(); GM_setValue(storageKey, DEFAULT_CONFIG[type]); }); this.config = this.loadConfig(); this.applyFont(); this.updateMenu(); } } } new FontManager(); })();