// ==UserScript== // @name 威软全能网盘增强助手 // @namespace Weiruan-Pan-Helper // @version 3.2.0 // @description 支持夸克、百度、阿里云盘。搭载【时空网络劫持 + DOM 黑洞陷阱】终极双擎,强行拦截底层真实下载直链。 // @author 威软科技 // @license MIT // @icon https://pan.quark.cn/favicon.ico // @match *://pan.quark.cn/* // @match *://pan.baidu.com/* // @match *://yun.baidu.com/* // @match *://*.aliyundrive.com/* // @match *://*.alipan.com/* // @grant GM_xmlhttpRequest // @grant GM_setClipboard // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant unsafeWindow // @run-at document-start // @connect drive.quark.cn // @connect pan.baidu.com // @connect api.aliyundrive.com // @homepage https://github.com/weiruankeji2025/weiruan-quark // @downloadURL none // ==/UserScript== (function() { 'use strict'; // ==================== 全局配置 ==================== const CONFIG = { VERSION: "3.2.0", DEBUG: true, HISTORY_MAX: 100, FOLDER_MAX_DEPTH: 5, FOLDER_MAX_FILES: 500, UA_QUARK: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160", UA_BAIDU: "netdisk;7.0.3.2;PC;PC-Windows;10.0.19045", UA_ALIYUN: "AliApp(Yundrive/4.0.0)", }; const State = { lang: GM_getValue('weiruan_lang', 'zh'), theme: GM_getValue('weiruan_theme', 'auto'), history: GM_getValue('weiruan_history', []), capturedLinks: new Map(), // 存储网络劫持到的真实直链 getLang() { return { title: '威软全能网盘助手', downloadHelper: '下载助手', processing: '处理中...', success: '解析成功', error: '错误', noFiles: '请先勾选需要下载的文件', networkError: '网络请求失败,请检查网络', copied: '已复制', copyAll: '复制全部', copyAria2: '导出 aria2', copyCurl: '导出 cURL', totalSize: '总大小', history: '历史记录', clearHistory: '清空历史', settings: '设置', darkMode: '深色模式', language: '语言', all: '全部', files: '个文件', noHistory: '暂无下载历史', auto: '跟随系统', light: '浅色', dark: '深色' }; }, setLang(lang) { this.lang = lang; GM_setValue('weiruan_lang', lang); }, setTheme(theme) { this.theme = theme; GM_setValue('weiruan_theme', theme); if(document.body) UI.applyTheme(); }, isDark() { return this.theme === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : this.theme === 'dark'; }, addHistory(files) { const newHistory = files.map(f => ({ name: f.file_name, size: f.size, time: Date.now() })); this.history = [...newHistory, ...this.history].slice(0, CONFIG.HISTORY_MAX); GM_setValue('weiruan_history', this.history); }, clearHistory() { this.history = []; GM_setValue('weiruan_history', []); } }; const Utils = { log: (...args) => { if (CONFIG.DEBUG) console.log('[威软全能助手]', ...args); }, formatSize: (bytes) => { if (!bytes) return '0 B'; const k = 1024, i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + ['B', 'KB', 'MB', 'GB', 'TB'][i]; }, getFileType: (fn) => { if(!fn) return 'other'; const ext = fn.split('.').pop().toLowerCase(); const t = { video: ['mp4', 'mkv', 'avi', 'mov', 'wmv', 'flv', 'rmvb', 'm4v'], audio: ['mp3', 'wav', 'flac', 'aac', 'ogg', 'wma', 'm4a'], image: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico'], document: ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md'], archive: ['zip', 'rar', '7z', 'tar', 'gz', 'bz2'] }; for (const [type, exts] of Object.entries(t)) if (exts.includes(ext)) return type; return 'other'; }, getFileIcon: (fn) => ({ video: '🎬', audio: '🎵', image: '🖼️', document: '📄', archive: '📦', other: '📁' }[Utils.getFileType(fn)] || '📁'), generateBatchLinks: (files) => files.map(f => f.download_url).join('\n'), generateAria2Commands: (files, ua) => files.map(f => `${f.folderPath ? `mkdir -p "${f.folderPath}" && ` : ''}aria2c -c -x 16 -s 16 "${f.download_url}" -o "${f.fullPath || f.file_name}" -U "${ua}" --header="Cookie: ${document.cookie}"`).join('\n\n'), generateCurlCommands: (files, ua) => files.map(f => `${f.folderPath ? `mkdir -p "${f.folderPath}" && ` : ''}curl -L -C - "${f.download_url}" -o "${f.fullPath || f.file_name}" -A "${ua}" -b "${document.cookie}"`).join('\n\n'), toast: (msg, type = 'success') => { if (!document.body) return; document.querySelector('.weiruan-toast')?.remove(); const div = document.createElement('div'); div.className = 'weiruan-toast'; div.innerText = msg; const colors = { success: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', error: 'linear-gradient(135deg, #ff6b6b 0%, #ee5a5a 100%)', info: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)', warning: 'linear-gradient(135deg, #f6d365 0%, #fda085 100%)' }; div.style.cssText = `position: fixed; top: 80px; left: 50%; transform: translateX(-50%); background: ${colors[type] || colors.success}; color: ${type==='warning'?'#333':'white'}; padding: 12px 24px; border-radius: 8px; z-index: 2147483649; font-size: 14px; box-shadow: 0 4px 20px rgba(0,0,0,0.25); animation: weiruan-toast-in 0.3s ease-out; font-family: -apple-system, BlinkMacSystemFont, sans-serif; white-space: pre-line; line-height: 1.5;`; document.body.appendChild(div); setTimeout(() => { div.style.animation = 'weiruan-toast-out 0.3s ease-out forwards'; setTimeout(() => div.remove(), 300); }, 4500); } }; // ==================== 🕸️ 黑洞引擎 (终极拦截) ==================== const SinkholeEngine = { init() { const win = unsafeWindow || window; if (win._weiruan_hooked) return; win._weiruan_hooked = true; Utils.log('🕸️ 威软黑洞引擎已启动,静候网盘触发下载...'); // 1. API 接口拦截 (防漏网之鱼) const origFetch = win.fetch; win.fetch = async function(...args) { const reqUrl = typeof args[0] === 'string' ? args[0] : (args[0]?.url || ''); const response = await origFetch.apply(this, args); if (reqUrl.includes('get_download_url') || reqUrl.includes('downloadUrl') || reqUrl.includes('v1/file/download')) { try { const clone = response.clone(); clone.json().then(data => { if (data && data.url) { let fid = 'unknown_fid_' + Date.now(); if (args[1] && args[1].body && typeof args[1].body === 'string') { const body = JSON.parse(args[1].body); fid = body.file_id || body.fileId || fid; } Utils.log('🎯 [API黑洞] 成功捕获直链:', data.url); State.capturedLinks.set(fid, data.url); if (DriveManager.currentAdapter && document.body) DriveManager.runExtraction(true); } }).catch(()=>{}); } catch(e) {} } return response; }; const origXhrSend = win.XMLHttpRequest.prototype.send; win.XMLHttpRequest.prototype.send = function(body) { this._weiruanBody = body; this.addEventListener('load', function() { if (this.responseURL && (this.responseURL.includes('get_download_url') || this.responseURL.includes('downloadUrl'))) { try { const data = JSON.parse(this.responseText); if (data && data.url) { let fid = 'unknown_fid_' + Date.now(); Utils.log('🎯 [XHR黑洞] 成功捕获直链:', data.url); State.capturedLinks.set(fid, data.url); if (DriveManager.currentAdapter && document.body) DriveManager.runExtraction(true); } } catch(e) {} } }); return origXhrSend.call(this, body); }; // 2. 🚀 DOM 动作拦截 (专治各种 ServiceWorker 绕过和隐藏下载) // 劫持 标签的点击事件 const origAnchorClick = HTMLAnchorElement.prototype.click; HTMLAnchorElement.prototype.click = function() { const url = this.href; // 判断是否是阿里云盘 CDN 或其它常见的下载链接特征 if (url && (url.includes('alicloudccp.com') || url.includes('aliyundrive.net') || url.includes('x-oss-') || url.includes('download'))) { Utils.log('🚨 [DOM黑洞] 拦截到 标签原生下载行为!URL:', url); // 获取当前页面上选中的文件名进行粗略匹配 let matchedName = "已劫持的阿里直链文件"; const selected = DriveManager.currentAdapter ? DriveManager.currentAdapter.getSelectedFiles() : []; if (selected.length === 1) { matchedName = selected[0].name; } else if (this.download) { matchedName = this.download; } // 存入劫持池并阻断原始下载,强制弹窗! const tempFid = 'hijack_' + Date.now(); State.capturedLinks.set(tempFid, url); // 手动将此文件塞入提取队列 DriveManager.forcedExtraction([{ fid: tempFid, name: matchedName, isDir: false, size: 0, download_url: url }]); return; // ⛔ 阻断原生下载! } return origAnchorClick.apply(this, arguments); }; // 劫持 window.open const origWindowOpen = win.open; win.open = function(url, target, features) { if (typeof url === 'string' && (url.includes('alicloudccp.com') || url.includes('aliyundrive.net') || url.includes('x-oss-'))) { Utils.log('🚨 [DOM黑洞] 拦截到 window.open 下载行为!URL:', url); const tempFid = 'hijack_' + Date.now(); State.capturedLinks.set(tempFid, url); DriveManager.forcedExtraction([{ fid: tempFid, name: "已劫持的新窗口下载任务", isDir: false, size: 0, download_url: url }]); return null; // ⛔ 阻断弹窗! } return origWindowOpen.call(win, url, target, features); }; } }; SinkholeEngine.init(); // ==================== 适配器 ==================== const Adapters = { quark: { /* 省略细节,保持与之前相同 */ name: "夸克网盘", matches: ['pan.quark.cn'], ua: CONFIG.UA_QUARK, getSelectedFiles: function() { return []; }, processFiles: async function(f) { return f; } }, baidu: { /* 省略细节,保持与之前相同 */ name: "百度网盘", matches: ['pan.baidu.com', 'yun.baidu.com'], ua: CONFIG.UA_BAIDU, getSelectedFiles: function() { return []; }, processFiles: async function(f) { return f; } }, // ---------------- 🚀 阿里云盘 (终极匹配提取) ---------------- aliyun: { name: "阿里云盘", matches: ['aliyundrive.com', 'alipan.com'], ua: CONFIG.UA_ALIYUN, isSharePage: function() { return location.pathname.includes('/s/') || location.pathname.includes('/share/'); }, getSelectedFiles: function() { const files = new Map(); const fileMemoryMap = new Map(); const findFilesInFiber = (obj, visited = new Set(), depth = 0) => { if (!obj || typeof obj !== 'object' || depth > 15) return; if (visited.has(obj)) return; visited.add(obj); if (obj.file_id && obj.name && typeof obj.file_id === 'string' && obj.file_id.length > 5) { fileMemoryMap.set(obj.name.trim(), obj); } for (let key in obj) { if (key === 'return' || key === 'child' || key === 'sibling' || key.startsWith('__') || obj[key] instanceof Node) continue; try { findFilesInFiber(obj[key], visited, depth + 1); } catch(e) {} } }; document.querySelectorAll('#root, #app, [class*="layout"], [class*="container"], [class*="body"]').forEach(el => { const key = Object.keys(el).find(k => k.startsWith('__reactFiber$') || k.startsWith('__reactInternalInstance$')); if (key) findFilesInFiber(el[key]); }); const checkedElements = document.querySelectorAll('input[type="checkbox"]:checked, [aria-checked="true"], [class*="checked"], [class*="Checked"], [class*="selected"], [class*="Selected"], .icon-checked, [class*="icon-checkbox-checked"]'); const cleanStr = (str) => (str || '').replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, ''); checkedElements.forEach(el => { if (el.closest('thead') || el.closest('[class*="header"]')) return; let matched = false; let currentEl = el; for (let i = 0; i < 5; i++) { if (!currentEl) break; const titleVal = currentEl.getAttribute('title') || currentEl.getAttribute('data-title') || currentEl.getAttribute('aria-label'); if (titleVal && fileMemoryMap.has(titleVal.trim())) { const memObj = fileMemoryMap.get(titleVal.trim()); files.set(memObj.file_id, { fid: memObj.file_id, drive_id: memObj.drive_id, name: memObj.name, isDir: memObj.type === 'folder', size: memObj.size || 0 }); matched = true; break; } currentEl = currentEl.parentElement; } if (!matched) { currentEl = el; for (let i = 0; i < 10; i++) { if (!currentEl) break; const rawText = currentEl.textContent || ''; const cleanRowText = cleanStr(rawText); if (cleanRowText.length > 1) { const memEntries = Array.from(fileMemoryMap.entries()).sort((a,b) => b[0].length - a[0].length); for (let [memName, memObj] of memEntries) { const cleanMemName = cleanStr(memName); if (cleanMemName.length === 0) continue; const fingerprint = cleanMemName.substring(0, Math.min(cleanMemName.length, 5)); if (cleanRowText.includes(fingerprint)) { files.set(memObj.file_id, { fid: memObj.file_id, drive_id: memObj.drive_id, name: memObj.name, isDir: memObj.type === 'folder', size: memObj.size || 0 }); matched = true; break; } } } if (matched) break; currentEl = currentEl.parentElement; } } }); return Array.from(files.values()); }, processFiles: async function(files, updateUIBtn, isAuto) { if (this.isSharePage()) { if (!isAuto) Utils.toast('阿里限制:分享页无法提取,请先【保存】到个人网盘!', 'error'); return null; } let readyFiles = []; let missingCount = 0; files.forEach(f => { let url = State.capturedLinks.get(f.fid); if (url) { readyFiles.push({ ...f, file_name: f.name, download_url: url, folderPath: '', fullPath: f.name }); } else { missingCount++; } }); if (missingCount > 0) { if (!isAuto) { Utils.toast(`🛡️ 我们已被阿里 X-Signature 防盗链系统拦截!\n\n请直接点击网页本身的【下载】按钮,\n助手会在底层强制拦截它的下载指令!`, 'warning'); return null; } if (readyFiles.length === 0) return null; } return readyFiles; } } }; const DriveManager = { currentAdapter: null, init() { const host = location.host; for (const key in Adapters) { if (Adapters[key].matches.some(m => host.includes(m))) { this.currentAdapter = Adapters[key]; break; } } }, // 正常点击触发 async runExtraction(isAuto = false) { if (!this.currentAdapter) return; const L = State.getLang(); const btn = document.getElementById('weiruan-btn'); const updateUIBtn = (html) => { if (btn && !isAuto) btn.innerHTML = html; }; try { if (btn && !isAuto) { btn.innerHTML = ` ${L.processing}`; btn.disabled = true; } const initialFiles = this.currentAdapter.getSelectedFiles(); if (!initialFiles || initialFiles.length === 0) { if (!isAuto) Utils.toast(L.noFiles, 'error'); return; } const resultData = await this.currentAdapter.processFiles(initialFiles, updateUIBtn, isAuto); if (resultData && resultData.length > 0) { State.addHistory(resultData); UI.showResultWindow(resultData); } } catch (e) { if (!isAuto) Utils.toast(L.networkError, 'error'); } finally { if (btn && !isAuto) { btn.innerHTML = ` ${L.downloadHelper}`; btn.disabled = false; } } }, // 暴力拦截触发 forcedExtraction(filesData) { Utils.toast('🎉 黑洞引擎拦截成功!强制提取满速直链!', 'success'); State.addHistory(filesData); UI.showResultWindow(filesData); } }; // ==================== 界面 UI ==================== const UI = { injectStyles: () => { GM_addStyle(` @keyframes weiruan-toast-in { from { opacity: 0; transform: translate(-50%, -20px); } to { opacity: 1; transform: translate(-50%, 0); } } @keyframes weiruan-toast-out { from { opacity: 1; transform: translate(-50%, 0); } to { opacity: 0; transform: translate(-50%, -20px); } } @keyframes weiruan-spin { to { transform: rotate(360deg); } } @keyframes weiruan-slide-in { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } } .weiruan-spinner { display: inline-block; width: 14px; height: 14px; border: 2px solid rgba(255,255,255,0.3); border-top-color: white; border-radius: 50%; animation: weiruan-spin 0.8s linear infinite; margin-right: 6px; vertical-align: middle; } .weiruan-btn { position: fixed; top: 50%; left: 0; transform: translateY(-50%); z-index: 2147483647; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; font-size: 14px; font-weight: 600; padding: 14px 18px; border: none; border-radius: 0 25px 25px 0; cursor: pointer; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); transition: all 0.3s ease; display: flex; align-items: center; gap: 6px; } .weiruan-btn:hover { padding-left: 22px; box-shadow: 0 6px 25px rgba(102, 126, 234, 0.5); } .weiruan-btn:disabled { opacity: 0.7; cursor: not-allowed; } .weiruan-icon { font-size: 16px; } .weiruan-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.6); z-index: 2147483648; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(5px); } .weiruan-modal { background: var(--weiruan-bg, #ffffff); width: 720px; max-width: 92%; max-height: 85vh; border-radius: 16px; box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3); display: flex; flex-direction: column; overflow: hidden; animation: weiruan-slide-in 0.3s ease-out; font-family: -apple-system, BlinkMacSystemFont, sans-serif; } .weiruan-tab-content { display: none; flex-direction: column; min-height: 0; flex: 1; overflow: hidden; } .weiruan-tab-content.active { display: flex; } .weiruan-modal-header { padding: 18px 24px; border-bottom: 1px solid var(--weiruan-border, #eee); display: flex; justify-content: space-between; align-items: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .weiruan-modal-title { margin: 0; font-size: 18px; font-weight: 600; display: flex; align-items: center; gap: 8px; } .weiruan-modal-close { cursor: pointer; font-size: 28px; line-height: 1; opacity: 0.8; transition: opacity 0.2s; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(255,255,255,0.1); } .weiruan-modal-close:hover { opacity: 1; background: rgba(255,255,255,0.2); } .weiruan-toolbar { padding: 12px 24px; background: var(--weiruan-toolbar-bg, #f8f9ff); border-bottom: 1px solid var(--weiruan-border, #eee); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; } .weiruan-toolbar-info { font-size: 13px; color: var(--weiruan-text-secondary, #666); } .weiruan-btn-group { display: flex; gap: 6px; } .weiruan-action-btn { padding: 8px 16px; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s; display: flex; align-items: center; gap: 4px; } .weiruan-action-btn.primary { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .weiruan-action-btn.success { background: linear-gradient(135deg, #56ab2f 0%, #a8e063 100%); color: white; } .weiruan-modal-body { padding: 16px 24px; overflow-y: auto; flex: 1; min-height: 0; max-height: 400px; background: var(--weiruan-bg, #ffffff); } .weiruan-file-item { background: var(--weiruan-item-bg, #f9f9f9); padding: 14px 16px; margin-bottom: 10px; border-radius: 10px; border-left: 4px solid #667eea; display: flex; justify-content: space-between; align-items: center; transition: all 0.2s; } .weiruan-file-info { overflow: hidden; flex: 1; margin-right: 12px; } .weiruan-file-name { font-weight: 600; color: var(--weiruan-text, #333); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 6px; font-size: 14px; } .weiruan-file-actions { display: flex; gap: 6px; flex-shrink: 0; } .weiruan-file-btn { padding: 6px 12px; border: none; border-radius: 5px; cursor: pointer; font-size: 12px; font-weight: 500; background: #333; color: white; transition: transform 0.2s; } .weiruan-file-btn:hover { transform: scale(1.05); } .weiruan-file-btn.idm { background: linear-gradient(135deg, #56ab2f 0%, #a8e063 100%); } .weiruan-file-btn.aria2 { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); } .weiruan-footer { padding: 12px 24px; border-top: 1px solid var(--weiruan-border, #eee); background: var(--weiruan-bg, #ffffff); text-align: center; font-size: 12px; color: var(--weiruan-text-secondary, #999); } .weiruan-dark { --weiruan-bg: #1a1a2e; --weiruan-text: #e0e0e0; --weiruan-text-secondary: #888; --weiruan-border: #333; --weiruan-item-bg: #252540; --weiruan-toolbar-bg: #1e1e35; } `); }, applyTheme: () => { const modal = document.getElementById('weiruan-modal'); if (modal) State.isDark() ? modal.classList.add('weiruan-dark') : modal.classList.remove('weiruan-dark'); }, createFloatButton: () => { if (document.getElementById('weiruan-btn')) return; const L = State.getLang(); const btn = document.createElement('button'); btn.id = 'weiruan-btn'; btn.className = 'weiruan-btn'; btn.innerHTML = ` ${L.downloadHelper}`; btn.onclick = () => DriveManager.runExtraction(false); document.body.appendChild(btn); }, showResultWindow: (data) => { const L = State.getLang(); document.getElementById('weiruan-modal')?.remove(); const totalSize = data.reduce((sum, f) => sum + f.size, 0); const modal = document.createElement('div'); modal.id = 'weiruan-modal'; modal.className = `weiruan-modal-overlay ${State.isDark() ? 'weiruan-dark' : ''}`; const activeUA = DriveManager.currentAdapter?.ua || CONFIG.UA_QUARK; const batchLinks = Utils.generateBatchLinks(data); const aria2Commands = Utils.generateAria2Commands(data, activeUA); const curlCommands = Utils.generateCurlCommands(data, activeUA); const fileListHTML = data.map((f, index) => `
${Utils.getFileIcon(f.file_name)}${f.file_name}
⬇️ IDM / 浏览器
`).join(''); modal.innerHTML = `

🎉提取成功!(共 ${data.length} 个)

×
${fileListHTML}
`; document.body.appendChild(modal); document.getElementById('weiruan-modal-close').addEventListener('click', () => modal.remove()); modal.addEventListener('click', (e) => { if (e.target === modal) modal.remove(); }); document.getElementById('weiruan-copy-all-btn').addEventListener('click', () => { GM_setClipboard(batchLinks); Utils.toast('✅ 全部链接已复制'); }); document.getElementById('weiruan-copy-aria2-btn').addEventListener('click', () => { GM_setClipboard(aria2Commands); Utils.toast('✅ aria2 命令已复制'); }); modal.querySelectorAll('.weiruan-copy-curl').forEach(btn => { btn.addEventListener('click', (e) => { const f = data[parseInt(e.target.getAttribute('data-index'))]; GM_setClipboard(`curl -L -C - "${f.download_url}" -o "${f.file_name}" -A "${activeUA}" -b "${document.cookie}"`); Utils.toast('✅ cURL 命令已复制'); }); }); modal.querySelectorAll('.weiruan-copy-aria2').forEach(btn => { btn.addEventListener('click', (e) => { const f = data[parseInt(e.target.getAttribute('data-index'))]; GM_setClipboard(`aria2c -c -x 16 -s 16 "${f.download_url}" -o "${f.file_name}" -U "${activeUA}" --header="Cookie: ${document.cookie}"`); Utils.toast('✅ aria2 命令已复制'); }); }); } }; const App = { init: () => { DriveManager.init(); if (!DriveManager.currentAdapter) return; UI.injectStyles(); UI.createFloatButton(); UI.applyTheme(); } }; function domReady(fn) { if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(fn, 1); } else { document.addEventListener('DOMContentLoaded', fn); } } domReady(() => { App.init(); console.log(`[威软全能助手] v${CONFIG.VERSION} 已在 DOM 挂载后启动`); let lastUrl = location.href; new MutationObserver(() => { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(App.init, 1000); } }).observe(document, { subtree: true, childList: true }); }); })();