// ==UserScript== // @name 网页加速器(可以让老爷爷坐飞机的快) // @namespace https://docs.scriptcat.org/ // @version 0.1.1 // @description try to take over the world! // @author You // @match https://*/* // @grant none // @noframes // ==/UserScript== (function() { 'use strict'; // Your code here... })(); // ==UserScript== // @name 网页加速器(可以让老爷爷坐飞机的快) // @namespace https://docs.scriptcat.org/ // @version 0.1.1 // @description try to take over the world! // @author You // @match https://*/* // @grant none // @noframes // ==/UserScript== /* eslint-disable */ (function(global) { 'use strict'; // 配置命名空间,避免冲突 if (global.HyperNav) return; class HyperNav { constructor() { this.name = 'HyperNav Accelerator'; this.version = '2.0.0'; // 核心配置 this.config = { enabled: true, mode: 'balanced', // 'balanced', 'aggressive', 'conservative' prefetchMethod: 'speculative', // 'speculative', 'intent', 'viewport' maxConcurrent: 3, delay: 150, threshold: 0.25, timeout: 3000, maxLinks: 50, cacheSize: 100, learnUserBehavior: true, respectDataSaver: true, respectNetworkType: true }; // 状态管理 this.state = { initialized: false, active: false, linksObserved: 0, linksPrefetched: 0, linksPredicted: 0, cacheHits: 0, userBehavior: {}, sessionStart: Date.now() }; // 缓存系统 this.cache = { urls: new Map(), timestamps: new Map(), sizes: new Map() }; // 忽略规则 this.ignorePatterns = { // URL路径模式 path: [ /\/api\//i, /\/ajax\//i, /\/auth\//i, /\/login\//i, /\/logout\//i, /\/signin\//i, /\/signout\//i, /\/register\//i, /\/checkout\//i, /\/cart\//i, /\/payment\//i, /\/download\//i, /\/upload\//i, /\/export\//i, /\/import\//i, /\/admin\//i, /\/dashboard\//i, /\/profile\//i, /\/settings\//i, /\/delete\//i, /\/edit\//i, /\/create\//i ], // 文件扩展名 extensions: [ /\.(zip|rar|7z|tar|gz|bz2|xz)$/i, /\.(pdf|doc|docx|xls|xlsx|ppt|pptx|odt|ods|odp)$/i, /\.(mp4|avi|mkv|mov|wmv|flv|webm|mpg|mpeg)$/i, /\.(mp3|wav|flac|aac|ogg|wma)$/i, /\.(exe|msi|dmg|pkg|deb|rpm|apk|ipa)$/i, /\.(iso|img|bin|dmg|toast)$/i, /\.(torrent|magnet)$/i ], // 协议 protocols: [ /^javascript:/i, /^mailto:/i, /^tel:/i, /^sms:/i, /^data:/i, /^file:/i, /^blob:/i, /^market:/i ], // 域名 domains: [ /(google-analytics|googletagmanager|doubleclick|facebook\.net)\./i, /(analytics|stats|metrics|tracking)\./i, /(adserver|adsystem|adservice)\./i ], // 查询参数 queries: [ /[?&](logout|signout|delete|remove|clear|reset|unsubscribe)=/i, /[?&](action=(delete|remove|logout|unsubscribe))/i, /[?&](confirm|verify|token|auth)=/i ] }; // 智能预测模型 this.predictor = { patterns: {}, weights: { distance: 0.3, frequency: 0.4, recency: 0.2, similarity: 0.1 }, learn: (link, clicked) => { const url = link.href; if (!this.predictor.patterns[url]) { this.predictor.patterns[url] = { clicks: 0, impressions: 0, lastSeen: 0, firstSeen: Date.now() }; } this.predictor.patterns[url].impressions++; if (clicked) { this.predictor.patterns[url].clicks++; } this.predictor.patterns[url].lastSeen = Date.now(); }, predict: (link) => { const url = link.href; const pattern = this.predictor.patterns[url]; if (!pattern) return 0.1; const age = Date.now() - pattern.firstSeen; const recency = Date.now() - pattern.lastSeen; let score = 0; // 点击率 const ctr = pattern.clicks / pattern.impressions; score += ctr * this.predictor.weights.frequency; // 最近性 const recencyScore = Math.max(0, 1 - (recency / (24 * 60 * 60 * 1000))); score += recencyScore * this.predictor.weights.recency; // 相似性(基于URL路径) const currentPath = window.location.pathname; const linkPath = new URL(url).pathname; const pathSimilarity = this.calculateSimilarity(currentPath, linkPath); score += pathSimilarity * this.predictor.weights.similarity; return Math.min(1, Math.max(0.1, score)); }, cleanup: () => { const now = Date.now(); const oneWeek = 7 * 24 * 60 * 60 * 1000; for (const url in this.predictor.patterns) { if (now - this.predictor.patterns[url].lastSeen > oneWeek) { delete this.predictor.patterns[url]; } } } }; // 网络感知 this.network = { connection: navigator.connection || navigator.mozConnection || navigator.webkitConnection, getType: () => { if (!this.network.connection) return 'unknown'; return this.network.connection.effectiveType || 'unknown'; }, isSlow: () => { if (!this.config.respectNetworkType) return false; const type = this.network.getType(); return type === 'slow-2g' || type === '2g' || type === '3g'; }, isMobile: () => { if (!this.network.connection) return false; return this.network.connection.type === 'cellular' || this.network.connection.type === 'bluetooth' || this.network.connection.type === 'wimax'; }, hasSaveData: () => { if (!this.config.respectDataSaver) return false; if (!this.network.connection) return false; return this.network.connection.saveData === true; }, shouldThrottle: () => { return this.network.isSlow() || this.network.hasSaveData() || this.network.isMobile(); } }; // 初始化 this.init(); } calculateSimilarity(str1, str2) { if (str1 === str2) return 1; if (!str1 || !str2) return 0; const longer = str1.length > str2.length ? str1 : str2; const shorter = str1.length > str2.length ? str2 : str1; if (longer.length === 0) return 1; const editDistance = this.levenshteinDistance(longer, shorter); return (longer.length - editDistance) / parseFloat(longer.length); } levenshteinDistance(a, b) { if (a.length === 0) return b.length; if (b.length === 0) return a.length; const matrix = []; for (let i = 0; i <= b.length; i++) { matrix[i] = [i]; } for (let j = 0; j <= a.length; j++) { matrix[0][j] = j; } for (let i = 1; i <= b.length; i++) { for (let j = 1; j <= a.length; j++) { if (b.charAt(i - 1) === a.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = Math.min( matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1 ); } } } return matrix[b.length][a.length]; } shouldIgnore(url) { try { const urlObj = new URL(url, window.location.origin); // 检查协议 for (const pattern of this.ignorePatterns.protocols) { if (pattern.test(urlObj.protocol)) { this.log('Ignore - Protocol', url); return true; } } // 检查域名 for (const pattern of this.ignorePatterns.domains) { if (pattern.test(urlObj.hostname)) { this.log('Ignore - Domain', url); return true; } } // 检查路径 for (const pattern of this.ignorePatterns.path) { if (pattern.test(urlObj.pathname)) { this.log('Ignore - Path', url); return true; } } // 检查扩展名 for (const pattern of this.ignorePatterns.extensions) { if (pattern.test(urlObj.pathname)) { this.log('Ignore - Extension', url); return true; } } // 检查查询参数 for (const pattern of this.ignorePatterns.queries) { if (pattern.test(urlObj.search)) { this.log('Ignore - Query', url); return true; } } // 检查是否跨域(可配置) if (urlObj.origin !== window.location.origin) { // 可以在这里添加跨域检查逻辑 } return false; } catch (e) { this.log('Error parsing URL', url, e); return true; } } async prefetchUrl(url, priority = 'low') { if (this.shouldIgnore(url)) { return false; } // 检查缓存 if (this.cache.urls.has(url)) { const cached = this.cache.urls.get(url); if (Date.now() - cached.timestamp < 5 * 60 * 1000) { // 5分钟缓存 this.state.cacheHits++; this.log('Cache hit', url); return true; } } // 网络条件检查 if (this.network.shouldThrottle()) { this.log('Throttled due to network conditions', url); return false; } // 并发控制 if (this.state.activePrefetches >= this.config.maxConcurrent) { this.log('Throttled due to concurrency limit', url); return false; } try { this.state.activePrefetches = (this.state.activePrefetches || 0) + 1; // 使用fetch API进行预加载 const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 5000); const response = await fetch(url, { method: 'HEAD', mode: 'cors', credentials: 'include', signal: controller.signal, headers: { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'X-Purpose': 'prefetch' } }); clearTimeout(timeoutId); if (response.ok) { // 检查内容类型 const contentType = response.headers.get('content-type') || ''; if (!contentType.includes('text/html') && !contentType.includes('application/xhtml+xml')) { this.log('Ignore - Not HTML', url, contentType); return false; } // 缓存结果 this.cache.urls.set(url, { timestamp: Date.now(), size: parseInt(response.headers.get('content-length') || '0'), type: contentType }); this.state.linksPrefetched++; this.log('Prefetch success', url); // 触发成功事件 this.triggerEvent('prefetch:success', { url, priority }); return true; } else { this.log('Prefetch failed', url, response.status); this.triggerEvent('prefetch:failed', { url, status: response.status }); return false; } } catch (error) { this.log('Prefetch error', url, error); this.triggerEvent('prefetch:error', { url, error }); return false; } finally { this.state.activePrefetches--; } } async prefetchLink(link) { if (!link || !link.href) return; const url = link.href; // 学习用户行为 if (this.config.learnUserBehavior) { this.predictor.learn(link, false); } // 计算预测分数 const score = this.config.learnUserBehavior ? this.predictor.predict(link) : 0.5; // 根据配置模式调整阈值 let threshold = 0.3; switch (this.config.mode) { case 'aggressive': threshold = 0.1; break; case 'conservative': threshold = 0.5; break; } if (score >= threshold) { await this.prefetchUrl(url, 'auto'); } } observeLinks() { if (!this.config.enabled || !this.state.initialized) { return; } // 创建观察器 this.observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const link = entry.target; this.observeLink(link); } }); }, { root: null, rootMargin: '50px', threshold: this.config.threshold }); // 观察所有链接 const links = document.querySelectorAll('a[href]:not([href^="#"])'); links.forEach(link => { this.observer.observe(link); }); this.state.linksObserved = links.length; // 添加鼠标悬停预测 if (this.config.prefetchMethod === 'intent') { this.addHoverListeners(links); } } observeLink(link) { if (link._hypernavObserved) return; link._hypernavObserved = true; // 添加点击监听 link.addEventListener('click', (e) => { if (this.config.learnUserBehavior) { this.predictor.learn(link, true); } // 记录点击事件 this.triggerEvent('link:clicked', { url: link.href, timestamp: Date.now() }); }, { once: true }); // 预加载链接 this.schedulePrefetch(link); } schedulePrefetch(link) { if (this.prefetchScheduled) return; this.prefetchScheduled = true; // 使用requestIdleCallback进行智能调度 requestIdleCallback(() => { this.prefetchLink(link); this.prefetchScheduled = false; }, { timeout: this.config.timeout }); } addHoverListeners(links) { let hoverTimer = null; links.forEach(link => { link.addEventListener('mouseenter', () => { clearTimeout(hoverTimer); hoverTimer = setTimeout(() => { this.prefetchLink(link); }, 100); }); link.addEventListener('mouseleave', () => { clearTimeout(hoverTimer); }); link.addEventListener('touchstart', () => { clearTimeout(hoverTimer); hoverTimer = setTimeout(() => { this.prefetchLink(link); }, 300); }, { passive: true }); }); } triggerEvent(eventName, data) { const event = new CustomEvent(`hypernav:${eventName}`, { detail: data }); window.dispatchEvent(event); } log(...args) { if (this.config.debug) { console.log('[HyperNav]', ...args); } } getStats() { const now = Date.now(); const sessionDuration = (now - this.state.sessionStart) / 1000; return { enabled: this.config.enabled, mode: this.config.mode, prefetchMethod: this.config.prefetchMethod, linksObserved: this.state.linksObserved, linksPrefetched: this.state.linksPrefetched, cacheHits: this.state.cacheHits, cacheSize: this.cache.urls.size, networkType: this.network.getType(), networkSlow: this.network.isSlow(), hasSaveData: this.network.hasSaveData(), sessionDuration: `${Math.round(sessionDuration)}s`, predictionPatterns: Object.keys(this.predictor.patterns).length }; } updateConfig(newConfig) { Object.assign(this.config, newConfig); this.saveConfig(); if (newConfig.enabled === false && this.observer) { this.observer.disconnect(); this.state.active = false; } else if (newConfig.enabled === true && !this.state.active) { this.observeLinks(); } } saveConfig() { try { localStorage.setItem('hypernav-config', JSON.stringify(this.config)); } catch (e) { this.log('Failed to save config', e); } } loadConfig() { try { const saved = localStorage.getItem('hypernav-config'); if (saved) { Object.assign(this.config, JSON.parse(saved)); } } catch (e) { this.log('Failed to load config', e); } } init() { if (this.state.initialized) return; this.loadConfig(); // 等待页面加载完成 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => this.start()); } else { this.start(); } this.state.initialized = true; } start() { if (!this.config.enabled) { this.log('HyperNav is disabled'); return; } if (this.network.hasSaveData()) { this.log('Save-Data enabled, throttling'); this.config.maxConcurrent = 1; } if (this.network.isSlow()) { this.log('Slow network detected, throttling'); this.config.maxConcurrent = 1; this.config.delay = 500; } this.observeLinks(); this.state.active = true; this.log('HyperNav started', this.config); // 定期清理 setInterval(() => { this.predictor.cleanup(); // 清理旧缓存 const now = Date.now(); for (const [url, data] of this.cache.urls.entries()) { if (now - data.timestamp > 30 * 60 * 1000) { // 30分钟 this.cache.urls.delete(url); } } }, 5 * 60 * 1000); // 每5分钟清理一次 } destroy() { if (this.observer) { this.observer.disconnect(); } this.state.active = false; this.state.initialized = false; this.log('HyperNav destroyed'); } } // 初始化 global.HyperNav = new HyperNav(); // 导出API global.hypernav = { enable: () => global.HyperNav.updateConfig({ enabled: true }), disable: () => global.HyperNav.updateConfig({ enabled: false }), getStats: () => global.HyperNav.getStats(), config: global.HyperNav.config, prefetch: (url) => global.HyperNav.prefetchUrl(url, 'manual') }; // 开发工具集成 if (typeof GM_registerMenuCommand === 'function') { GM_registerMenuCommand('📊 HyperNav Stats', () => { const stats = global.HyperNav.getStats(); GM_notification({ text: JSON.stringify(stats, null, 2), title: 'HyperNav Statistics', timeout: 5000 }); }); GM_registerMenuCommand('⚡ Toggle HyperNav', () => { global.HyperNav.updateConfig({ enabled: !global.HyperNav.config.enabled }); GM_notification({ text: `HyperNav ${global.HyperNav.config.enabled ? 'Enabled' : 'Disabled'}`, title: 'HyperNav', timeout: 2000 }); }); } })(typeof window !== 'undefined' ? window : this);