您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
🎯 专为LINUX DO OAuth设计的三主题UI助手 - 简约白/紫色渐变/彩虹华丽 + 条形图统计 (已移除自动点击功能)
// ==UserScript== // @name 🏆 LINUX DO OAuth 极简助手 - 面板集成版 (无自动点击) // @namespace https://github.com/TechnologyStar/linuxdo-oauth-helper // @version 3.0.3 // @description 🎯 专为LINUX DO OAuth设计的三主题UI助手 - 简约白/紫色渐变/彩虹华丽 + 条形图统计 (已移除自动点击功能) // @author Premium UI Designer // @match https://connect.linux.do/* // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_notification // @grant GM_openInTab // @grant GM_download // @license MIT // @icon data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHJ4PSIyMCIgZmlsbD0iI0ZGRkZGRiIgc3Ryb2tlPSIjRTVFN0VCIiBzdHJva2Utd2lkdGg9IjIiLz48dGV4dCB4PSIzMiIgeT0iNDAiIGZvbnQtZmFtaWx5PSJzeXN0ZW0tdWkiIGZvbnQtc2l6ZT0iMjQiIGZpbGw9IiM2QjdCODAiIHRleHQtYW5jaG9yPSJtaWRkbGUiPvCfkpA8L3RleHQ+PC9zdmc+ // ==/UserScript== (function() { 'use strict'; // ================== 配置 ================== const CONFIG = { version: '3.2.0', github: 'https://github.com/TechnologyStar/linuxdo-oauth-helper', defaultSettings: { // 核心功能 // autoClickApprove: false, // ❌ 已移除:自动点击授权 saveLoginHistory: true, showNotifications: false, // 网站限制 // restrictByWebsite: true, // ❌ 已移除:默认开启限制:只对白名单网站自动授权 // useRemoteWhitelist: true, // ❌ 已移除:默认启用远程白名单 // remoteWhitelistUrl: 'https://raw.githubusercontent.com/TechnologyStar/linuxdo-oauth-helper/refs/heads/main/whitelist.json', // ❌ 已移除 // remoteWhitelistTtlMs: 6 * 60 * 60 * 1000, // ❌ 已移除:远程名单缓存时长:6小时 // whitelist: [], // ❌ 已移除:本地额外白名单(可选,手动补充) // UI设置 autoHidePanel: false, enablePageStyling: true, theme: 'light', uiTheme: 'minimal-white', // 高级功能 autoExportData: false, checkForUpdates: true, enableAdvancedStats: false, enableDebugMode: false, showChartStats: true, // 显示图表统计 showHourlyChart: true, // 显示小时统计 showWebsiteStats: true, // 显示网站统计 // 时间设置 // autoClickDelay: 10, // ❌ 已移除:自动点击延迟 notificationDuration: 3000, panelPosition: 'top-right' }, selectors: { // approveButton: 'a.bg-red-500[href*="/oauth2/approve/"]', // ❌ 已移除:自动点击相关选择器 declineButton: 'a.bg-blue-500[href*="/oauth2/decline/"]', userInfo: 'h1.text-2xl' }, themes: { light: { primary: '#ffffff', secondary: '#f9fafb', accent: '#10b981', text: '#111827', border: '#e5e7eb' }, dark: { primary: '#1f2937', secondary: '#111827', accent: '#34d399', text: '#f9fafb', border: '#374151' } }, uiThemes: { 'minimal-white': { name: '简约白', description: '极简白色设计,清爽简洁', icon: '⚪', colors: { panelBg: '#ffffff', panelBorder: '#e5e7eb', triggerBg: '#ffffff', accent: '#10b981', text: '#111827', textMuted: '#6b7280' } }, 'purple-gradient': { name: '紫色渐变', description: '基于OAuth页面的紫色渐变设计', icon: '🟣', colors: { panelBg: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', panelBorder: 'rgba(255,255,255,0.2)', triggerBg: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', accent: '#4c51bf', text: '#ffffff', textMuted: 'rgba(255,255,255,0.8)' } }, 'rainbow-fancy': { name: '彩虹华丽', description: '炫酷多彩动画设计,视觉冲击', icon: '🌈', colors: { panelBg: 'linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab)', panelBorder: 'rgba(255,255,255,0.3)', triggerBg: 'linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab)', accent: '#ff6b6b', text: '#ffffff', textMuted: 'rgba(255,255,255,0.9)' } } } }; // ================== 工具函数 ================== class Utils { static log(message, type = 'info') { const settings = window.oauthHelper?.storage?.getSettings() || {}; if (settings.enableDebugMode || type === 'error') { console.log(`%c[OAuth Helper] ${message}`, type === 'error' ? 'color: red' : 'color: #10B981', new Date().toLocaleTimeString() ); } } static formatDate(date) { return new Date(date).toLocaleString('zh-CN'); } static generateId() { return Date.now() + '-' + Math.random().toString(36).substr(2, 6); } static debounce(func, wait) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; } static formatBytes(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } // ✅ 规范化:输入 URL 或 文本 → 纯域名(不带协议、不带路径、不带末尾/) static normalizeHost(input = '') { if (!input) return ''; let s = String(input).trim(); // 先去协议、末尾斜杠、路径 s = s.replace(/^https?:\/\//i, '').replace(/\/+$/g, ''); s = s.split('/')[0]; return s.toLowerCase(); } // ✅ 远程抓取文本(优先 GM_xmlhttpRequest,失败再用 fetch) static fetchText(url) { return new Promise((resolve, reject) => { if (typeof GM_xmlhttpRequest === 'function') { GM_xmlhttpRequest({ method: 'GET', url, headers: { 'Cache-Control': 'no-cache' }, timeout: 15000, onload: r => resolve(r.responseText), onerror: e => reject(e && e.error || 'GM_xmlhttpRequest error'), ontimeout: () => reject('GM_xmlhttpRequest timeout') }); } else { fetch(url, { cache: 'no-store' }) .then(res => res.text()) .then(resolve) .catch(err => reject(err?.message || 'fetch error')); } }); } // ✅ 加载或刷新远程白名单(按行解析,忽略空行和 # 注释) // 结果会缓存到 Storage 的 remoteWhitelist / remoteWhitelistUpdatedAt static async loadRemoteWhitelist(storage, settings) { // ❌ 已移除:相关逻辑 return []; // 返回空数组 } // ✅ 判断 host 是否在 {远程 | 本地} 白名单(支持 *.example.com) static isHostAllowed(host, lists = []) { // ❌ 已移除:相关逻辑 return true; // 默认允许 } static exportToJSON(data, filename) { const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } static async importFromJSON(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { try { const data = JSON.parse(e.target.result); resolve(data); } catch (error) { reject(error); } }; reader.onerror = reject; reader.readAsText(file); }); } // 生成条形图HTML static generateBarChart(data, options = {}) { const { maxHeight = 80, barColor = '#10b981', backgroundColor = '#f3f4f6', showValues = true, className = 'oauth-chart-bar' } = options; const maxValue = Math.max(...Object.values(data)); if (maxValue === 0) return '<div class="oauth-chart-empty">📊 暂无统计数据</div>'; return Object.entries(data).map(([label, value]) => { const percentage = (value / maxValue) * 100; const height = Math.max((percentage / 100) * maxHeight, 4); // 最小高度4px return ` <div class="oauth-chart-bar-container"> <div class="oauth-chart-bar-wrapper" style="height: ${maxHeight + 5}px;"> <div class="${className}" style="height: ${height}px; background: ${barColor};" data-value="${value}" data-label="${label}"> ${showValues && value > 0 ? `<span class="oauth-chart-value">${value}</span>` : ''} </div> </div> <div class="oauth-chart-label" title="${label}: ${value}次">${label}</div> </div> `; }).join(''); } // 生成时间序列数据(最近7天) static generateTimeSeriesData(history) { const now = new Date(); const last7Days = {}; // 初始化最近7天 for (let i = 6; i >= 0; i--) { const date = new Date(now); date.setDate(date.getDate() - i); const dateKey = date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' }); last7Days[dateKey] = 0; } // 统计每天的登录(不可用)次数 history.forEach(record => { const recordDate = new Date(record.timestamp); const dateKey = recordDate.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' }); if (last7Days.hasOwnProperty(dateKey)) { last7Days[dateKey]++; } }); return last7Days; } // 生成小时统计数据(今天24小时) static generateHourlyData(history) { const today = new Date(); const todayStr = today.toDateString(); const hourlyData = {}; // 初始化24小时 for (let i = 0; i < 24; i++) { const hour = i.toString().padStart(2, '0') + ':00'; hourlyData[hour] = 0; } // 统计今天各小时的登录(不可用)次数 history.forEach(record => { const recordDate = new Date(record.timestamp); if (recordDate.toDateString() === todayStr) { const hour = recordDate.getHours().toString().padStart(2, '0') + ':00'; hourlyData[hour]++; } }); return hourlyData; } // 生成网站统计数据 static generateWebsiteStats(history) { const websites = {}; history.forEach(record => { const website = record.website || '未知网站'; websites[website] = (websites[website] || 0) + 1; }); // 排序并取前5个 const sortedWebsites = Object.entries(websites) .sort(([,a], [,b]) => b - a) .slice(0, 5) .reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {}); return sortedWebsites; } // 生成操作类型统计 static generateActionStats(history) { const actions = { // '自动授权': 0, // ❌ 已移除:自动授权统计 '手动授权': 0, '手动拒绝': 0 }; history.forEach(record => { // if (record.action === '自动授权') { // ❌ 已移除:自动授权判断 // actions['自动授权']++; // } else if (record.action === '手动授权') { actions['手动授权']++; } else if (record.action === '手动拒绝') { actions['手动拒绝']++; } }); return actions; } } // ================== 存储管理 ================== class Storage { constructor() { this.prefix = 'loh_'; this.initStorage(); } initStorage() { const keys = ['settings', 'stats', 'history', 'metadata']; // ❌ 已移除:'remoteWhitelist', 'remoteWhitelistUpdatedAt' keys.forEach(key => { if (this.get(key) === null) { this.set(key, this.getDefaultValue(key)); } }); } getDefaultValue(key) { const defaults = { settings: CONFIG.defaultSettings, stats: { totalLogins: 0, // autoClicks: 0, // ❌ 已移除:自动点击统计 manualClicks: 0, sessionsCount: 0, lastUpdate: null, installDate: new Date().toISOString(), totalUsageTime: 0, declineCount: 0 }, history: [], metadata: { version: CONFIG.version, lastBackup: null, migrationVersion: 1 } // ❌ 已移除:remoteWhitelist 和 remoteWhitelistUpdatedAt 的默认值 }; return defaults[key] || {}; } get(key, defaultValue = null) { try { return GM_getValue(this.prefix + key, defaultValue); } catch (error) { Utils.log(`读取存储失败: ${key}`, 'error'); return defaultValue; } } set(key, value) { try { GM_setValue(this.prefix + key, value); Utils.log(`存储成功: ${key}`); return true; } catch (error) { Utils.log(`存储失败: ${key}`, 'error'); return false; } } getSettings() { return { ...CONFIG.defaultSettings, ...this.get('settings', {}) }; } updateSetting(key, value) { const settings = this.getSettings(); settings[key] = value; this.set('settings', settings); Utils.log(`设置更新: ${key} = ${value}`); } addHistory(record) { const history = this.get('history', []); const newRecord = { id: Utils.generateId(), timestamp: new Date().toISOString(), ...record }; history.unshift(newRecord); if (history.length > 200) { // 增加历史记录数量 history.splice(200); } this.set('history', history); Utils.log('历史记录已保存'); return newRecord; } getHistory() { return this.get('history', []); } clearHistory() { this.set('history', []); Utils.log('历史记录已清空'); } updateStats(key, value = 1) { const stats = this.get('stats', this.getDefaultValue('stats')); stats[key] = (stats[key] || 0) + value; stats.lastUpdate = new Date().toISOString(); this.set('stats', stats); Utils.log(`统计更新: ${key} +${value}`); } getStats() { return this.get('stats', this.getDefaultValue('stats')); } exportAllData() { const data = { settings: this.getSettings(), stats: this.getStats(), history: this.getHistory(), metadata: { version: CONFIG.version, exportDate: new Date().toISOString(), dataSize: this.calculateDataSize() } }; return data; } importAllData(data) { try { if (data.settings) this.set('settings', data.settings); if (data.stats) this.set('stats', data.stats); if (data.history) this.set('history', data.history); Utils.log('数据导入成功'); return true; } catch (error) { Utils.log('数据导入失败: ' + error.message, 'error'); return false; } } calculateDataSize() { let totalSize = 0; // ❌ 已移除:'remoteWhitelist', 'remoteWhitelistUpdatedAt' 的计算 ['settings', 'stats', 'history', 'metadata'].forEach(key => { const data = this.get(key); if (data) { totalSize += JSON.stringify(data).length; } }); return totalSize; } } // ================== 页面信息提取 ================== class PageInfo { constructor() { this.extract(); } extract() { try { const userEl = document.querySelector('h1.text-2xl'); const userText = userEl ? userEl.textContent : ''; const userMatch = userText.match(/你好,\s*$([^)]+)$\s*(\d+)级用户/); const systemEl = this.findTextElement('系统:'); const system = systemEl ? systemEl.textContent.replace('系统:', '').trim() : '未知系统'; // ✅ 正确从同一 <p> 内部取到 <a> const websiteEl = this.findTextElement('网站:'); let website = '未知网站'; let websiteUrl = ''; if (websiteEl) { const link = websiteEl.querySelector('a'); if (link) { website = (link.textContent || '').trim(); websiteUrl = link.getAttribute('href') || ''; } else { website = websiteEl.textContent.replace('网站:', '').trim(); } } // ✅ 归一化为纯域名(不带 https:// 且无末尾 /) const websiteHost = Utils.normalizeHost(websiteUrl || website); const descEl = this.findTextElement('描述:'); const description = descEl ? descEl.textContent.replace('描述:', '').trim() : '无描述'; this.info = { user: { name: userMatch ? userMatch[1] : '未知用户', level: userMatch ? parseInt(userMatch[2]) : 0 }, system, website, websiteUrl, description, extractTime: new Date().toISOString(), pageType: this.getPageType(), url: window.location.href }; Utils.log('页面信息提取完成'); } catch (error) { Utils.log('页面信息提取失败', 'error'); this.info = { user: { name: '未知用户', level: 0 }, system: '未知系统', website: '未知网站', websiteUrl: '', websiteHost, description: '无描述', extractTime: new Date().toISOString(), pageType: this.getPageType(), url: window.location.href }; } } getPageType() { const path = window.location.pathname; if (path.includes('/oauth2/approve')) return 'oauth-approve'; if (path.includes('/oauth2/decline')) return 'oauth-decline'; if (path.includes('/oauth2/')) return 'oauth-other'; return 'main'; } findTextElement(text) { const elements = document.querySelectorAll('strong'); for (const el of elements) { if (el.textContent.includes(text)) { return el.parentElement; } } return null; } get() { return this.info; } } // ================== 点击跟踪管理器 ================== class ClickTracker { constructor(storage, settings) { this.storage = storage; this.settings = settings; this.hasTrackedManualClick = false; this.pageInfo = new PageInfo(); Utils.log('点击跟踪管理器初始化'); this.init(); } async init() { await this.waitForButtons(); this.addManualClickListeners(); } async waitForButtons() { return new Promise((resolve) => { const checkButtons = () => { // const approveBtn = document.querySelector(CONFIG.selectors.approveButton); // ❌ 已移除:自动点击相关按钮检查 const declineBtn = document.querySelector(CONFIG.selectors.declineButton); if (/* approveBtn || */ declineBtn) { // ❌ 已移除:approveBtn 检查 Utils.log('找到授权按钮,准备添加监听器'); resolve(); } else { setTimeout(checkButtons, 100); } }; checkButtons(); }); } addManualClickListeners() { // const approveBtn = document.querySelector(CONFIG.selectors.approveButton); // ❌ 已移除:自动点击相关按钮监听 // if (approveBtn) { // approveBtn.addEventListener('click', (e) => { // Utils.log('检测到手动点击授权按钮'); // this.recordManualClick('手动授权', 'approve'); // }); // } const declineBtn = document.querySelector(CONFIG.selectors.declineButton); if (declineBtn) { declineBtn.addEventListener('click', (e) => { Utils.log('检测到手动点击拒绝按钮'); this.recordManualClick('手动拒绝', 'decline'); }); } } recordManualClick(action, type) { if (this.hasTrackedManualClick) { Utils.log('已记录过手动点击,跳过'); return; } this.hasTrackedManualClick = true; if (this.settings.saveLoginHistory) { const pageInfo = this.pageInfo.get(); this.storage.addHistory({ action: action, system: pageInfo.system, website: pageInfo.website, description: pageInfo.description, user: pageInfo.user, clickType: 'manual', buttonType: type, pageType: pageInfo.pageType, url: pageInfo.url }); Utils.log(`手动点击历史已记录: ${action}`); } this.storage.updateStats('manualClicks'); this.storage.updateStats('totalLogins'); if (type === 'decline') { this.storage.updateStats('declineCount'); } Utils.log(`手动点击统计已更新: ${action}`); if (this.settings.showNotifications) { this.showNotification(`${action}已记录`); } } showNotification(message) { if (typeof GM_notification === 'function') { GM_notification({ title: '🏆 OAuth助手', text: message, timeout: this.settings.notificationDuration }); } } updateSettings(settings) { this.settings = settings; } } // ================== 自动点击管理器 ================== // ❌ 已移除:整个 AutoClickManager 类 /* class AutoClickManager { constructor(storage, settings) { // ... 原有代码 ... } init() { // ... 原有代码 ... } async attemptAutoClick() { // ... 原有代码 ... } showNotification(message) { // ... 原有代码 ... } updateSettings(settings) { // ... 原有代码 ... } } */ // ================== UI管理器 ================== class UIManager { constructor(storage) { this.storage = storage; this.settings = storage.getSettings(); this.isVisible = false; this.currentTheme = this.settings.theme; this.currentUITheme = this.settings.uiTheme || 'minimal-white'; this.init(); } init() { this.addStyles(); this.createUI(); this.bindEvents(); this.applyTheme(); this.applyUITheme(); Utils.log('UI管理器初始化完成'); } addStyles() { const isOAuthPage = this.isOAuthPage(); const enableStyling = this.settings.enablePageStyling; const uiTheme = CONFIG.uiThemes[this.currentUITheme]; let css = ` /* OAuth助手基础样式 */ .oauth-helper { position: fixed; ${this.getPositionStyles()} z-index: 10000; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } .oauth-trigger { width: 48px; height: 48px; background: ${uiTheme.colors.triggerBg}; border: 2px solid ${uiTheme.colors.panelBorder}; border-radius: 24px; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); transition: all 0.3s ease; color: ${uiTheme.colors.text}; font-size: 20px; ${this.currentUITheme === 'rainbow-fancy' ? 'animation: rainbow-rotate 4s ease-in-out infinite;' : ''} } .oauth-trigger:hover { transform: translateY(-2px) scale(1.05); box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2); ${this.currentUITheme === 'rainbow-fancy' ? 'filter: brightness(1.1);' : ''} } .oauth-trigger.active { transform: translateY(-1px) scale(1.02); box-shadow: 0 8px 12px -2px rgba(0, 0, 0, 0.15); } .oauth-panel { position: absolute; ${this.getPanelPositionStyles()} width: 400px; background: ${uiTheme.colors.panelBg}; border: 2px solid ${uiTheme.colors.panelBorder}; border-radius: 16px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); opacity: 0; visibility: hidden; transform: translateY(-12px) scale(0.95); transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); overflow: hidden; max-height: 80vh; backdrop-filter: blur(10px); ${this.currentUITheme === 'rainbow-fancy' ? 'animation: rainbow-bg 6s ease-in-out infinite; background-size: 400% 400%;' : ''} } .oauth-panel.show { opacity: 1; visibility: visible; transform: translateY(0) scale(1); } .oauth-header { padding: 20px 24px; background: ${this.currentUITheme === 'minimal-white' ? '#fafafa' : 'rgba(255,255,255,0.1)'}; border-bottom: 1px solid ${uiTheme.colors.panelBorder}; backdrop-filter: blur(5px); } .oauth-title { font-size: 18px; font-weight: 700; color: ${uiTheme.colors.text}; margin: 0; ${this.currentUITheme === 'rainbow-fancy' ? 'background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; animation: rainbow-text 3s ease-in-out infinite;' : ''} } .oauth-version { font-size: 11px; color: ${uiTheme.colors.textMuted}; margin-top: 4px; font-weight: 500; } .oauth-content { padding: 0; max-height: calc(80vh - 100px); overflow-y: auto; background: ${this.currentUITheme === 'minimal-white' ? 'transparent' : 'rgba(255,255,255,0.05)'}; } .oauth-content::-webkit-scrollbar { width: 6px; } .oauth-content::-webkit-scrollbar-track { background: transparent; } .oauth-content::-webkit-scrollbar-thumb { background: ${uiTheme.colors.textMuted}; border-radius: 3px; opacity: 0.5; } .oauth-section { padding: 18px 24px; border-bottom: 1px solid ${uiTheme.colors.panelBorder}; backdrop-filter: blur(2px); } .oauth-section:last-child { border-bottom: none; } .oauth-section-title { font-size: 14px; font-weight: 700; color: ${uiTheme.colors.text}; margin-bottom: 16px; display: flex; align-items: center; gap: 10px; ${this.currentUITheme === 'rainbow-fancy' ? 'text-shadow: 0 0 10px rgba(255,255,255,0.5);' : ''} } .oauth-switch-item { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; background: ${this.currentUITheme === 'minimal-white' ? '#f9fafb' : 'rgba(255,255,255,0.1)'}; border-radius: 12px; margin-bottom: 10px; transition: all 0.3s ease; backdrop-filter: blur(5px); ${this.currentUITheme === 'rainbow-fancy' ? 'border: 1px solid rgba(255,255,255,0.2);' : ''} } .oauth-switch-item:hover { background: ${this.currentUITheme === 'minimal-white' ? '#f3f4f6' : 'rgba(255,255,255,0.15)'}; transform: translateY(-1px); ${this.currentUITheme === 'rainbow-fancy' ? 'box-shadow: 0 4px 15px rgba(0,0,0,0.1);' : ''} } .oauth-switch-info { flex: 1; } .oauth-switch-label { font-size: 14px; color: ${uiTheme.colors.text}; font-weight: 600; margin-bottom: 3px; } .oauth-switch-desc { font-size: 12px; color: ${uiTheme.colors.textMuted}; line-height: 1.4; } .oauth-switch { position: relative; width: 44px; height: 24px; background: ${this.currentUITheme === 'minimal-white' ? '#e5e7eb' : 'rgba(255,255,255,0.2)'}; border-radius: 12px; cursor: pointer; transition: all 0.3s ease; flex-shrink: 0; } .oauth-switch.active { background: ${uiTheme.colors.accent}; ${this.currentUITheme === 'rainbow-fancy' ? 'box-shadow: 0 0 20px rgba(255,107,107,0.6);' : ''} } .oauth-switch-knob { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: white; border-radius: 50%; transition: all 0.3s ease; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); } .oauth-switch.active .oauth-switch-knob { transform: translateX(20px); ${this.currentUITheme === 'rainbow-fancy' ? 'box-shadow: 0 0 15px rgba(255,255,255,0.8);' : ''} } .oauth-btn { background: ${this.currentUITheme === 'minimal-white' ? 'white' : 'rgba(255,255,255,0.1)'}; border: 1px solid ${uiTheme.colors.panelBorder}; color: ${uiTheme.colors.text}; font-size: 12px; padding: 8px 14px; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; font-weight: 600; margin-right: 8px; margin-bottom: 6px; backdrop-filter: blur(5px); display: inline-block; } .oauth-btn:hover { background: ${this.currentUITheme === 'minimal-white' ? '#f3f4f6' : 'rgba(255,255,255,0.2)'}; transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); } .oauth-btn.primary { background: ${uiTheme.colors.accent}; color: white; border-color: ${uiTheme.colors.accent}; ${this.currentUITheme === 'rainbow-fancy' ? 'background: linear-gradient(45deg, #ff6b6b, #4ecdc4); border: none;' : ''} } .oauth-btn.primary:hover { ${this.currentUITheme === 'rainbow-fancy' ? 'filter: brightness(1.1); transform: translateY(-2px);' : 'filter: brightness(0.9);'} } .oauth-btn.danger { border-color: #ef4444; color: #ef4444; } .oauth-btn.danger:hover { border-color: #dc2626; color: #dc2626; background: ${this.currentUITheme === 'minimal-white' ? '#fef2f2' : 'rgba(239,68,68,0.1)'}; } .oauth-stat-card { background: ${this.currentUITheme === 'minimal-white' ? '#f9fafb' : 'rgba(255,255,255,0.1)'}; border: 1px solid ${uiTheme.colors.panelBorder}; border-radius: 12px; padding: 16px; text-align: center; margin-bottom: 10px; transition: all 0.3s ease; backdrop-filter: blur(5px); ${this.currentUITheme === 'rainbow-fancy' ? 'border: 1px solid rgba(255,255,255,0.2);' : ''} } .oauth-stat-card:hover { transform: translateY(-2px); ${this.currentUITheme === 'rainbow-fancy' ? 'box-shadow: 0 8px 25px rgba(0,0,0,0.15);' : ''} } .oauth-stat-value { font-size: 24px; font-weight: 800; color: ${uiTheme.colors.text}; margin-bottom: 6px; ${this.currentUITheme === 'rainbow-fancy' ? 'background: linear-gradient(45deg, #ff6b6b, #4ecdc4); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent;' : ''} } .oauth-stat-label { font-size: 11px; color: ${uiTheme.colors.textMuted}; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; } .oauth-stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 16px; } /* 条形图样式 */ .oauth-chart-container { background: ${this.currentUITheme === 'minimal-white' ? '#f9fafb' : 'rgba(255,255,255,0.1)'}; border: 1px solid ${uiTheme.colors.panelBorder}; border-radius: 12px; padding: 16px; margin-bottom: 16px; backdrop-filter: blur(5px); ${this.currentUITheme === 'rainbow-fancy' ? 'border: 1px solid rgba(255,255,255,0.2);' : ''} } .oauth-chart-title { font-size: 13px; font-weight: 600; color: ${uiTheme.colors.text}; margin-bottom: 12px; text-align: center; display: flex; align-items: center; justify-content: center; gap: 6px; } .oauth-chart-bars { display: flex; align-items: end; gap: 6px; height: 100px; justify-content: space-between; margin-bottom: 4px; } .oauth-chart-bar-container { display: flex; flex-direction: column; align-items: center; flex: 1; min-width: 0; } .oauth-chart-bar-wrapper { position: relative; display: flex; align-items: end; width: 100%; margin-bottom: 8px; } .oauth-chart-bar { width: 100%; background: ${uiTheme.colors.accent}; border-radius: 4px 4px 0 0; position: relative; transition: all 0.3s ease; min-height: 4px; cursor: pointer; ${this.currentUITheme === 'rainbow-fancy' ? 'background: linear-gradient(45deg, #ff6b6b, #4ecdc4); box-shadow: 0 2px 8px rgba(255,107,107,0.3);' : ''} } .oauth-chart-bar:hover { ${this.currentUITheme === 'rainbow-fancy' ? 'filter: brightness(1.1); box-shadow: 0 4px 12px rgba(255,107,107,0.4);' : 'filter: brightness(0.9);'} transform: translateY(-1px); } .oauth-chart-value { position: absolute; top: -20px; left: 50%; transform: translateX(-50%); font-size: 10px; font-weight: 600; color: ${uiTheme.colors.text}; background: ${this.currentUITheme === 'minimal-white' ? 'rgba(255,255,255,0.9)' : 'rgba(0,0,0,0.7)'}; padding: 2px 6px; border-radius: 4px; white-space: nowrap; opacity: 0; transition: opacity 0.3s ease; } .oauth-chart-bar:hover .oauth-chart-value { opacity: 1; } .oauth-chart-label { font-size: 10px; color: ${uiTheme.colors.textMuted}; font-weight: 500; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; } .oauth-chart-empty { text-align: center; color: ${uiTheme.colors.textMuted}; font-size: 12px; padding: 40px 20px; font-style: italic; } .oauth-history-item { padding: 16px; border-bottom: 1px solid ${uiTheme.colors.panelBorder}; font-size: 13px; transition: all 0.3s ease; } .oauth-history-item:hover { background: ${this.currentUITheme === 'minimal-white' ? '#f9fafb' : 'rgba(255,255,255,0.05)'}; padding-left: 20px; } .oauth-history-item:last-child { border-bottom: none; } .oauth-history-title { font-weight: 700; color: ${uiTheme.colors.text}; margin-bottom: 6px; display: flex; justify-content: space-between; align-items: center; } .oauth-history-detail { color: ${uiTheme.colors.textMuted}; margin-bottom: 3px; font-size: 12px; } .oauth-history-time { color: ${uiTheme.colors.textMuted}; font-size: 10px; font-weight: 500; } .oauth-history-badge { font-size: 10px; padding: 3px 8px; border-radius: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; } .oauth-history-badge.auto { background: ${this.currentUITheme === 'minimal-white' ? '#dbeafe' : 'rgba(59,130,246,0.2)'}; color: ${this.currentUITheme === 'minimal-white' ? '#1e40af' : '#93c5fd'}; } .oauth-history-badge.manual { background: ${this.currentUITheme === 'minimal-white' ? '#d1fae5' : 'rgba(34,197,94,0.2)'}; color: ${this.currentUITheme === 'minimal-white' ? '#065f46' : '#86efac'}; } .oauth-empty { text-align: center; padding: 40px 20px; color: ${uiTheme.colors.textMuted}; font-style: italic; font-size: 12px; } .oauth-divider { height: 1px; background: ${uiTheme.colors.panelBorder}; margin: 16px 0; } .oauth-input, .oauth-select { width: 100%; padding: 10px 14px; border: 1px solid ${uiTheme.colors.panelBorder}; border-radius: 8px; background: ${this.currentUITheme === 'minimal-white' ? 'white' : 'rgba(255,255,255,0.1)'}; color: ${uiTheme.colors.text}; font-size: 13px; margin: 6px 0; transition: all 0.3s ease; backdrop-filter: blur(5px); } .oauth-input:focus, .oauth-select:focus { outline: none; border-color: ${uiTheme.colors.accent}; ${this.currentUITheme === 'rainbow-fancy' ? 'box-shadow: 0 0 20px rgba(255,107,107,0.3);' : 'box-shadow: 0 0 0 3px rgba(16,185,129,0.1);'} } .oauth-ui-theme-selector { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; margin-top: 12px; } .oauth-ui-theme-option { padding: 12px 8px; border: 2px solid ${uiTheme.colors.panelBorder}; border-radius: 10px; text-align: center; cursor: pointer; transition: all 0.3s ease; background: ${this.currentUITheme === 'minimal-white' ? 'white' : 'rgba(255,255,255,0.1)'}; backdrop-filter: blur(5px); } .oauth-ui-theme-option:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); } .oauth-ui-theme-option.active { border-color: ${uiTheme.colors.accent}; background: ${this.currentUITheme === 'minimal-white' ? '#f0fdf4' : 'rgba(16,185,129,0.1)'}; ${this.currentUITheme === 'rainbow-fancy' ? 'box-shadow: 0 0 20px rgba(255,107,107,0.3);' : ''} } .oauth-ui-theme-icon { font-size: 18px; margin-bottom: 4px; } .oauth-ui-theme-name { font-size: 11px; font-weight: 600; color: ${uiTheme.colors.text}; } /* 动画效果 */ @keyframes rainbow-rotate { 0%, 100% { transform: rotate(0deg) scale(1); } 50% { transform: rotate(180deg) scale(1.1); } } @keyframes rainbow-bg { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } @keyframes rainbow-text { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } } .oauth-highlight { animation: pulse 1s ease-in-out 3; } .oauth-fade-in { animation: fadeIn 0.5s ease-out; } `; // 只在OAuth页面且启用UI优化时添加页面美化样式 if (isOAuthPage && enableStyling) { css += this.getOAuthPageStyles(); } GM_addStyle(css); } getOAuthPageStyles() { const uiTheme = this.currentUITheme; switch (uiTheme) { case 'purple-gradient': return ` /* 紫色渐变主题页面美化 */ body { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; min-height: 100vh; } .bg-white { background: rgba(255,255,255,0.95) !important; backdrop-filter: blur(10px) !important; border-radius: 20px !important; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25) !important; border: 1px solid rgba(255,255,255,0.2) !important; } .bg-red-500, .bg-blue-500 { border-radius: 12px !important; font-weight: 600 !important; padding: 12px 24px !important; transition: all 0.3s ease !important; backdrop-filter: blur(5px) !important; } .bg-red-500 { background: linear-gradient(135deg, #10b981, #059669) !important; color: white !important; border: none !important; } .bg-red-500:hover { background: linear-gradient(135deg, #059669, #047857) !important; transform: translateY(-2px) !important; box-shadow: 0 10px 25px rgba(16,185,129,0.4) !important; } .bg-red-500::before { content: '✓ '; color: white; font-weight: bold; } .bg-blue-500 { background: rgba(239,68,68,0.9) !important; color: white !important; border: none !important; } .bg-blue-500:hover { background: rgba(220,38,38,0.9) !important; transform: translateY(-2px) !important; box-shadow: 0 10px 25px rgba(239,68,68,0.4) !important; } .bg-blue-500::before { content: '✕ '; color: white; font-weight: bold; } /* 权限说明框样式 */ .bg-white p:has(strong) { background: linear-gradient(135deg, #fef3c7, #fde68a) !important; padding: 16px !important; border-radius: 12px !important; border-left: 4px solid #f59e0b !important; margin: 16px 0 !important; } `; case 'rainbow-fancy': return ` /* 彩虹华丽主题页面美化 */ body { background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab) !important; background-size: 400% 400% !important; animation: rainbow-bg 6s ease-in-out infinite !important; min-height: 100vh !important; } .bg-white { background: rgba(255,255,255,0.1) !important; backdrop-filter: blur(20px) !important; border-radius: 25px !important; box-shadow: 0 30px 60px -12px rgba(0, 0, 0, 0.4) !important; border: 2px solid rgba(255,255,255,0.3) !important; position: relative !important; overflow: hidden !important; } .bg-white::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(45deg, transparent 40%, rgba(255,255,255,0.1) 50%, transparent 60%); animation: shine 3s ease-in-out infinite; pointer-events: none; } @keyframes shine { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } .bg-red-500, .bg-blue-500 { border-radius: 15px !important; font-weight: 700 !important; padding: 14px 28px !important; transition: all 0.4s ease !important; backdrop-filter: blur(10px) !important; position: relative !important; overflow: hidden !important; } .bg-red-500 { background: linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4) !important; background-size: 300% 300% !important; animation: rainbow-button 4s ease-in-out infinite !important; color: white !important; border: none !important; text-shadow: 0 2px 4px rgba(0,0,0,0.3) !important; } .bg-red-500:hover { transform: translateY(-3px) scale(1.05) !important; box-shadow: 0 15px 35px rgba(255,107,107,0.6) !important; filter: brightness(1.2) !important; } .bg-red-500::before { content: '✨ '; color: white; font-weight: bold; } .bg-blue-500 { background: linear-gradient(45deg, #ff6b6b, #ee5a24, #ff9ff3, #54a0ff) !important; background-size: 300% 300% !important; animation: rainbow-button-reverse 4s ease-in-out infinite !important; color: white !important; border: none !important; text-shadow: 0 2px 4px rgba(0,0,0,0.3) !important; } .bg-blue-500:hover { transform: translateY(-3px) scale(1.05) !important; box-shadow: 0 15px 35px rgba(255,107,107,0.6) !important; filter: brightness(1.2) !important; } .bg-blue-500::before { content: '💫 '; color: white; font-weight: bold; } @keyframes rainbow-button { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } } @keyframes rainbow-button-reverse { 0%, 100% { background-position: 100% 50%; } 50% { background-position: 0% 50%; } } /* 华丽的权限说明框 */ .bg-white p:has(strong) { background: linear-gradient(45deg, rgba(255,215,0,0.3), rgba(255,165,0,0.3)) !important; padding: 20px !important; border-radius: 15px !important; border: 2px solid rgba(255,215,0,0.5) !important; margin: 20px 0 !important; box-shadow: 0 8px 25px rgba(255,215,0,0.3) !important; position: relative !important; overflow: hidden !important; } .bg-white p:has(strong)::before { content: '🔒'; position: absolute; top: 10px; right: 15px; font-size: 20px; animation: float 2s ease-in-out infinite; } @keyframes float { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-5px); } } `; default: // minimal-white return ` /* 简约白主题页面美化 */ body { background: #f9fafb !important; } .bg-red-500, .bg-blue-500 { background: white !important; color: #374151 !important; border: 2px solid #e5e7eb !important; transition: all 0.2s ease !important; position: relative !important; } .bg-red-500:hover, .bg-blue-500:hover { background: #f9fafb !important; border-color: #d1d5db !important; color: #111827 !important; transform: translateY(-1px) !important; } .bg-red-500::before { content: '✓ '; color: #10b981; font-weight: bold; } .bg-blue-500::before { content: '✕ '; color: #ef4444; font-weight: bold; } /* 简约白主题的信息框样式 - 保持简洁 */ .bg-white p:has(strong) { background: white !important; padding: 16px !important; border-radius: 8px !important; border: 1px solid #e5e7eb !important; margin: 16px 0 !important; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important; } `; } } getPositionStyles() { const pos = this.settings.panelPosition; switch (pos) { case 'top-left': return 'top: 20px; left: 20px;'; case 'bottom-right': return 'bottom: 20px; right: 20px;'; case 'bottom-left': return 'bottom: 20px; left: 20px;'; default: return 'top: 20px; right: 20px;'; } } getPanelPositionStyles() { const pos = this.settings.panelPosition; switch (pos) { case 'top-left': return 'top: 56px; left: 0;'; case 'bottom-right': return 'bottom: 56px; right: 0;'; case 'bottom-left': return 'bottom: 56px; left: 0;'; default: return 'top: 56px; right: 0;'; } } isOAuthPage() { return window.location.pathname.includes('/oauth2/'); } createUI() { const ui = document.createElement('div'); ui.className = 'oauth-helper'; ui.innerHTML = ` <div class="oauth-trigger" id="oauthTrigger"> 🏆 </div> <div class="oauth-panel" id="oauthPanel"> <div class="oauth-header"> <div class="oauth-title">🏆 OAuth助手</div> <div class="oauth-version">v${CONFIG.version} - 面板集成版 (无自动点击)</div> </div> <div class="oauth-content"> ${this.generateContent()} </div> </div> `; document.body.appendChild(ui); this.ui = ui; } generateContent() { return ` ${this.generateUIThemeHTML()} ${this.generateSettingsHTML()} ${this.generateAdvancedSettingsHTML()} ${this.generateStatsHTML()} ${this.generateHistoryHTML()} ${this.generateToolsHTML()} `; } generateUIThemeHTML() { return ` <div class="oauth-section"> <div class="oauth-section-title"> <span>🎨</span> <span>UI主题切换</span> </div> <div style="margin-bottom: 12px; font-size: 12px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted};"> 选择你喜欢的界面风格,即时生效 </div> <div class="oauth-ui-theme-selector"> ${Object.entries(CONFIG.uiThemes).map(([key, theme]) => ` <div class="oauth-ui-theme-option ${this.currentUITheme === key ? 'active' : ''}" data-theme="${key}"> <div class="oauth-ui-theme-icon">${theme.icon}</div> <div class="oauth-ui-theme-name">${theme.name}</div> </div> `).join('')} </div> <div style="margin-top: 8px; font-size: 11px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted}; text-align: center;"> 当前:${CONFIG.uiThemes[this.currentUITheme].description} </div> <div style="margin-top: 12px;"> <button class="oauth-btn primary" id="toggleUITheme">🔄 快速切换主题</button> <button class="oauth-btn" id="toggleTheme">🌓 颜色主题</button> </div> </div> `; } generateSettingsHTML() { const settings = this.settings; return ` <div class="oauth-section"> <div class="oauth-section-title"> <span>⚙️</span> <span>基础设置</span> </div> <!-- 原有:保存登录(不可用)记录 --> <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">保存登录(不可用)记录</div> <div class="oauth-switch-desc">记录所有授权操作的详细历史</div> </div> <div class="oauth-switch ${settings.saveLoginHistory ? 'active' : ''}" data-setting="saveLoginHistory"> <div class="oauth-switch-knob"></div> </div> </div> <!-- 原有:显示通知 --> <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">显示通知</div> <div class="oauth-switch-desc">操作完成后显示提示通知</div> </div> <div class="oauth-switch ${settings.showNotifications ? 'active' : ''}" data-setting="showNotifications"> <div class="oauth-switch-knob"></div> </div> </div> <!-- 原有:启用UI优化 --> <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">启用UI优化</div> <div class="oauth-switch-desc">美化OAuth页面按钮和样式</div> </div> <div class="oauth-switch ${settings.enablePageStyling ? 'active' : ''}" data-setting="enablePageStyling"> <div class="oauth-switch-knob"></div> </div> </div> <!-- ❌ 已移除:网站白名单限制 --> <!-- <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">网站白名单限制</div> <div class="oauth-switch-desc">只对白名单网站自动授权(默认开启)。名单来源:GitHub远程 + 本地补充</div> </div> <div class="oauth-switch ${settings.restrictByWebsite ? 'active' : ''}" data-setting="restrictByWebsite"> <div class="oauth-switch-knob"></div> </div> </div> --> <!-- ❌ 已移除:操作按钮行 --> <!-- <div style="display:flex;gap:8px;align-items:center;margin-top:8px;"> <button class="oauth-btn" id="refreshRemoteWhitelist">🔄 立即刷新远程白名单</button> <button class="oauth-btn" id="addCurrentSiteToWhitelist">➕ 把当前网站加入本地白名单</button> </div> --> </div> `; } generateAdvancedSettingsHTML() { const settings = this.settings; return ` <div class="oauth-section"> <div class="oauth-section-title"> <span>🔧</span> <span>高级设置</span> </div> <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">自动隐藏面板</div> <div class="oauth-switch-desc">点击外部区域自动关闭面板</div> </div> <div class="oauth-switch ${settings.autoHidePanel ? 'active' : ''}" data-setting="autoHidePanel"> <div class="oauth-switch-knob"></div> </div> </div> <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">显示图表统计</div> <div class="oauth-switch-desc">显示最近7天登录(不可用)趋势条形图</div> </div> <div class="oauth-switch ${settings.showChartStats ? 'active' : ''}" data-setting="showChartStats"> <div class="oauth-switch-knob"></div> </div> </div> <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">显示小时统计</div> <div class="oauth-switch-desc">显示今日24小时登录(不可用)分布图</div> </div> <div class="oauth-switch ${settings.showHourlyChart ? 'active' : ''}" data-setting="showHourlyChart"> <div class="oauth-switch-knob"></div> </div> </div> <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">显示网站统计</div> <div class="oauth-switch-desc">显示各网站授权次数排行</div> </div> <div class="oauth-switch ${settings.showWebsiteStats ? 'active' : ''}" data-setting="showWebsiteStats"> <div class="oauth-switch-knob"></div> </div> </div> <div class="oauth-switch-item"> <div class="oauth-switch-info"> <div class="oauth-switch-label">调试模式</div> <div class="oauth-switch-desc">在控制台显示详细运行日志</div> </div> <div class="oauth-switch ${settings.enableDebugMode ? 'active' : ''}" data-setting="enableDebugMode"> <div class="oauth-switch-knob"></div> </div> </div> <div style="margin-top: 12px;"> <label style="font-size: 12px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted};">颜色主题</label> <select class="oauth-select" id="themeSelect"> <option value="light" ${settings.theme === 'light' ? 'selected' : ''}>浅色主题</option> <option value="dark" ${settings.theme === 'dark' ? 'selected' : ''}>深色主题</option> <option value="auto" ${settings.theme === 'auto' ? 'selected' : ''}>自动切换</option> </select> </div> <div style="margin-top: 8px;"> <label style="font-size: 12px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted};">面板位置</label> <select class="oauth-select" id="positionSelect"> <option value="top-right" ${settings.panelPosition === 'top-right' ? 'selected' : ''}>右上角</option> <option value="top-left" ${settings.panelPosition === 'top-left' ? 'selected' : ''}>左上角</option> <option value="bottom-right" ${settings.panelPosition === 'bottom-right' ? 'selected' : ''}>右下角</option> <option value="bottom-left" ${settings.panelPosition === 'bottom-left' ? 'selected' : ''}>左下角</option> </select> </div> </div> `; } generateStatsHTML() { const stats = this.storage.getStats(); const history = this.storage.getHistory(); const isOAuth = this.isOAuthPage(); const uiTheme = CONFIG.uiThemes[this.currentUITheme]; // 生成多种统计图表 let chartsHTML = ''; if (this.settings.showChartStats) { const timeSeriesData = Utils.generateTimeSeriesData(history); const chartBars = Utils.generateBarChart(timeSeriesData, { maxHeight: 80, barColor: uiTheme.colors.accent, showValues: true, className: 'oauth-chart-bar' }); chartsHTML += ` <div class="oauth-chart-container"> <div class="oauth-chart-title">📈 最近7天登录(不可用)统计</div> <div class="oauth-chart-bars"> ${chartBars} </div> </div> `; } if (this.settings.showHourlyChart) { const hourlyData = Utils.generateHourlyData(history); const hourlyBars = Utils.generateBarChart(hourlyData, { maxHeight: 60, barColor: '#8b5cf6', showValues: true, className: 'oauth-chart-bar' }); chartsHTML += ` <div class="oauth-chart-container"> <div class="oauth-chart-title">🕐 今日小时分布</div> <div class="oauth-chart-bars"> ${hourlyBars} </div> </div> `; } if (this.settings.showWebsiteStats) { const websiteData = Utils.generateWebsiteStats(history); const websiteBars = Utils.generateBarChart(websiteData, { maxHeight: 70, barColor: '#f59e0b', showValues: true, className: 'oauth-chart-bar' }); chartsHTML += ` <div class="oauth-chart-container"> <div class="oauth-chart-title">🌍 网站授权排行 (TOP 5)</div> <div class="oauth-chart-bars"> ${websiteBars} </div> </div> `; } return ` <div class="oauth-section"> <div class="oauth-section-title"> <span>📊</span> <span>使用统计</span> </div> <div class="oauth-stat-grid"> <div class="oauth-stat-card"> <div class="oauth-stat-value">${stats.totalLogins}</div> <div class="oauth-stat-label">总授权次数</div> </div> <div class="oauth-stat-card"> <div class="oauth-stat-value">${stats.sessionsCount || 0}</div> <div class="oauth-stat-label">使用会话</div> </div> </div> <div class="oauth-stat-grid"> <div class="oauth-stat-card"> <div class="oauth-stat-value">${stats.manualClicks || 0}</div> <div class="oauth-stat-label">手动点击</div> </div> <div class="oauth-stat-card"> <div class="oauth-stat-value">${stats.declineCount || 0}</div> <div class="oauth-stat-label">拒绝次数</div> </div> </div> ${chartsHTML} ${isOAuth ? '<div style="text-align: center; margin-top: 8px; color: ' + uiTheme.colors.textMuted + '; font-size: 11px;">🔐 当前页面:OAuth授权模式</div>' : '<div style="text-align: center; margin-top: 8px; color: ' + uiTheme.colors.textMuted + '; font-size: 11px;">🏠 当前页面:主页面模式</div>'} </div> `; } generateHistoryHTML() { const history = this.storage.getHistory().slice(0, 6); let historyHTML = ''; if (history.length === 0) { historyHTML = '<div class="oauth-empty">📋 暂无授权记录<br><small>启用"保存登录(不可用)记录"后将显示历史</small></div>'; } else { historyHTML = history.map(record => ` <div class="oauth-history-item"> <div class="oauth-history-title"> ${record.system || '未知系统'} <span class="oauth-history-badge ${record.clickType}">${record.clickType === 'auto' ? '自动' : '手动'}</span> </div> <div class="oauth-history-detail">🌍 网站: ${record.website || '未知网站'}</div> <div class="oauth-history-detail">👤 用户: ${record.user?.name || '未知'} ${record.user?.level ? `(${record.user.level}级)` : ''}</div> <div class="oauth-history-detail">⚡ 操作: ${record.action || '未知操作'}</div> <div class="oauth-history-time">⏰ ${Utils.formatDate(record.timestamp)}</div> </div> `).join(''); } return ` <div class="oauth-section"> <div class="oauth-section-title"> <span>📋</span> <span>最近记录</span> </div> ${historyHTML} ${history.length > 0 ? ` <div style="text-align: center; margin-top: 12px;"> <button class="oauth-btn" id="viewAllHistory">📋 查看全部记录 (${this.storage.getHistory().length})</button> </div> ` : ''} </div> `; } generateToolsHTML() { const dataSize = Utils.formatBytes(this.storage.calculateDataSize()); const stats = this.storage.getStats(); const installDays = stats.installDate ? Math.floor((new Date() - new Date(stats.installDate)) / (1000 * 60 * 60 * 24)) : 0; return ` <div class="oauth-section"> <div class="oauth-section-title"> <span>🛠️</span> <span>工具箱</span> </div> <div style="margin-bottom: 12px;"> <button class="oauth-btn primary" id="exportData">💾 导出数据</button> <button class="oauth-btn" id="importData">📂 导入数据</button> <input type="file" id="importFile" accept=".json" style="display: none;"> </div> <div style="margin-bottom: 12px;"> <button class="oauth-btn" id="clearHistory">🗑️ 清空记录</button> <button class="oauth-btn danger" id="resetSettings">⚠️ 重置设置</button> </div> <div style="margin-bottom: 12px;"> <button class="oauth-btn" id="showHelp">❓ 显示帮助</button> <button class="oauth-btn" id="aboutScript">ℹ️ 关于脚本</button> </div> <div style="text-align: center; font-size: 10px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted}; line-height: 1.4;"> 📊 数据大小: ${dataSize}<br> 🎨 当前主题: ${CONFIG.uiThemes[this.currentUITheme].name}<br> 📅 使用天数: ${installDays}天 </div> </div> `; } bindEvents() { const trigger = this.ui.querySelector('#oauthTrigger'); trigger.addEventListener('click', (e) => { e.stopPropagation(); this.togglePanel(); }); this.bindContentEvents(); document.addEventListener('click', (e) => { if (!this.ui.contains(e.target) && this.isVisible) { if (this.settings.autoHidePanel) { this.hidePanel(); } } }); } bindContentEvents() { // UI主题选择事件 const themeOptions = this.ui.querySelectorAll('.oauth-ui-theme-option'); themeOptions.forEach(option => { option.addEventListener('click', (e) => { const theme = e.currentTarget.dataset.theme; this.changeUITheme(theme); }); }); // 开关事件 const switches = this.ui.querySelectorAll('.oauth-switch'); switches.forEach(switchEl => { switchEl.addEventListener('click', (e) => { const setting = e.currentTarget.dataset.setting; const isActive = e.currentTarget.classList.contains('active'); this.toggleSetting(setting, !isActive); }); }); // 下拉选择事件 const themeSelect = this.ui.querySelector('#themeSelect'); if (themeSelect) { themeSelect.addEventListener('change', (e) => { this.updateSetting('theme', e.target.value); this.applyTheme(); }); } const positionSelect = this.ui.querySelector('#positionSelect'); if (positionSelect) { positionSelect.addEventListener('change', (e) => { this.updateSetting('panelPosition', e.target.value); this.updatePosition(); }); } // 按钮事件 this.bindButtonEvents(); } bindButtonEvents() { const buttons = { exportData: () => this.exportData(), importData: () => this.ui.querySelector('#importFile').click(), clearHistory: () => this.clearHistory(), resetSettings: () => this.resetSettings(), showHelp: () => this.showHelp(), aboutScript: () => this.showAbout(), toggleUITheme: () => this.toggleUITheme(), toggleTheme: () => this.toggleTheme(), viewAllHistory: () => this.showAllHistory(), // ❌ 已移除:刷新远程白名单按钮 // refreshRemoteWhitelist: async () => { // try { // const list = await Utils.loadRemoteWhitelist(this.storage, this.settings); // this.showMessage(`✅ 远程白名单已刷新(${list.length} 条)`); // } catch (e) { // this.showMessage('❌ 刷新失败,请稍后重试', 'error'); // } // }, // ❌ 已移除:把当前网站加入本地白名单按钮 // addCurrentSiteToWhitelist: () => { // const pi = new PageInfo().get(); // const host = Utils.normalizeHost(pi.websiteUrl || pi.website); // if (!host) return this.showMessage('未识别到当前网站', 'error'); // const wl = Array.isArray(this.settings.whitelist) ? this.settings.whitelist.slice() : []; // if (wl.includes(host)) { // return this.showMessage('已在本地白名单', 'warning'); // } // wl.push(host); // this.updateSetting('whitelist', wl); // this.refreshUI(); // this.showMessage(`已加入本地白名单:${host}`); // } }; // 统一绑定每个按钮 id -> handler Object.entries(buttons).forEach(([id, handler]) => { const btn = this.ui.querySelector(`#${id}`); if (btn) { btn.addEventListener('click', handler); } }); // 维持原有的“导入文件”监听 const importFile = this.ui.querySelector('#importFile'); if (importFile) { importFile.addEventListener('change', (e) => { this.importData(e.target.files[0]); e.target.value = ''; }); } } changeUITheme(themeKey) { this.currentUITheme = themeKey; this.updateSetting('uiTheme', themeKey); // 重新创建UI this.recreateUI(); this.showMessage(`UI主题已切换为: ${CONFIG.uiThemes[themeKey].name}`); } toggleUITheme() { const themes = Object.keys(CONFIG.uiThemes); const currentIndex = themes.indexOf(this.currentUITheme); const nextTheme = themes[(currentIndex + 1) % themes.length]; this.changeUITheme(nextTheme); } recreateUI() { // 移除当前UI if (this.ui) { this.ui.remove(); } // 重新创建UI setTimeout(() => { this.addStyles(); this.createUI(); this.bindEvents(); this.applyTheme(); this.applyUITheme(); }, 100); } togglePanel() { this.isVisible = !this.isVisible; const trigger = this.ui.querySelector('#oauthTrigger'); const panel = this.ui.querySelector('#oauthPanel'); trigger.classList.toggle('active', this.isVisible); panel.classList.toggle('show', this.isVisible); if (this.isVisible) { this.refreshUI(); } } hidePanel() { if (this.isVisible) { this.togglePanel(); } } toggleSetting(key, value) { Utils.log(`切换设置: ${key} = ${value}`); this.updateSetting(key, value); const switchEl = this.ui.querySelector(`[data-setting="${key}"]`); if (switchEl) { switchEl.classList.toggle('active', value); } if (window.oauthHelper) { window.oauthHelper.updateSettings(); } // 特殊处理 - 需要重新创建UI的设置 if (['enablePageStyling', 'showChartStats', 'showHourlyChart', 'showWebsiteStats'].includes(key)) { this.recreateUI(); } this.showMessage(`${this.getSettingLabel(key)} ${value ? '已开启' : '已关闭'}`); } updateSetting(key, value) { this.settings[key] = value; this.storage.updateSetting(key, value); } getSettingLabel(key) { const labels = { // autoClickApprove: '自动点击授权', // ❌ 已移除:自动点击相关标签 saveLoginHistory: '保存登录(不可用)记录', showNotifications: '显示通知', autoHidePanel: '自动隐藏面板', enablePageStyling: 'UI优化', enableDebugMode: '调试模式', showChartStats: '图表统计', showHourlyChart: '小时统计', showWebsiteStats: '网站统计' // restrictByWebsite: '网站白名单限制' // ❌ 已移除:白名单限制标签 }; return labels[key] || key; } applyTheme() { const theme = this.settings.theme; let actualTheme = theme; if (theme === 'auto') { actualTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } this.ui.classList.toggle('dark', actualTheme === 'dark'); this.currentTheme = actualTheme; } applyUITheme() { // UI主题通过CSS样式和recreateUI应用 } toggleTheme() { const themes = ['light', 'dark', 'auto']; const currentIndex = themes.indexOf(this.settings.theme); const nextTheme = themes[(currentIndex + 1) % themes.length]; this.updateSetting('theme', nextTheme); this.applyTheme(); this.refreshUI(); const themeNames = { light: '浅色', dark: '深色', auto: '自动' }; this.showMessage(`主题已切换为: ${themeNames[nextTheme]}`); } updatePosition() { // 移除当前UI if (this.ui) { this.ui.remove(); } // 重新创建UI setTimeout(() => { this.createUI(); this.bindEvents(); this.applyTheme(); }, 100); } exportData() { const data = this.storage.exportAllData(); const filename = `oauth-helper-backup-${new Date().toISOString().split('T')[0]}.json`; Utils.exportToJSON(data, filename); this.showMessage('📊 数据导出成功'); } async importData(file) { if (!file) return; try { const data = await Utils.importFromJSON(file); if (confirm('确定要导入数据吗?这将覆盖当前设置和记录。')) { if (this.storage.importAllData(data)) { this.settings = this.storage.getSettings(); this.refreshUI(); this.showMessage('📂 数据导入成功,请刷新页面'); } else { this.showMessage('❌ 数据导入失败'); } } } catch (error) { Utils.log('导入数据失败: ' + error.message, 'error'); this.showMessage('❌ 数据格式错误,导入失败'); } } clearHistory() { if (confirm('确定要清空所有历史记录吗?此操作不可恢复。')) { this.storage.clearHistory(); this.refreshUI(); this.showMessage('🗑️ 历史记录已清空'); } } resetSettings() { if (confirm('确定要重置所有设置吗?此操作不可恢复。')) { this.storage.set('settings', CONFIG.defaultSettings); this.settings = CONFIG.defaultSettings; this.currentUITheme = 'minimal-white'; this.recreateUI(); this.showMessage('⚠️ 设置已重置为默认值'); } } showHelp() { const helpContent = ` <div style="max-width: 500px; line-height: 1.6;"> <h3 style="margin-bottom: 16px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.text};">🏆 OAuth助手使用指南</h3> <div style="margin-bottom: 16px;"> <h4 style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.accent};">🎨 主题切换</h4> <p>• <strong>简约白</strong>:极简清爽的白色设计</p> <p>• <strong>紫色渐变</strong>:基于OAuth页面的紫色渐变</p> <p>• <strong>彩虹华丽</strong>:炫酷多彩的动态效果</p> </div> <div style="margin-bottom: 16px;"> <h4 style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.accent};">⚙️ 主要功能</h4> <p>• <strong>历史记录</strong>:保存所有授权操作记录</p> <p>• <strong>条形图统计</strong>:可视化显示使用数据</p> <p>• <strong>数据导入导出</strong>:备份和恢复个人数据</p> </div> <div style="margin-bottom: 16px;"> <h4 style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.accent};">📊 统计图表</h4> <p>• <strong>7天趋势</strong>:显示最近一周的登录(不可用)分布</p> <p>• <strong>小时分布</strong>:显示今日24小时使用情况</p> <p>• <strong>网站排行</strong>:显示最常授权的网站TOP5</p> </div> <div style="margin-bottom: 16px;"> <h4 style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.accent};">🛠️ 使用技巧</h4> <p>• 点击面板外部可快速关闭设置面板</p> <p>• 启用"自动隐藏面板"提升使用体验</p> <p>• 定期导出数据做备份,防止数据丢失</p> <p>• 启用调试模式可查看详细运行日志</p> </div> <div style="text-align: center; margin-top: 20px;"> <button class="oauth-btn primary" onclick="this.parentElement.parentElement.parentElement.remove()">关闭帮助</button> </div> </div> `; this.showModal('帮助信息', helpContent); } showAbout() { const stats = this.storage.getStats(); const aboutContent = ` <div style="max-width: 450px; text-align: center; line-height: 1.6;"> <div style="margin-bottom: 20px;"> <h2 style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.text}; margin: 0;">🏆 OAuth助手</h2> <p style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted}; margin: 8px 0;">专为LINUX DO OAuth设计的极简助手 (无自动点击)</p> </div> <div style="margin-bottom: 20px; padding: 16px; background: ${CONFIG.uiThemes[this.currentUITheme].colors.panelBg}; border-radius: 12px; border: 1px solid ${CONFIG.uiThemes[this.currentUITheme].colors.panelBorder};"> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px; font-size: 13px;"> <div><strong>版本</strong><br>${CONFIG.version}</div> <div><strong>主题</strong><br>${CONFIG.uiThemes[this.currentUITheme].name}</div> <div><strong>总使用</strong><br>${stats.totalLogins}次</div> <div><strong>安装日期</strong><br>${stats.installDate ? new Date(stats.installDate).toLocaleDateString('zh-CN') : '未知'}</div> </div> </div> <div style="margin-bottom: 20px;"> <h4 style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.accent};">✨ 特色功能</h4> <p style="font-size: 13px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted};"> 🎨 三种精美UI主题<br> 📊 多维度条形图统计<br> 📋 完整历史记录<br> 🛠️ 数据导入导出<br> 🔧 丰富自定义选项 </p> </div> <div style="margin-bottom: 20px;"> <h4 style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.accent};">💡 设计理念</h4> <p style="font-size: 13px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted};"> 简洁而不简单,功能丰富而不臃肿<br> 所有功能均集成在设置面板中<br> 无快捷键设计,纯鼠标操作<br> 可视化统计,数据一目了然 </p> </div> <div style="margin-top: 20px;"> <button class="oauth-btn primary" onclick="window.open('${CONFIG.github}', '_blank')">🌟 GitHub</button> <button class="oauth-btn" onclick="this.parentElement.parentElement.parentElement.remove()">关闭</button> </div> </div> `; this.showModal('关于脚本', aboutContent); } showAllHistory() { const history = this.storage.getHistory(); if (history.length === 0) { this.showMessage('📋 暂无历史记录'); return; } const historyContent = ` <div style="max-width: 600px; max-height: 500px; overflow-y: auto;"> <h3 style="margin-bottom: 16px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.text};">📋 全部历史记录 (${history.length}条)</h3> <div style="margin-bottom: 16px;"> <button class="oauth-btn danger" onclick="if(confirm('确定清空所有记录?')) { window.oauthHelper.ui.clearHistory(); this.parentElement.parentElement.parentElement.remove(); }">🗑️ 清空记录</button> <button class="oauth-btn" onclick="window.oauthHelper.ui.exportData()">💾 导出记录</button> </div> <div style="border: 1px solid ${CONFIG.uiThemes[this.currentUITheme].colors.panelBorder}; border-radius: 8px; overflow: hidden;"> ${history.map((record, index) => ` <div style="padding: 12px; border-bottom: 1px solid ${CONFIG.uiThemes[this.currentUITheme].colors.panelBorder}; ${index % 2 === 0 ? `background: ${CONFIG.uiThemes[this.currentUITheme].colors.panelBg};` : ''}"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;"> <strong style="color: ${CONFIG.uiThemes[this.currentUITheme].colors.text};">${record.system || '未知系统'}</strong> <span class="oauth-history-badge ${record.clickType}" style="font-size: 10px; padding: 2px 6px; border-radius: 8px; font-weight: bold;">${record.clickType === 'auto' ? '自动' : '手动'}</span> </div> <div style="font-size: 12px; color: ${CONFIG.uiThemes[this.currentUITheme].colors.textMuted}; line-height: 1.4;"> 🌍 ${record.website || '未知网站'}<br> 👤 ${record.user?.name || '未知'} ${record.user?.level ? `(${record.user.level}级)` : ''}<br> ⚡ ${record.action || '未知操作'}<br> ⏰ ${Utils.formatDate(record.timestamp)} </div> </div> `).join('')} </div> <div style="text-align: center; margin-top: 16px;"> <button class="oauth-btn primary" onclick="this.parentElement.parentElement.remove()">关闭</button> </div> </div> `; this.showModal('历史记录', historyContent); } showModal(title, content) { // 移除已存在的模态框 const existingModal = document.querySelector('.oauth-modal'); if (existingModal) { existingModal.remove(); } const modal = document.createElement('div'); modal.className = 'oauth-modal'; modal.style.cssText = ` position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 99999; backdrop-filter: blur(5px); `; modal.innerHTML = ` <div style=" background: ${CONFIG.uiThemes[this.currentUITheme].colors.panelBg}; border: 2px solid ${CONFIG.uiThemes[this.currentUITheme].colors.panelBorder}; border-radius: 16px; padding: 24px; margin: 20px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); backdrop-filter: blur(10px); max-width: 90vw; max-height: 90vh; overflow-y: auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; "> ${content} </div> `; // 点击背景关闭 modal.addEventListener('click', (e) => { if (e.target === modal) { modal.remove(); } }); document.body.appendChild(modal); } showMessage(message, type = 'info', duration = 3000) { const messageEl = document.createElement('div'); messageEl.style.cssText = ` position: fixed; top: 80px; right: 20px; background: ${type === 'error' ? '#fee2e2' : type === 'warning' ? '#fef3c7' : '#dcfce7'}; color: ${type === 'error' ? '#dc2626' : type === 'warning' ? '#d97706' : '#16a34a'}; padding: 12px 16px; border-radius: 8px; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); z-index: 99999; font-size: 14px; font-weight: 600; border: 1px solid ${type === 'error' ? '#fecaca' : type === 'warning' ? '#fed7aa' : '#bbf7d0'}; backdrop-filter: blur(5px); animation: slideIn 0.3s ease-out; `; messageEl.textContent = message; document.body.appendChild(messageEl); setTimeout(() => { messageEl.style.opacity = '0'; messageEl.style.transform = 'translateX(100%)'; setTimeout(() => messageEl.remove(), 300); }, duration); } refreshUI() { if (this.isVisible) { const content = this.ui.querySelector('.oauth-content'); if (content) { content.innerHTML = this.generateContent(); this.bindContentEvents(); } } } updateSettings(newSettings) { this.settings = { ...this.settings, ...newSettings }; this.refreshUI(); } } // ================== 主入口 ================== class OAuthHelper { constructor() { this.storage = new Storage(); this.settings = this.storage.getSettings(); this.ui = null; this.clickTracker = null; // this.autoClickManager = null; // ❌ 已移除:自动点击管理器实例 this.sessionStartTime = Date.now(); Utils.log('OAuth助手初始化中...'); this.init(); } init() { // 更新会话统计 this.storage.updateStats('sessionsCount'); // 初始化UI this.ui = new UIManager(this.storage); // 初始化点击跟踪 this.clickTracker = new ClickTracker(this.storage, this.settings); // ❌ 已移除:初始化自动点击(如果启用) // if (this.settings.autoClickApprove) { // this.autoClickManager = new AutoClickManager(this.storage, this.settings); // } // 绑定页面卸载事件 this.bindUnloadEvents(); Utils.log('OAuth助手初始化完成'); // 显示欢迎消息(仅第一次安装) this.showWelcomeMessage(); } showWelcomeMessage() { const stats = this.storage.getStats(); const isFirstRun = stats.totalLogins === 0 && stats.sessionsCount <= 1; if (isFirstRun) { setTimeout(() => { this.ui.showMessage('🎉 欢迎使用OAuth助手!点击右上角图标开始使用', 'info', 5000); }, 1000); } } updateSettings() { this.settings = this.storage.getSettings(); // 更新各个组件的设置 if (this.clickTracker) { this.clickTracker.updateSettings(this.settings); } // ❌ 已移除:更新自动点击管理器设置 // if (this.autoClickManager) { // this.autoClickManager.updateSettings(this.settings); // } // ❌ 已移除:如果自动点击设置变化,重新初始化 // if (this.settings.autoClickApprove && !this.autoClickManager) { // this.autoClickManager = new AutoClickManager(this.storage, this.settings); // } else if (!this.settings.autoClickApprove && this.autoClickManager) { // this.autoClickManager = null; // } if (this.ui) { this.ui.updateSettings(this.settings); } Utils.log('设置已更新'); } bindUnloadEvents() { // 页面卸载时记录使用时间 window.addEventListener('beforeunload', () => { const usageTime = Date.now() - this.sessionStartTime; this.storage.updateStats('totalUsageTime', Math.floor(usageTime / 1000)); }); // 页面可见性变化时的处理 document.addEventListener('visibilitychange', () => { if (document.hidden) { // 页面隐藏时 const usageTime = Date.now() - this.sessionStartTime; this.storage.updateStats('totalUsageTime', Math.floor(usageTime / 1000)); } else { // 页面显示时 this.sessionStartTime = Date.now(); } }); } } // ================== 启动脚本 ================== function startScript() { Utils.log('开始启动OAuth助手...'); // 等待DOM加载完成 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { window.oauthHelper = new OAuthHelper(); }); } else { window.oauthHelper = new OAuthHelper(); } } // 立即启动 startScript(); // 注册(不可用)GM菜单命令 if (typeof GM_registerMenuCommand === 'function') { GM_registerMenuCommand('🏆 打开OAuth助手', () => { if (window.oauthHelper && window.oauthHelper.ui) { window.oauthHelper.ui.togglePanel(); } }); GM_registerMenuCommand('📊 导出数据', () => { if (window.oauthHelper && window.oauthHelper.ui) { window.oauthHelper.ui.exportData(); } }); GM_registerMenuCommand('🎨 切换主题', () => { if (window.oauthHelper && window.oauthHelper.ui) { window.oauthHelper.ui.toggleUITheme(); } }); GM_registerMenuCommand('❓ 显示帮助', () => { if (window.oauthHelper && window.oauthHelper.ui) { window.oauthHelper.ui.showHelp(); } }); GM_registerMenuCommand('ℹ️ 关于脚本', () => { if (window.oauthHelper && window.oauthHelper.ui) { window.oauthHelper.ui.showAbout(); } }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址