// ==UserScript== // @name 无线网络优化脚本 (WiFi/移动网络) // @namespace workbuddy.wireless // @version 1.0.0 // @description 无线网络场景网页优化:网络感知、图片/视频降级加载、流量节省、弱网资源拦截、断线检测、WebSocket保活、动画降级 // @author WorkBuddy // @license MIT // @match *://*/* // @exclude *://*.mozilla.org/* // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @run-at document-start // @noframes // ==/UserScript== /** * ================================================================== * 无线网络优化脚本 (Wireless Network Optimizer) * ================================================================== * 适用场景: WiFi · 移动热点 · 4G/5G · 弱网环境 * * 功能总览: * [1] 网络感知 —— 读取 Network Information API,判断网络质量 * [2] 图片优化 —— 弱网下降级/懒加载图片,省流量 * [3] 视频优化 —— 自动降低码率档位、关闭自动播放 * [4] 资源拦截 —— 弱网下阻止重型脚本/字体/追踪器加载 * [5] 流量节省 —— 提示网站启用 Save-Data、阻止预加载 * [6] 断线检测 —— 在线/离线状态浮窗提示 + 自动重连 * [7] WebSocket —— 心跳保活,弱网防掉线 * [8] 动画降级 —— 关闭重型 CSS 动画,省电省流量 * [9] 状态面板 —— 实时显示网络质量与优化统计 * ================================================================== */ (function () { 'use strict'; /* ============================================================ * 0. 网络状态感知 * ============================================================ */ const conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection || null; // 网络质量分级: 0=未知, 1=极差(2G), 2=较差(3G), 3=一般(4G), 4=良好(WiFi/宽带) function getNetworkLevel() { if (!conn) return 3; // 无法获取时按一般处理 if (conn.saveData) return 1; // 系统省流量模式 const type = (conn.effectiveType || '').toLowerCase(); if (type.includes('2g')) return 1; if (type.includes('3g')) return 2; if (type.includes('4g')) return 3; if (type.includes('5g')) return 4; if (conn.type === 'wifi' || conn.type === 'ethernet') return 4; return 3; } const NETWORK_LEVEL = getNetworkLevel(); const IS_SLOW_NETWORK = NETWORK_LEVEL <= 2; // 3G 及以下视为弱网 const IS_MOBILE = /Android|iPhone|iPad|iPod|Windows Phone/i.test(navigator.userAgent); console.log(`[无线优化] 网络等级: ${NETWORK_LEVEL}/4 (${conn ? conn.effectiveType : '未知'}), 弱网: ${IS_SLOW_NETWORK}`); /* ============================================================ * 1. 图片优化 * ============================================================ */ // 弱网下将图片源降级为低质量版本(常见 CDN 参数) function downgradeImageSrc(src) { if (!src) return src; // 已有质量参数则跳过 if (/[?&](w|width|q|quality|size)=/.test(src)) return src; // 常见图床参数格式(不同站不同,这里处理通用格式) let newSrc = src; if (src.includes('?')) { newSrc += '&q=50&w=800'; } else { // 部分站点支持 /!q50 或 /format/ 等路径参数,这里不强行处理 newSrc = src; } return newSrc; } function optimizeImages() { const setupImg = (img) => { if (img.dataset.wbOpt) return; img.dataset.wbOpt = '1'; // 1) 强制懒加载(所有未加载的图片) if (!img.loading) img.loading = 'lazy'; img.decoding = 'async'; // 2) 弱网下降级图片质量 if (IS_SLOW_NETWORK) { // 不处理 1x1 像素等特殊图 if (img.width < 10 && img.height < 10) return; // 拦截高分辨率源 const src = img.currentSrc || img.src; if (src && !src.startsWith('data:')) { const orig = src; const low = downgradeImageSrc(src); if (low !== orig) { img.dataset.wbOrig = orig; // 保存原图(用户可手动恢复) // 用 Image 预试加载低清版,成功后再切换 const test = new Image(); test.onload = () => { if (test.naturalWidth >= 100) { // 防止加载到坏图 img.src = low; } }; test.onerror = () => { /* 保留原图 */ }; test.src = low; } } } // 3) 阻止低优先级图片在弱网下自动加载(设置 fetchpriority) try { img.fetchPriority = IS_SLOW_NETWORK ? 'low' : 'auto'; } catch (e) {} }; document.querySelectorAll('img').forEach(setupImg); // 动态图片同样处理 new MutationObserver(() => { document.querySelectorAll('img:not([data-wb-opt])').forEach(setupImg); }).observe(document.documentElement, { childList: true, subtree: true }); } /* ============================================================ * 2. 视频优化 * ============================================================ */ function optimizeVideos() { const setupVideo = (video) => { if (video.dataset.wbOpt) return; video.dataset.wbOpt = '1'; // 1) 弱网下暂停自动播放 if (IS_SLOW_NETWORK) { video.autoplay = false; // 拦截自动播放尝试 video.addEventListener('play', (e) => { if (!video.dataset.wbUserPlay && video.currentTime < 0.5) { // 页面自动触发的播放(非用户操作)在弱网下暂停 // 通过 userActivation 判断是否为用户操作 if (!e.isTrusted) { video.pause(); } } }, true); } // 2) 预加载策略:弱网只加载元数据 video.preload = IS_SLOW_NETWORK ? 'metadata' : 'auto'; // 3) 弱网下自动选择低码率(部分播放器尊重 data-quality 或自定义事件) if (IS_SLOW_NETWORK) { try { // 尝试触发播放器切换清晰度(不同播放器支持不同) const player = video.closest('[class*="player"], [class*="video"]'); if (player) { // 部分站点监听 qualitychange 事件 player.dispatchEvent(new CustomEvent('qualitychange', { detail: { quality: 'auto' } })); } } catch (e) {} } // 4) 记录用户主动播放(供弱网判断用) video.addEventListener('play', () => { video.dataset.wbUserPlay = '1'; }, { once: false }); }; document.querySelectorAll('video').forEach(setupVideo); new MutationObserver(() => { document.querySelectorAll('video:not([data-wb-opt])').forEach(setupVideo); }).observe(document.documentElement, { childList: true, subtree: true }); } /* ============================================================ * 3. 资源拦截(弱网模式) * ============================================================ */ // 弱网下拦截的重型资源 const HEAVY_SCRIPT_PATTERNS = [ /(ad|ads|advert|doubleclick|googlesyndication)/i, // 广告脚本 /(analytics|tracker|tracking|beacon|pixel)/i, // 统计追踪 /(hotjar|clarity|matomo|mixpanel|segment|amplitude)/i, // 第三方分析 /(livechat|intercom|drift|crisp|tawk)/i, // 在线客服 /(videojs|jwplayer|flowplayer)/i, // 重型播放器(弱网下首页可省) ]; // 弱网下拦截的预连接/预取 function blockHeavyResources() { if (!IS_SLOW_NETWORK) return; const blockScript = (script) => { const src = script.src || ''; if (HEAVY_SCRIPT_PATTERNS.some(p => p.test(src))) { // 保留 src 但阻止执行(通过替换为注释) script.setAttribute('type', 'application/wb-blocked'); script.remove(); return true; } return false; }; // 拦截 document-start 阶段的脚本 const removeHeavyScripts = () => { document.querySelectorAll('script[src]').forEach(s => { if (!s.dataset.wbChecked) { s.dataset.wbChecked = '1'; blockScript(s); } }); }; removeHeavyScripts(); // 拦截预连接/预取/预渲染 const removeHints = () => { document.querySelectorAll('link[rel="preconnect"], link[rel="prefetch"], link[rel="preload"], link[rel="dns-prefetch"], link[rel="prebake"], link[rel="prerender"]').forEach(link => { const href = link.href || ''; if (HEAVY_SCRIPT_PATTERNS.some(p => p.test(href)) || href.startsWith('https://fonts.')) { link.remove(); } }); }; removeHints(); // 弱网下禁用网页字体(省流量,改用系统字体) GM_addStyle(` @font-face { font-family: 'wb-fallback'; src: local('system-ui'); } `); // 动态添加的脚本 new MutationObserver(() => { document.querySelectorAll('script[src]:not([data-wb-checked])').forEach(blockScript); removeHints(); }).observe(document.documentElement, { childList: true, subtree: true }); } /* ============================================================ * 4. 流量节省 (Save-Data) * ============================================================ */ // 向站点声明省流量偏好(部分站点支持 Save-Data,会主动发轻量版) function enableSaveData() { try { // 模拟 saveData 提示(部分站点的 JS 检测) Object.defineProperty(navigator, 'connection', { get: () => conn || {}, configurable: true }); } catch (e) {} // 为支持 Save-Data 的站点添加标记 // 部分站点通过 document.documentElement 属性检测 if (IS_SLOW_NETWORK) { document.documentElement.setAttribute('data-save-data', 'on'); document.documentElement.setAttribute('data-network', conn ? conn.effectiveType : 'unknown'); } // 弱网下阻止预加载视频/音频 if (IS_SLOW_NETWORK) { GM_addStyle(` video[preload="auto"], audio[preload="auto"] { transition: none; } `); } } /* ============================================================ * 5. 断线检测与自动重连 * ============================================================ */ let offlineNotified = false; function initConnectionMonitor() { // 离线提示条 const showOfflineBar = () => { let bar = document.getElementById('wb-offline-bar'); if (!bar) { bar = document.createElement('div'); bar.id = 'wb-offline-bar'; GM_addStyle(` #wb-offline-bar { position: fixed; top: 0; left: 0; right: 0; z-index: 2147483646; background: #e74c3c; color: #fff; text-align: center; padding: 8px 12px; font-size: 13px; font-family: system-ui, sans-serif; box-shadow: 0 2px 8px rgba(0,0,0,0.2); } `); document.body.appendChild(bar); } bar.textContent = '📡 网络已断开,正在尝试重连...'; }; const hideOfflineBar = () => { const bar = document.getElementById('wb-offline-bar'); if (bar) bar.remove(); }; window.addEventListener('offline', () => { offlineNotified = true; showOfflineBar(); }); window.addEventListener('online', () => { if (offlineNotified) { offlineNotified = false; hideOfflineBar(); // 在线后刷新当前页(重新加载网络资源) // 只在页面是空白/错误页时刷新,避免打断用户 if (document.readyState === 'complete' && document.body && document.body.children.length < 5) { location.reload(); } } }); } /* ============================================================ * 6. WebSocket 心跳保活 * ============================================================ */ function initWebSocketKeepAlive() { // 劫持 WebSocket,自动添加心跳 if (window.WebSocket) { const NativeWS = window.WebSocket; const wsMap = new WeakMap(); function WSPatch(url, protocols) { const ws = protocols ? new NativeWS(url, protocols) : new NativeWS(url); wsMap.set(ws, { pingInterval: null, lastActive: Date.now() }); // 心跳:每 30 秒发送一次 Ping(弱网 15 秒) const startHeartbeat = () => { const meta = wsMap.get(ws); if (meta.pingInterval) return; meta.pingInterval = setInterval(() => { if (ws.readyState === NativeWS.OPEN) { try { ws.send('{"type":"ping"}'); // 通用心跳消息 } catch (e) { /* 忽略 */ } } }, IS_SLOW_NETWORK ? 15000 : 30000); }; // 弱网下自动重连 if (IS_SLOW_NETWORK) { ws.addEventListener('close', () => { const meta = wsMap.get(ws); if (meta && meta.pingInterval) { clearInterval(meta.pingInterval); } // 5 秒后尝试重连(限制最多 3 次) if (!ws.dataset || !ws.dataset.wbReconnectCount) { ws.dataset = ws.dataset || {}; ws.dataset.wbReconnectCount = '1'; setTimeout(() => { try { const newWs = protocols ? new NativeWS(url, protocols) : new NativeWS(url); // 替换(原 ws 已关闭,新的连接由页面逻辑接管较复杂, // 这里仅做日志提示,实际重连交给页面脚本) console.warn('[无线优化] WebSocket 已断开,建议页面自行重连'); } catch (e) {} }, 5000); } }); } ws.addEventListener('open', startHeartbeat); return ws; } WSPatch.prototype = NativeWS.prototype; WSPatch.OPEN = NativeWS.OPEN; WSPatch.CONNECTING = NativeWS.CONNECTING; WSPatch.CLOSING = NativeWS.CLOSING; WSPatch.CLOSED = NativeWS.CLOSED; // 复制静态属性 for (const key of Object.getOwnPropertyNames(NativeWS)) { if (!(key in WSPatch)) { try { WSPatch[key] = NativeWS[key]; } catch (e) {} } } window.WebSocket = WSPatch; } } /* ============================================================ * 7. 动画降级(弱网/省电) * ============================================================ */ function downgradeAnimations() { if (!IS_SLOW_NETWORK && !conn || !(conn && conn.saveData)) return; // 弱网下降低动画流畅度,减少 CPU/GPU 占用 GM_addStyle(` *, *::before, *::after { animation-duration: 0.001s !important; animation-iteration-count: 1 !important; transition-duration: 0.001s !important; scroll-behavior: auto !important; } `); } /* ============================================================ * 8. 状态面板 * ============================================================ */ function initStatusPanel() { // 显示网络信息浮窗(可通过菜单开关) let panelVisible = GM_getValue('panelVisible', false); const createPanel = () => { if (document.getElementById('wb-net-panel')) return; const panel = document.createElement('div'); panel.id = 'wb-net-panel'; GM_addStyle(` #wb-net-panel { position: fixed; bottom: 20px; right: 20px; z-index: 2147483646; background: rgba(17,17,17,0.9); color: #fff; padding: 12px 16px; border-radius: 10px; font-size: 12px; font-family: system-ui, monospace; box-shadow: 0 4px 16px rgba(0,0,0,0.35); pointer-events: auto; min-width: 160px; line-height: 1.7; } #wb-net-panel .wp-title { font-weight: bold; font-size: 13px; margin-bottom: 4px; } #wb-net-panel .wp-close { position: absolute; top: 6px; right: 8px; cursor: pointer; opacity: 0.7; font-size: 14px; } #wb-net-panel .wp-close:hover { opacity: 1; } #wb-net-panel .wp-good { color: #2ecc71; } #wb-net-panel .wp-mid { color: #f39c12; } #wb-net-panel .wp-bad { color: #e74c3c; } `); panel.innerHTML = `