--- layout: post title: "嗅探脚本" date: 2026-06-12 18:01:02 +08:00 categories: 拾光 随笔 时光存档 tags: 风正扬 --- // ==UserScript== // @name 布局修正·UI美化·Bug6.9日修复完整版 // @namespace https://viayoo.com/ // @version 6.3-stable // @description 精准修复顶部分类标签拥挤换行、布局错位,修复代码报错,保留全部原有功能 // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @grant GM_download // @grant GM_setClipboard // @grant GM_openInTab // @connect * // @run-at document-end // @exclude *://123apps.com/* // @exclude *://*.123apps.com/* // @exclude *://online-audio-converter.com/cn/* // @exclude *://video-converter.com/cn/* // @exclude *://online-video-cutter.com/cn/* // @exclude *://www.diancigaoshou.com/* // ==/UserScript== (function() { 'use strict'; const fixedFontStyle = document.createElement('style'); fixedFontStyle.textContent = ` /* 固定浮层:排除 tm- + 三方自身两个弹窗 */ div[style*="position:fixed"]:not([class^="tm-"]):not(#filterHidePanel):not(.mask), div[style*="position:fixed"]:not([class^="tm-"]):not(#filterHidePanel):not(.mask) *, /* 定位浮层:同样排除自身弹窗 */ div[style*="top:"][style*="left:"]:not([class^="tm-"]):not(#filterHidePanel):not(.mask), div[style*="top:"][style*="left:"]:not([class^="tm-"]):not(#filterHidePanel):not(.mask) *, /* 格式过滤设置面板 */ .format-settings-header, .format-settings-header *, .format-settings-title, .format-settings-close, .format-group-control-btn, .format-settings-group, .format-settings-group *, .format-settings-group-title, .format-group-controls, .format-checkbox-container, .format-checkbox-container *, .format-checkbox-item, .size-filter-section, .size-filter-section *, .switch-row, .switch-label, .size-filter-row, .size-filter-label, .size-filter-input, .switch, .switch *, /* 常规列表面板 */ .p-item-url, .p-item-bar, .p-cp, .p-open, .p-down, .p-conv, .p-item-bar *, /* 全局span:排除tm组件 + 三方新弹窗内span */ span[style*="font-size:11px"]:not(.tm-floating-btn span):not(.tm-mobile-menu span):not(.tm-highlight span):not(#filterHidePanel span):not(.mask span) { font-size: 10px !important; } `; document.head.appendChild(fixedFontStyle); // 下面是原有代码 let filterCountNum = 0; let invalidLinkCount = 0; const mgmapi = { async getValue(name, defaultVal) { return typeof GM_getValue === "function" ? GM_getValue(name, defaultVal) : await GM.getValue(name, defaultVal); }, async setValue(name, value) { return typeof GM_setValue === "function" ? GM_setValue(name, value) : await GM.setValue(name, value); }, openInTab(url) { if (typeof GM_openInTab === "function") { GM_openInTab(url, { active: true }); } else if (typeof GM.openInTab === "function") { GM.openInTab(url, { active: true }); } else { window.open(url, '_blank'); } }, copyText(text) { try { if (typeof GM_setClipboard === "function") { GM_setClipboard(text); msg("✅ 复制成功"); return; } if (typeof GM.setClipboard === "function") { GM.setClipboard(text); msg("✅ 复制成功"); return; } if (navigator.clipboard) { navigator.clipboard.writeText(text).then(() => msg("✅ 复制成功")); return; } const t = document.createElement("textarea"); t.value = text; t.style.opacity = "0"; document.body.appendChild(t); t.select(); document.execCommand("copy"); t.remove(); msg("✅ 复制成功"); } catch (e) { msg("❌ 复制失败"); } }, downloadFile({ url, name }) { if (typeof GM_download === "function") { GM_download({ url, name, saveAs: true }); return; } const a = document.createElement('a'); a.href = url; a.download = name || url.split('/').pop(); a.style.display = 'none'; document.body.appendChild(a); a.click(); setTimeout(() => a.remove(), 100); }, xmlhttpRequest(options) { if (typeof GM_xmlhttpRequest === "function") { return GM_xmlhttpRequest(options); } else if (typeof GM.xmlHttpRequest === "function") { return GM.xmlHttpRequest(options); } else { return new Promise(resolve => { if (options.method === "HEAD") { fetch(options.url, { method: "HEAD", mode: 'no-cors' }) .then(res => { const headers = new Map(); res.headers.forEach((value, key) => headers.set(key.toLowerCase(), value)); const contentLength = headers.get('content-length'); resolve({ responseHeaders: contentLength ? `content-length: ${contentLength}` : '', status: res.status }); }) .catch(() => resolve({ responseHeaders: '', status: 0 })); } else { fetch(options.url) .then(res => res.text()) .then(text => resolve({ responseText: text })) .catch(() => resolve({ responseText: '' })); } }); } } }; function fixUrl(url) { if (!url) return url; let u = url.replace(/^file:\/\/\/([^\/]+)\//i, 'https://$1/'); u = u.split('?')[0].split('#')[0]; return u; } function msg(text, t = 2000) { let m = document.createElement("div"); m.innerText = text; m.style = `position:fixed;bottom:60px;right:15px;background:rgba(0,0,0,0.75);color:#fff !important;padding:8px 14px;border-radius:8px;z-index:99999999;font-size:12px !important;backdrop-filter:blur(6px);border:1px solid rgba(255,255,255,0.1);`; document.body.appendChild(m); setTimeout(() => m.remove(), t); } if (location.host === "tools.thatwind.com") return; let shownUrls = new Set(); let allItems = []; let currentFilter = 'all'; let sn = 1; let formatSettingsPanel = null; let isFormatSettingsOpen = false; let filteredHideList = []; let observerLock = false; let filteredUrlSet = new Set(); let formatCounts = { MP4: 0, M3U8: 0, TS: 0, FLV: 0, MKV: 0, WEBM: 0, AVI: 0, MOV: 0, WMV: 0, VIDEO: 0, AAC: 0, MP3: 0, AUDIO: 0, JPG: 0, PNG: 0, GIF: 0, BMP: 0, WEBP: 0, SVG: 0, ICO: 0, TIFF: 0, HEIC: 0, AVIF: 0, JFIF: 0, PJPEG: 0, JXR: 0, IMAGE: 0, PDF: 0, ZIP: 0, RAR: 0, APK: 0, EXE: 0, OTHER: 0 }; let enabledFormats = {}; Object.keys(formatCounts).forEach(k => enabledFormats[k] = true); let sizeFilterSettings = { enabled: false, minSize: 0, maxSize: 0 }; let checkedElements = new WeakSet(); let box, container, categoryBar, list, formatCountDisplay; // ===== 全局样式(原样保留)===== const globalStyle = document.createElement('style'); globalStyle.textContent = ` @keyframes categoryVideo { 0% { box-shadow: 0 0 0 0 rgba(82,196,26,0.8), 0 0 0 0 rgba(255,255,255,0.6); } 50% { box-shadow: 0 0 14px 6px rgba(82,196,26,0.4), 0 0 20px 8px rgba(255,255,255,0.35); } 100% { box-shadow: 0 0 0 0 rgba(82,196,26,0.8), 0 0 0 0 rgba(255,255,255,0.6); } } @keyframes categoryAudio { 0% { box-shadow: 0 0 0 0 rgba(64,169,255,0.8), 0 0 0 0 rgba(255,255,255,0.6); } 50% { box-shadow: 0 0 14px 6px rgba(64,169,255,0.4), 0 0 20px 8px rgba(255,255,255,0.35); } 100% { box-shadow: 0 0 0 0 rgba(64,169,255,0.8), 0 0 0 0 rgba(255,255,255,0.6); } } @keyframes categoryImage { 0% { box-shadow: 0 0 0 0 rgba(247,89,171,0.8), 0 0 0 0 rgba(255,255,255,0.6); } 50% { box-shadow: 0 0 14px 6px rgba(247,89,171,0.4), 0 0 20px 8px rgba(255,255,255,0.35); } 100% { box-shadow: 0 0 0 0 rgba(247,89,171,0.8), 0 0 0 0 rgba(255,255,255,0.6); } } @keyframes categoryDoc { 0% { box-shadow: 0 0 0 0 rgba(250,84,28,0.8), 0 0 0 0 rgba(255,255,255,0.6); } 50% { box-shadow: 0 0 14px 6px rgba(250,84,28,0.4), 0 0 20px 8px rgba(255,255,255,0.35); } 100% { box-shadow: 0 0 0 0 rgba(250,84,28,0.8), 0 0 0 0 rgba(255,255,255,0.6); } } @keyframes categoryArchive { 0% { box-shadow: 0 0 0 0 rgba(19,194,194,0.8), 0 0 0 0 rgba(255,255,255,0.6); } 50% { box-shadow: 0 0 14px 6px rgba(19,194,194,0.4), 0 0 20px 8px rgba(255,255,255,0.35); } 100% { box-shadow: 0 0 0 0 rgba(19,194,194,0.8), 0 0 0 0 rgba(255,255,255,0.6); } } @keyframes categoryApp { 0% { box-shadow: 0 0 0 0 rgba(235,47,150,0.8), 0 0 0 0 rgba(255,255,255,0.6); } 50% { box-shadow: 0 0 14px 6px rgba(235,47,150,0.4), 0 0 20px 8px rgba(255,255,255,0.35); } 100% { box-shadow: 0 0 0 0 rgba(235,47,150,0.8), 0 0 0 0 rgba(255,255,255,0.6); } } @keyframes tabAllRainbow { 0% { box-shadow: 0 0 10px 4px hsla(0,80%,60%,0.6), 0 0 16px 6px rgba(255,255,255,0.5); } 25% { box-shadow: 0 0 10px 4px hsla(90,80%,55%,0.6), 0 0 16px 6px rgba(255,255,255,0.5); } 50% { box-shadow: 0 0 10px 4px hsla(180,80%,60%,0.6), 0 0 16px 6px rgba(255,255,255,0.5); } 75% { box-shadow: 0 0 10px 4px hsla(270,80%,65%,0.6), 0 0 16px 6px rgba(255,255,255,0.5); } 100% { box-shadow: 0 0 10px 4px hsla(360,80%,60%,0.6), 0 0 16px 6px rgba(255,255,255,0.5); } } .clear-animate-btn.run-ani{ animation: tabAllRainbow 3s ease-in-out infinite !important; } .clear-animate-btn{ animation: none !important; } @keyframes ballRainbowGlow { 0% { box-shadow: 0 0 0 0 hsla(0, 80%, 60%, 0.8), 0 0 0 0 rgba(255,255,255,0.6); } 14% { box-shadow: 0 0 16px 6px hsla(45, 80%, 60%, 0.5), 0 0 24px 10px rgba(255,255,255,0.35); } 28% { box-shadow: 0 0 16px 6px hsla(90, 80%, 55%, 0.5), 0 0 24px 10px rgba(255,255,255,0.35); } 42% { box-shadow: 0 0 16px 6px hsla(135, 80%, 55%, 0.5), 0 0 24px 10px rgba(255,255,255,0.35); } 56% { box-shadow: 0 0 16px 6px hsla(180, 80%, 60%, 0.5), 0 0 24px 10px rgba(255,255,255,0.35); } 70% { box-shadow: 0 0 16px 6px hsla(225, 80%, 65%, 0.5), 0 0 24px 10px rgba(255,255,255,0.35); } 84% { box-shadow: 0 0 16px 6px hsla(270, 80%, 65%, 0.5), 0 0 24px 10px rgba(255,255,255,0.35); } 100% { box-shadow: 0 0 0 0 hsla(360, 80%, 60%, 0.8), 0 0 0 0 rgba(255,255,255,0.6); } } @keyframes ballRainbowGlowActive { 0% { box-shadow: 0 0 0 0 hsla(0, 80%, 60%, 0.8), 0 0 0 0 rgba(255,255,255,0.6); } 14% { box-shadow: 0 0 16px 6px hsla(45, 80%, 60%, 0.6), 0 0 24px 10px rgba(255,255,255,0.45); } 28% { box-shadow: 0 0 16px 6px hsla(90, 80%, 55%, 0.6), 0 0 24px 10px rgba(255,255,255,0.45); } 42% { box-shadow: 0 0 16px 6px hsla(135, 80%, 55%, 0.6), 0 0 24px 10px rgba(255,255,255,0.45); } 56% { box-shadow: 0 0 16px 6px hsla(180, 80%, 60%, 0.6), 0 0 24px 10px rgba(255,255,255,0.45); } 70% { box-shadow: 0 0 16px 6px hsla(225, 80%, 65%, 0.6), 0 0 24px 10px rgba(255,255,255,0.45); } 84% { box-shadow: 0 0 16px 6px hsla(270, 80%, 65%, 0.6), 0 0 24px 10px rgba(255,255,255,0.45); } 100% { box-shadow: 0 0 0 0 hsla(360, 80%, 60%, 0.8), 0 0 0 0 rgba(255,255,255,0.6); } } .icon{ position:fixed;z-index:2147483647 !important; width:52px;height:52px;border-radius:50%; background:rgba(0,0,0,0.8);display:flex; align-items:center;justify-content:center; font-size:11px !important;color:#fff !important;font-weight:bold !important; cursor:move; animation: ballRainbowGlow 3.2s ease-in-out infinite !important; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0.8; transition: all 0.3s cubic-bezier(0.25,0.8,0.25,1) !important; } .icon.active{animation: ballRainbowGlowActive 1.6s ease-in-out infinite !important;} .circular-ring{ position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 50%; pointer-events: none; z-index: 0 !important; transform-origin: center; animation: starRotate 8s linear infinite !important; } @keyframes starRotate{ 0%{transform:rotate(0deg)} 100%{transform:rotate(360deg)} } .star-item{ position: absolute; left: 50%; top: 0; font-size: 11px !important; opacity: 0.6; transform-origin: center 158px; } @keyframes starTwinkle{ 0%,100%{opacity:0.3;transform:scale(0.7)} 50%{opacity:1;transform:scale(1.3)} } .star-item.video{color:#52c41a !important;} .star-item.audio{color:#722ed1 !important;} .star-item.image{color:#f759ab !important;} .star-item.doc{color:#fa541c !important;} .star-item.zip{color:#13c2c2 !important;} .outer-ring{ position: absolute; left: 0; top: 0; width: 100%; height: 100%; border-radius: 50%; pointer-events: none; z-index: 1 !important; } @keyframes ring-vid{ 0%{transform:scale(2.0);opacity:1;border:3px solid #52c41a;} 100%{transform:scale(1);opacity:0;border:3px solid #52c41a;} } @keyframes ring-aud{ 0%{transform:scale(2.0);opacity:1;border:3px solid #722ed1;} 100%{transform:scale(1);opacity:0;border:3px solid #722ed1;} } @keyframes ring-img{ 0%{transform:scale(2.0);opacity:1;border:3px solid #f759ab;} 100%{transform:scale(1);opacity:0;border:3px solid #f759ab;} } @keyframes ring-doc{ 0%{transform:scale(2.0);opacity:1;border:3px solid #fa541c;} 100%{transform:scale(1);opacity:0;border:3px solid #fa541c;} } @keyframes ring-zip{ 0%{transform:scale(2.0);opacity:1;border:3px solid #13c2c2;} 100%{transform:scale(1);opacity:0;border:3px solid #13c2c2;} } .ring-vid{animation:ring-vid 1.4s ease forwards;} .ring-aud{animation:ring-aud 1.4s ease forwards;} .ring-img{animation:ring-img 1.4s ease forwards;} .ring-doc{animation:ring-doc 1.4s ease forwards;} .ring-zip{animation:ring-zip 1.4s ease forwards;} .category-tab { transition: box-shadow .3s ease; padding:4px 8px;border-radius:16px;font-size:11px;cursor:pointer; transition: all 0.25s ease;white-space:nowrap;border:1px solid transparent; opacity:0.85;flex:0 0 auto; } .category-tab.active[data-category="all"]{ animation: tabAllRainbow 3s ease-in-out infinite !important; } .category-tab.active[data-category="video"]{ animation: categoryVideo 2.6s ease-in-out infinite !important; } .category-tab.active[data-category="audio"]{ animation: categoryAudio 2.6s ease-in-out infinite !important; } .category-tab.active[data-category="image"]{ animation: categoryImage 2.6s ease-in-out infinite !important; } .category-tab.active[data-category="document"]{ animation: categoryDoc 2.6s ease-in-out infinite !important; } .category-tab.active[data-category="archive"]{ animation: categoryArchive 2.6s ease-in-out infinite !important; } .category-tab.active[data-category="app"]{ animation: categoryApp 2.6s ease-in-out infinite !important; } .category-tab.active[data-category="other"]{ animation: categoryDoc 2.6s ease-in-out infinite !important; } .category-row-wrap { display:flex; gap:4px; row-gap:6px; padding:4px 8px 0 8px; flex-wrap: wrap; align-items:center; justify-content:flex-start; overflow: hidden; flex-shrink: 0; } .item .cp,.item .open-btn,.item .download-btn,.item .convert-btn { transition: all .15s ease; border-radius:6px; } .item .cp:hover,.item .open-btn:hover,.item .download-btn:hover,.item .convert-btn:hover { transform: scale(1.05); filter: brightness(1.2); background:rgba(255,255,255,0.15) !important; } ::-webkit-scrollbar{width:6px;height:6px;} ::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.25);border-radius:6px;} ::-webkit-scrollbar-track{background:rgba(255,255,255,0.05);} .switch { position:relative;display:inline-block;width:44px;height:24px; } .switch input {opacity:0;width:0;height:0;} .slider { position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0; background-color:#2a2a2a;transition:.3s;border-radius:24px; border:1px solid rgba(255,255,255,0.1); } .slider:before { position:absolute;content:"";height:18px;width:18px;left:2px;bottom:2px; background-color:#fff;transition:.3s;border-radius:50%; } input:checked + .slider {background-color:#40a9ff;} input:checked + .slider:before {transform: translateX(20px);} `; document.head.appendChild(globalStyle); // ===== 弹窗样式(原样保留)===== const popStyle = document.createElement('style'); popStyle.textContent = ` #filterHidePanel{ position:fixed; top:50%;left:50%; transform:translate(-50%,-50%); width:85%;max-width:800px;max-height:75vh; background:rgba(0,0,0,0.75); border-radius:12px;border:1px solid rgba(255,255,255,0.15); z-index:99999999;display:none;flex-direction:column;overflow:hidden; } #filterHidePanel .p-head{ padding:12px 18px;background:rgba(0,0,0,0.6); display:flex;justify-content:space-between;align-items:center; color:#fff;font-size:14px;border-bottom:1px solid rgba(255,255,255,0.1); position: sticky;top: 0;z-index: 100; } #filterHidePanel .p-close{cursor:pointer;font-size:20px;color:#ccc;padding:0 8px;transition:color 0.2s;} #filterHidePanel .p-close:hover{color:#fff;} #filterHidePanel .p-list{flex:1;padding:10px;overflow-y:auto;} #filterHidePanel .p-item{ background:rgba(255,255,255,0.05);color:#fff;padding:12px;border-radius:10px;margin:6px 0;font-size:12px; border-left:3px solid #40a9ff;transition:background 0.2s; } #filterHidePanel .p-item:hover{background:rgba(255,255,255,0.08);} #filterHidePanel .p-item-url{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:4px 0;color:#eee;line-height:1.4;} #filterHidePanel .p-item-bar{display:flex;gap:12px;margin-top:10px;flex-wrap:wrap;} #filterHidePanel .p-cp,#filterHidePanel .p-open,#filterHidePanel .p-down,#filterHidePanel .p-conv{cursor:pointer;padding:3px 8px;border:1px solid;border-radius:6px;font-size:11px;transition:all 0.2s;} #filterHidePanel .p-cp{color:#40a9ff;border-color:#40a9ff;} #filterHidePanel .p-open{color:#722ed1;border-color:#722ed1;} #filterHidePanel .p-down{color:#52c41a;border-color:#52c41a;} #filterHidePanel .p-conv{color:#fa8c16;border-color:#fa8c16;} #filterHidePanel .p-cp:hover,#filterHidePanel .p-open:hover,#filterHidePanel .p-down:hover,#filterHidePanel .p-conv:hover{background:rgba(255,255,255,0.15);} `; document.head.appendChild(popStyle); // ===== 面板逻辑(略,保持你原有结构)===== function createHideFilterPanel() { if (document.getElementById('filterHidePanel')) return; // 注入专属样式,锁定字号 const style = document.createElement('style'); style.textContent = ` #filterHidePanel .p-head { font-size: 16px !important; line-height: 1.5 !important; } #filterHidePanel .p-head span { font-size: inherit !important; } #filterHidePanel .p-close { font-size: 18px !important; cursor: pointer; } `; document.head.appendChild(style); const p = document.createElement('div'); p.id = 'filterHidePanel'; p.innerHTML = `
已被过滤资源列表 ×
`; document.body.appendChild(p); p.querySelector('.p-close').onclick = () => p.style.display = 'none'; p.onclick = e => { if (e.target === p) p.style.display = 'none'; }; } function showHideFilterPanel() { createHideFilterPanel(); const panel = document.getElementById('filterHidePanel'); const wrap = document.getElementById('hideFilterListWrap'); // 先提前注入样式(放在脚本顶部/初始化位置) const style = document.createElement('style'); style.textContent = ` .empty-tip { color: #888 !important; text-align: center !important; padding: 30px !important; font-size: 13px !important; } `; document.head.appendChild(style); // 对应逻辑改为 if (filteredHideList.length === 0) { wrap.innerHTML = '
暂无被过滤的资源
'; } else { let html = ''; filteredHideList.forEach((item, idx) => { const shortUrl = item.url.length > 120 ? item.url.substring(0, 120) + '...' : item.url; let typeClass = 'type-default'; const cat = getFileCategory(item.type); if (cat === 'video') typeClass = 'type-video'; else if (cat === 'audio') typeClass = 'type-audio'; else if (cat === 'image') typeClass = 'type-image'; else if (cat === 'document') typeClass = 'type-document'; else if (cat === 'archive') typeClass = 'type-archive'; else if (cat === 'app') typeClass = 'type-app'; html += `
${idx + 1}. ${item.type} ${item.info || '已过滤'}
${shortUrl}
复制 新标签打开 下载 转换
`; }); wrap.innerHTML = html; } panel.style.display = 'flex'; setTimeout(() => { wrap.querySelectorAll('.p-cp').forEach(el => el.onclick = () => mgmapi.copyText(el.dataset.url)); wrap.querySelectorAll('.p-open').forEach(el => el.onclick = () => mgmapi.openInTab(el.dataset.url)); wrap.querySelectorAll('.p-down').forEach(el => el.onclick = function () { mgmapi.downloadFile({ url: this.dataset.url, name: this.dataset.name }); }); wrap.querySelectorAll('.p-conv').forEach(el => el.onclick = () => handleConversion(el.dataset.url)); }, 50); } function getFileType(url) { if (!url || typeof url !== 'string') return "OTHER"; const urlLower = url.toLowerCase(); if (/\.webp(\?|$|#|&|%)/i.test(url)) return "WEBP"; if (urlLower.includes('/webp/') || urlLower.includes('/format,webp/') || urlLower.includes('format=webp') || urlLower.includes('fm=webp') || urlLower.includes('f=webp') || urlLower.includes('type=webp')) return "WEBP"; if (/\.mp4(\?|$|#)/i.test(url)) return "MP4"; if (/\.m3u8(\?|$|#)/i.test(url)) return "M3U8"; if (/\.ts(\?|$|#)/i.test(url)) return "TS"; if (/\.aac(\?|$|#)/i.test(url)) return "AAC"; if (/\.mp3(\?|$|#)/i.test(url)) return "MP3"; if (/\.flv(\?|$|#)/i.test(url)) return "FLV"; if (/\.mkv(\?|$|#)/i.test(url)) return "MKV"; if (/\.webm(\?|$|#)/i.test(url)) return "WEBM"; if (/\.avi(\?|$|#)/i.test(url)) return "AVI"; if (/\.mov(\?|$|#)/i.test(url)) return "MOV"; if (/\.wmv(\?|$|#)/i.test(url)) return "WMV"; if (/\.jpg(\?|$|#)/i.test(url) || /\.jpeg(\?|$|#)/i.test(url)) return "JPG"; if (/\.png(\?|$|#)/i.test(url)) return "PNG"; if (/\.gif(\?|$|#)/i.test(url)) return "GIF"; if (/\.bmp(\?|$|#)/i.test(url)) return "BMP"; if (/\.svg(\?|$|#)/i.test(url)) return "SVG"; if (/\.ico(\?|$|#)/i.test(url)) return "ICO"; if (/\.tiff(\?|$|#)/i.test(url) || /\.tif(\?|$|#)/i.test(url)) return "TIFF"; if (/\.heic(\?|$|#)/i.test(url) || /\.heif(\?|$|#)/i.test(url)) return "HEIC"; if (/\.avif(\?|$|#)/i.test(url)) return "AVIF"; if (/\.jfif(\?|$|#)/i.test(url)) return "JFIF"; if (/\.pjpeg(\?|$|#)/i.test(url) || /\.pjpg(\?|$|#)/i.test(url)) return "PJPEG"; if (/\.jxr(\?|$|#)/i.test(url) || /\.hdp(\?|$|#)/i.test(url) || /\.wdp(\?|$|#)/i.test(url)) return "JXR"; if (/\.pdf(\?|$|#)/i.test(url)) return "PDF"; if (/\.zip(\?|$|#)/i.test(url)) return "ZIP"; if (/\.rar(\?|$|#)/i.test(url)) return "RAR"; if (/\.apk(\?|$|#)/i.test(url)) return "APK"; if (/\.exe(\?|$|#)/i.test(url)) return "EXE"; if (urlLower.includes('/video/') || urlLower.includes('type=video') || urlLower.includes('video/')) return "VIDEO"; if (urlLower.includes('/audio/') || urlLower.includes('type=audio') || urlLower.includes('audio/')) return "AUDIO"; if (urlLower.includes('/image/') || urlLower.includes('type=image') || urlLower.includes('image/')) { if (urlLower.includes('jpeg') || urlLower.includes('jpg')) return "JPG"; if (urlLower.includes('png')) return "PNG"; if (urlLower.includes('gif')) return "GIF"; if (urlLower.includes('webp')) return "WEBP"; if (urlLower.includes('svg')) return "SVG"; if (urlLower.includes('bmp')) return "BMP"; if (urlLower.includes('ico')) return "ICO"; if (urlLower.includes('tiff') || urlLower.includes('tif')) return "TIFF"; if (urlLower.includes('heic') || urlLower.includes('heif')) return "HEIC"; if (urlLower.includes('avif')) return "AVIF"; return "IMAGE"; } return "OTHER"; } function getFileCategory(type) { const categories = { 'video': ['MP4', 'M3U8', 'TS', 'FLV', 'MKV', 'WEBM', 'AVI', 'MOV', 'WMV', 'VIDEO'], 'audio': ['AAC', 'MP3', 'AUDIO'], 'image': ['JPG', 'PNG', 'GIF', 'BMP', 'WEBP', 'SVG', 'ICO', 'TIFF', 'HEIC', 'AVIF', 'JFIF', 'PJPEG', 'JXR', 'IMAGE'], 'document': ['PDF'], 'archive': ['ZIP', 'RAR'], 'app': ['APK', 'EXE'], 'other': ['OTHER'] }; for (const [category, types] of Object.entries(categories)) { if (types.includes(type)) return category; } return 'other'; } function checkSizeFilter(fileSize) { if (!sizeFilterSettings.enabled) return true; if (fileSize === 0) return true; const minSize = sizeFilterSettings.minSize * 1024; const maxSize = sizeFilterSettings.maxSize * 1024; if (minSize > 0 && fileSize < minSize) return false; if (maxSize > 0 && fileSize > maxSize) return false; return true; } function isInvalidItem(item) { if (!item) return false; const info = (item.info || ""); return info.includes("未知大小") || info.includes("跨域无法获取") || info.includes("获取失败") || info.includes("解析失败"); } async function getInfoByUrl(url, type) { let finalUrl = fixUrl(url); const imgTypes = ["JPG", "PNG", "GIF", "BMP", "WEBP", "SVG", "ICO", "TIFF", "HEIC", "AVIF", "JFIF", "PJPEG", "JXR", "IMAGE"]; if (imgTypes.includes(type)) { return new Promise(resolve => { let fileSize = 0; mgmapi.xmlhttpRequest({ method: "HEAD", url: finalUrl, timeout: 2500, onload(res) { const sizeMat = res.responseHeaders?.match(/content-length:\s*(\d+)/i); if (sizeMat) fileSize = parseInt(sizeMat[1]) || 0; }, onerror() { }, ontimeout() { getImgSize(); } }); setTimeout(getImgSize, 300); function getImgSize() { let sizeText = "未知大小"; if (fileSize > 0) { if (fileSize < 1024) sizeText = fileSize + "B"; else if (fileSize < 1024 * 1024) sizeText = (fileSize / 1024).toFixed(1) + "KB"; else sizeText = (fileSize / 1024 / 1024).toFixed(1) + "MB"; } const img = new Image(); img.src = finalUrl; img.onload = function () { const w = img.naturalWidth || img.width; const h = img.naturalHeight || img.height; if (w && h && w > 10 && h > 10) resolve({ info: `${sizeText} | 📐 ${w} × ${h}`, size: fileSize, realUrl: finalUrl, isApi: false }); else resolve({ info: `${sizeText} | 📐 无法解析尺寸`, size: fileSize, realUrl: finalUrl, isApi: false }); }; img.onerror = img.onabort = function () { resolve({ info: `${sizeText} | 📐 跨域无法获取`, size: fileSize, realUrl: finalUrl, isApi: false }); }; setTimeout(() => resolve({ info: `${sizeText} | 📐 获取超时`, size: fileSize, realUrl: finalUrl, isApi: false }), 3000); } }); } return new Promise(resolve => { mgmapi.xmlhttpRequest({ method: "HEAD", url: finalUrl, timeout: 3000, onload(res) { if (res.finalUrl) finalUrl = res.finalUrl; let isApi = false; const ct = res.responseHeaders || ""; if (/content-type.*xml/i.test(ct) || /content-type.*json/i.test(ct)) isApi = true; if (/\.xml(\?|$|#)/i.test(finalUrl) || /\.json(\?|$|#)/i.test(finalUrl)) isApi = true; if (isApi) return resolve({ info: "⚠️ 接口XML/JSON", size: 0, realUrl: finalUrl, isApi: true }); if (["MP4", "TS", "FLV", "MKV", "WEBM", "AVI", "MOV", "WMV", "VIDEO"].includes(type)) { try { const size = res.responseHeaders.match(/content-length:\s*(\d+)/i); const length = size ? parseInt(size[1]) : 0; let infoText = length ? (length < 1024 ? length + "B" : length < 1024 * 1024 ? (length / 1024).toFixed(1) + "KB" : (length / 1024 / 1024).toFixed(1) + "MB") : "未知大小"; if (["MP4", "MOV", "AVI", "WMV"].includes(type)) infoText += ` | ⏱ ~${Math.round(length / (1024 * 256))}s`; else if (type === "TS") infoText += ` | ⏱ ~${Math.round(length / (1024 * 128))}s`; else if (type === "FLV") infoText += ` | ⏱ ~${Math.round(length / (1024 * 200))}s`; resolve({ info: infoText, size: length, realUrl: finalUrl, isApi: false }); } catch (e) { resolve({ info: "未知大小", size: 0, realUrl: finalUrl, isApi: false }); } } else if (["MP3", "AAC", "AUDIO"].includes(type)) { try { const size = res.responseHeaders.match(/content-length:\s*(\d+)/i); const length = size ? parseInt(size[1]) : 0; let infoText = length ? (length < 1024 ? length + "B" : length < 1024 * 1024 ? (length / 1024).toFixed(1) + "KB" : (length / 1024 / 1024).toFixed(1) + "MB") : "未知大小"; if (type === "MP3") infoText += ` | ⏱ ~${Math.round(length / (1024 * 128))}s`; else if (type === "AAC") infoText += ` | ⏱ ~${Math.round(length / (1024 * 64))}s`; resolve({ info: infoText, size: length, realUrl: finalUrl, isApi: false }); } catch (e) { resolve({ info: "未知大小", size: 0, realUrl: finalUrl, isApi: false }); } } else if (type === "M3U8") { mgmapi.xmlhttpRequest({ method: "GET", url: finalUrl, timeout: 5000, onload(res) { try { const text = res.responseText; if (!text || !text.trim().startsWith('#EXTM3U')) return resolve({ info: "无效M3U8", size: 0, realUrl: finalUrl, isApi: false }); const lines = text.split('\n'); let tsCount = 0; for (let i = 0; i < lines.length; i++) if (lines[i].trim() && !lines[i].startsWith('#')) tsCount++; resolve({ info: `分片:${tsCount}`, size: 0, realUrl: finalUrl, isApi: false }); } catch (e) { resolve({ info: "解析失败", size: 0, realUrl: finalUrl, isApi: false }); } }, onerror() { resolve({ info: "获取失败", size: 0, realUrl: finalUrl, isApi: false }); } }); } else { try { const size = res.responseHeaders.match(/content-length:\s*(\d+)/i); const length = size ? parseInt(size[1]) : 0; let infoText = length ? (length < 1024 ? length + "B" : length < 1024 * 1024 ? (length / 1024).toFixed(1) + "KB" : (length / 1024 / 1024).toFixed(1) + "MB") : "未知大小"; resolve({ info: infoText, size: length, realUrl: finalUrl, isApi: false }); } catch (e) { resolve({ info: "未知大小", size: 0, realUrl: url, isApi: false }); } } }, onerror() { resolve({ info: "未知大小", size: 0, realUrl: url, isApi: false }); } }); }); } function initDetect() { const win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window; if (typeof win.fetch === 'function') { const originalFetch = win.fetch; win.fetch = function (...args) { const requestUrl = args[0] && typeof args[0] === 'string' ? args[0] : (args[0] && args[0].url ? args[0].url : args[0]); if (requestUrl && typeof requestUrl === 'string') { const type = getFileType(requestUrl); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url: requestUrl }); } const fetchPromise = originalFetch.apply(this, args); fetchPromise.then(response => { if (response && response.url) { const type = getFileType(response.url); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url: response.url }); } return response; }).catch(() => { }); return fetchPromise; }; } if (typeof win.XMLHttpRequest === 'function') { const OriginalXHR = win.XMLHttpRequest; win.XMLHttpRequest = function () { const xhr = new OriginalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; let requestUrl = ''; xhr.open = function (method, url, ...rest) { requestUrl = url; return originalOpen.apply(this, [method, url, ...rest]); }; xhr.send = function (data) { const onLoad = () => { try { const finalUrl = xhr.responseURL || requestUrl; if (finalUrl) { const type = getFileType(finalUrl); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url: finalUrl }); } } catch (e) { } }; xhr.addEventListener('load', onLoad, { once: true }); return originalSend.call(this, data); }; return xhr; }; } function checkPageResources() { if (observerLock) return; observerLock = true; setTimeout(() => observerLock = false, 500); document.querySelectorAll('video').forEach(video => { if (video.src && !checkedElements.has(video)) { const type = getFileType(video.src); if (type !== "OTHER" && enabledFormats[type] && getFileCategory(type) === 'video') addItem({ type, url: video.src }); checkedElements.add(video); } video.querySelectorAll('source').forEach(source => { if (source.src && !checkedElements.has(source)) { const type = getFileType(source.src); if (type !== "OTHER" && enabledFormats[type] && getFileCategory(type) === 'video') addItem({ type, url: source.src }); checkedElements.add(source); } }); }); document.querySelectorAll('audio').forEach(audio => { if (audio.src && !checkedElements.has(audio)) { const type = getFileType(audio.src); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url: audio.src }); checkedElements.add(audio); } audio.querySelectorAll('source').forEach(source => { if (source.src && !checkedElements.has(source)) { const type = getFileType(source.src); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url: source.src }); checkedElements.add(source); } }); }); document.querySelectorAll('img').forEach(img => { if (img.src && !checkedElements.has(img)) { const type = getFileType(img.src); if (["JPG", "PNG", "GIF", "BMP", "WEBP", "SVG", "ICO", "TIFF", "HEIC", "AVIF", "JFIF", "PJPEG", "JXR", "IMAGE"].includes(type) && enabledFormats[type]) addItem({ type, url: img.src }); checkedElements.add(img); } ['data-original', 'data-actualsrc', 'data-src', 'data-lazy-src'].forEach(attr => { const dataUrl = img.getAttribute(attr); if (dataUrl && dataUrl.length > 10 && !dataUrl.startsWith('data:') && !checkedElements.has(img)) { const type = getFileType(dataUrl); if (["JPG", "PNG", "GIF", "BMP", "WEBP", "SVG", "ICO", "TIFF", "HEIC", "AVIF", "JFIF", "PJPEG", "JXR", "IMAGE"].includes(type) && enabledFormats[type]) addItem({ type, url: dataUrl }); } }); }); document.querySelectorAll('picture').forEach(picture => { if (!checkedElements.has(picture)) { picture.querySelectorAll('source').forEach(source => { if (source.srcset && !checkedElements.has(source)) { const srcset = source.srcset; const sources = srcset.split(',').map(s => s.trim().split(' ')[0]); sources.forEach(src => { if (src) { const type = getFileType(src); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url: src }); } }); checkedElements.add(source); } }); checkedElements.add(picture); } }); document.querySelectorAll('a').forEach(link => { if (link.href && !checkedElements.has(link)) { const type = getFileType(link.href); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url: link.href }); checkedElements.add(link); } }); document.querySelectorAll('*[style*="url("]').forEach(element => { if (!checkedElements.has(element)) { const styleText = element.getAttribute('style') || ''; const urlMatches = styleText.match(/url\(["']?([^"')]+)["']?\)/gi); if (urlMatches) { urlMatches.forEach(match => { const url = match.replace(/url\(["']?(.*?)["']?\)/i, '$1').trim(); if (url) { const type = getFileType(url); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url }); } }); checkedElements.add(element); } } }); } if (document.body) checkPageResources(); if (typeof MutationObserver !== 'undefined') { const observer = new MutationObserver(() => setTimeout(checkPageResources, 300)); if (document.body) observer.observe(document.body, { childList: true, subtree: true }); } if (typeof PerformanceObserver !== 'undefined') { try { const resourceObserver = new PerformanceObserver(list => { list.getEntries().forEach(entry => { if (['fetch', 'xmlhttprequest', 'script', 'link', 'img'].includes(entry.initiatorType)) { const url = entry.name; if (url) { const type = getFileType(url); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url }); } } }); }); resourceObserver.observe({ entryTypes: ['resource'] }); } catch (e) { } } ['play', 'loadedmetadata', 'canplay'].forEach(event => document.addEventListener(event, (e) => { const target = e.target; if (target && (target.tagName === 'VIDEO' || target.tagName === 'AUDIO')) { if (target.src && !checkedElements.has(target)) { const type = getFileType(target.src); if (type !== "OTHER" && enabledFormats[type]) addItem({ type, url: target.src }); checkedElements.add(target); } } }, true) ); setInterval(checkPageResources, 3000); } function handleConversion(url) { mgmapi.copyText(url); setTimeout(() => { const conversionUrl = "https://123apps.com/cn/"; const redirectPage = `重定向`; const dataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(redirectPage); const newWindow = window.open(dataUrl, '_blank', 'noopener,noreferrer,width=1200,height=700'); newWindow ? newWindow.focus() : mgmapi.openInTab(conversionUrl); msg("✅ 链接已复制,正在打开转换网站..."); }, 100); } async function loadUserSettings() { const savedEnabled = await mgmapi.getValue('formatEnabledFormats', null); if (savedEnabled) Object.assign(enabledFormats, savedEnabled); sizeFilterSettings.enabled = await mgmapi.getValue('sizeFilterEnable', false); sizeFilterSettings.minSize = await mgmapi.getValue('sizeFilterMin', 0); sizeFilterSettings.maxSize = await mgmapi.getValue('sizeFilterMax', 0); } function initUI() { if (box) return; box = document.createElement("div"); box.id = "sniffer-main-box"; box.style = `position:fixed;z-index:9999999;left:15px;top:80px;width:320px;max-width:90vw;display:block;user-select:none;`; document.body.appendChild(box); const btn = document.createElement("div"); btn.style = "text-align:right;margin-bottom:8px;"; btn.innerHTML = `
资源嗅探
点击展开
0
`; box.appendChild(btn); formatCountDisplay = btn.querySelector(".format-display"); container = document.createElement("div"); container.style = `max-height:60vh;display:none;flex-direction:column;background:rgba(0,0,0,0.75);-webkit-border:1px solid rgba(255,255,255,0.1);border-radius:8px;overflow:hidden;`; box.appendChild(container); const categoryRow = document.createElement("div"); categoryRow.className = "category-row-wrap"; container.appendChild(categoryRow); initCategoryTabs(categoryRow); const controlRow = document.createElement("div"); controlRow.style = "display:flex;gap:8px;justify-content:center;padding:4px 8px;flex-wrap:wrap;background:transparent;border-bottom:none;margin-top:0;"; controlRow.innerHTML = `
批量下载
格式设置
清空嗅探
已过滤0
`; controlRow.querySelectorAll("div").forEach(el => { el.onmouseover = () => el.style.transform = "scale(1.05)"; el.onmouseout = () => el.style.transform = "scale(1)"; }); container.appendChild(controlRow); list = document.createElement("div"); list.id = "sniffer-list-container"; list.style = `flex:1;overflow-y:auto;padding:4px;`; container.appendChild(list); const style = document.createElement("style"); style.textContent = ` .format-settings-panel { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0,0,0,0.55); backdrop-filter: blur(12px); border: 1px solid rgba(255,255,255,0.15); border-radius: 14px; padding: 20px; width: 460px; max-width: 92vw; max-height: 80vh; overflow-y: auto; z-index: 99999; } .format-settings-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid rgba(255,255,255,0.1); } .format-settings-title { font-size: 15px; color: #fff; font-weight: bold; } .format-settings-close { background: none; border: none; color: #ccc; font-size: 20px; cursor: pointer; } .format-settings-close:hover { color: #fff; } .format-settings-group { margin-bottom: 16px; } .format-settings-group-title { display: flex; justify-content: space-between; align-items: center; font-size: 13px; color: #40a9ff; margin-bottom: 8px; } .format-group-controls { display: flex; gap: 10px; } .format-group-control-btn { font-size: 12px; color: #ccc; cursor: pointer; padding: 2px 6px; border-radius: 4px; } .format-group-control-btn:hover { color: #fff; background: rgba(255,255,255,0.1); } .format-checkbox-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 8px; } .format-checkbox-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #fff; cursor: pointer; padding: 4px; border-radius: 4px; } .format-checkbox-item:hover { background: rgba(255,255,255,0.1); } .format-checkbox-item.checked { color: #40a9ff; } .item{ background:rgba(255,255,255,0.05);color:#fff;padding:12px; border-radius:10px;margin:6px 0;font-size:12px; border-left:3px solid #40a9ff;transition:background 0.2s; } .item:hover{background:rgba(255,255,255,0.08);} .item.mp4{border-left-color:#52c41a;}.item.m3u8{border-left-color:#fa8c16;}.item.ts{border-left-color:#1890ff;} .item.audio{border-left-color:#722ed1;} .item.jpg,.item.jpeg{border-left-color:#fa541c;}.item.png{border-left-color:#13c2c2;}.item.gif{border-left-color:#eb2f96;} .item.bmp{border-left-color:#722ed1;}.item.webp{border-left-color:#fa8c16;}.item.svg{border-left-color:#f759ab;} .item.ico{border-left-color:#52c41a;}.item.tiff{border-left-color:#1890ff;} .item.heic,.item.avif{border-left-color:#40a9ff;}.item.jfif,.item.pjpeg{border-left-color:#fa8c16;}.item.jxr{border-left-color:#666;} .item.image{border-left-color:#f759ab;}.item.pdf{border-left-color:#fa541c;}.item.archive{border-left-color:#13c2c2;}.item.app{border-left-color:#eb2f96;} .tag{color:#ffd040;font-weight:bold;margin-bottom:6px;display:flex;justify-content:space-between;align-items:center;} .url{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:4px 0;cursor:pointer;color:#eee;line-height:1.4;transition:color 0.2s;} .url:hover{color:#fff;} .url.exp{white-space:normal;word-break:break-all;} .info{font-size:11px;color:#aaa;margin:2px 0 6px;} .bar{display:flex;gap:12px;margin-top:10px;flex-wrap:wrap;} .cp,.open-btn,.download-btn,.convert-btn{cursor:pointer;padding:3px 8px;border:1px solid;border-radius:6px;font-size:11px;} .cp{color:#40a9ff;border-color:#40a9ff;}.open-btn{color:#d7bde2;border-color:#d7bde2;} .download-btn{color:#a3e4d7;border-color:#a3e4d7;}.convert-btn{color:#ff9f8c;border-color:#ff9f8c;} .hide .item{display:none;} .format-badge{font-size:9px;padding:1px 5px;border-radius:4px;margin-left:6px;} .category-tab[data-category="all"]{background:#666;color:white;} .category-tab[data-category="video"]{background:#52c41a;color:white;} .category-tab[data-category="audio"]{background:#722ed1;color:white;} .category-tab[data-category="image"]{background:#f759ab;color:white;} .category-tab[data-category="document"]{background:#fa541c;color:white;} .category-tab[data-category="archive"]{background:#13c2c2;color:white;} .category-tab[data-category="app"]{background:#eb2f96;color:white;} .category-tab[data-category="other"]{background:#666;color:white;} .size-filter-section { margin-top: 20px; padding-top: 15px; border-top: 1px solid rgba(255,255,255,0.1); color:#fff; } .switch-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; font-size: 12px; } .size-filter-row { display: flex; align-items: center; margin-bottom: 8px; font-size: 12px; } .size-filter-label { width: 80px; } .size-filter-input { flex: 1; background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.15); border-radius: 6px; padding: 5px; color: #fff; font-size: 12px; } .switch { position: relative; display: inline-block; width: 34px; height: 18px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #444; transition: .3s; border-radius: 18px; } .slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 2px; bottom: 2px; background-color: white; transition: .3s; border-radius: 50%; } input:checked + .slider { background-color: #40a9ff; } input:checked + .slider:before { transform: translateX(16px); } `; document.head.appendChild(style); // ===== 拖拽逻辑(原样保留)===== let dragStartX, dragStartY, boxStartLeft, boxStartTop; const dragIcon = box.querySelector(".icon"); dragIcon.addEventListener('mousedown', e => { dragStartX = e.clientX; dragStartY = e.clientY; boxStartLeft = box.offsetLeft; boxStartTop = box.offsetTop; document.addEventListener('mousemove', onDrag); document.addEventListener('mouseup', stopDrag); }); function onDrag(e) { const dx = e.clientX - dragStartX; const dy = e.clientY - dragStartY; box.style.left = boxStartLeft + dx + 'px'; box.style.top = boxStartTop + dy + 'px'; } function stopDrag() { document.removeEventListener('mousemove', onDrag); document.removeEventListener('mouseup', stopDrag); } let tx, ty, l, t, moved = false; let isLongPress = false; // 新增:标记是否触发了长按 dragIcon.addEventListener('touchstart', e => { tx = e.touches[0].clientX; ty = e.touches[0].clientY; l = box.offsetLeft; t = box.offsetTop; moved = false; }); dragIcon.addEventListener('touchmove', e => { e.stopPropagation(); let dx = e.touches[0].clientX - tx; let dy = e.touches[0].clientY - ty; if (Math.hypot(dx, dy) > 6) moved = true; box.style.left = l + dx + 'px'; box.style.top = t + dy + 'px'; }); dragIcon.addEventListener('touchend', () => { // 触发了长按 或 拖动,都不执行面板切换 if (isLongPress || moved) { isLongPress = false; // 重置标记 return; } container.style.display = container.style.display === 'flex' ? 'none' : 'flex'; }); // 新增:长按悬浮球 隐藏/关闭悬浮球 let longPressTimer = null; const LONG_TIME = 600; // 长按600毫秒触发 dragIcon.addEventListener('mousedown', () => { longPressTimer = setTimeout(() => { isLongPress = true; // 标记长按触发 const icon = document.querySelector('.icon'); if(icon) icon.style.display = 'none'; msg('悬浮球已隐藏,刷新页面恢复'); }, LONG_TIME); }); dragIcon.addEventListener('mouseup', () => { if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); dragIcon.addEventListener('mouseleave', () => { if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); // 移动端触摸长按兼容 dragIcon.addEventListener('touchstart', () => { longPressTimer = setTimeout(() => { isLongPress = true; // 标记长按触发 const icon = document.querySelector('.icon'); if(icon) icon.style.display = 'none'; msg('悬浮球已隐藏,刷新页面恢复'); }, LONG_TIME); }); dragIcon.addEventListener('touchend', () => { if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); dragIcon.addEventListener('touchcancel', () => { if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); // ===== 按钮事件 ===== controlRow.querySelector('.clear-btn').onclick = () => { allItems = []; shownUrls.clear(); list.innerHTML = ''; sn = 1; invalidLinkCount = 0; filteredHideList = []; filteredUrlSet.clear(); resetFormatCounts(); updateBadge(); updateFormatCountDisplay(); document.getElementById('invalidBadge').innerText = "0"; document.getElementById('filterCount').innerText = "0"; msg("✅ 已清空所有嗅探资源"); }; controlRow.querySelector('.filter-btn').onclick = showHideFilterPanel; controlRow.querySelector('.batch-btn').onclick = () => { const videoList = allItems.filter(item => getFileCategory(item.type) === 'video'); const audioList = allItems.filter(item => getFileCategory(item.type) === 'audio'); const imageList = allItems.filter(item => getFileCategory(item.type) === 'image'); const allList = [...allItems]; let mask = document.createElement('div'); mask.style = `position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:99999998;display:flex;align-items:center;justify-content:center;`; let b = document.createElement('div'); b.style = `background:#222;padding:20px;border-radius:12px;border:1px solid rgba(255,255,255,0.15);`; b.innerHTML = `
选择批量下载分类
`; mask.appendChild(b); document.body.appendChild(mask); const closePop = () => mask.remove(); b.querySelectorAll('.down-btn').forEach(btn => { btn.onclick = () => { let type = btn.dataset.type; let arr = []; if (type === 'video') arr = videoList; else if (type === 'audio') arr = audioList; else if (type === 'image') arr = imageList; else arr = allList; if (arr.length === 0) { msg("该分类暂无资源"); closePop(); return; } arr.filter(i => !isInvalidItem(i)).forEach((item, i) => { setTimeout(() => { mgmapi.downloadFile({ url: item.realUrl, name: `file_${i + 1}` }); }, i * 400); }); msg(`已开始批量下载 ${arr.length} 个文件`); closePop(); }; }); b.querySelector('.close-btn').onclick = closePop; mask.onclick = e => e.target === mask && closePop(); }; controlRow.querySelector('.settings-btn').onclick = () => { toggleFormatSettingsPanel(); }; } function initCategoryTabs(wrap) { const cats = [ { key: 'all', name: '全部', bg: '#9a8c98' }, { key: 'video', name: '视频', bg: '#52c41a' }, { key: 'audio', name: '音频', bg: '#40a9ff' }, { key: 'image', name: '图片', bg: '#f759ab' }, { key: 'document', name: '文档', bg: '#fa541c' }, { key: 'archive', name: '压缩', bg: '#13c2c2' }, { key: 'app', name: '应用', bg: '#ff9a9e' }, { key: 'other', name: '其他', bg: '#cdedf6' } ]; wrap.style.display = 'flex'; wrap.style.flexWrap = 'wrap'; wrap.style.gap = '4px'; wrap.style.rowGap = '6px'; wrap.style.justifyContent = 'flex-start'; wrap.style.alignItems = 'center'; wrap.style.padding = '6px 8px'; wrap.style.boxSizing = 'border-box'; cats.forEach(c => { const tab = document.createElement('div'); tab.className = 'category-tab'; tab.style.padding = '4px 7px'; tab.style.color = '#fff !important'; tab.style.borderRadius = '10px'; tab.style.fontSize = '10px !important'; tab.style.cursor = 'pointer'; tab.style.whiteSpace = 'nowrap'; tab.style.transition = 'all 0.2s'; tab.style.boxSizing = 'border-box'; tab.style.background = c.bg; tab.style.flex = '0 0 auto'; tab.dataset.category = c.key; tab.innerHTML = `${c.name}0`; tab.onclick = () => switchCategory(c.key); wrap.appendChild(tab); }); const clearRoundBtn = document.createElement('div'); clearRoundBtn.classList.add('clear-animate-btn'); clearRoundBtn.style.width = '20px'; clearRoundBtn.style.height = '20px'; clearRoundBtn.style.borderRadius = '50%'; clearRoundBtn.style.background = '#b56576'; clearRoundBtn.style.display = 'flex'; clearRoundBtn.style.alignItems = 'center'; clearRoundBtn.style.justifyContent = 'center'; clearRoundBtn.style.cursor = 'pointer'; clearRoundBtn.style.position = 'relative'; clearRoundBtn.style.transition = 'all 0.2s'; clearRoundBtn.style.marginLeft = 'auto'; clearRoundBtn.style.marginRight = '8px'; clearRoundBtn.innerText = '清'; clearRoundBtn.style.color = '#fff !important'; clearRoundBtn.style.fontSize = '8px !important'; clearRoundBtn.style.boxShadow = '0 0 8px 3px hsla(0,100%,60%,0.5)'; clearRoundBtn.style.animation = 'tabAllRainbow 3s ease-in-out infinite'; clearRoundBtn.style.transformOrigin = 'center center'; clearRoundBtn.innerHTML += `0`; clearRoundBtn.onmouseover = () => clearRoundBtn.style.transform = 'scale(1.08)'; clearRoundBtn.onmouseout = () => clearRoundBtn.style.transform = 'scale(1)'; clearRoundBtn.onclick = function () { allItems = allItems.filter(item => !isInvalidItem(item)); invalidLinkCount = 0; sn = 1; list.innerHTML = ""; allItems.forEach(renderItem); updateBadge(); updateFormatCountDisplay(); document.getElementById('invalidBadge').innerText = "0"; msg("✅ 已清理无效链接"); setTimeout(() => updateBadge(), 20); }; wrap.appendChild(clearRoundBtn); } function switchCategory(cat) { currentFilter = cat; sn = 1; list.innerHTML = ""; document.querySelectorAll('.category-tab').forEach(t => { t.classList.remove('active'); if (t.dataset.category === cat) t.classList.add('active'); }); renderFilterList(); } function resetFormatCounts() { Object.keys(formatCounts).forEach(k => formatCounts[k] = 0); } function updateBadge() { const total = allItems.length; const filter = filteredHideList.length; const badge = box.querySelector(".tipBadge"); badge.innerText = total + "|" + filter; const icon = box.querySelector(".icon"); icon.classList.toggle('active', total > 0); let btn = document.querySelector('.clear-animate-btn'); if (!btn) return; let badgeDom = document.getElementById('invalidBadge'); let num = badgeDom ? parseInt(badgeDom.innerText) || 0 : 0; if (num > 0) { btn.classList.add('run-ani'); } else { btn.classList.remove('run-ani'); } } function updateFormatCountDisplay() { let videoNum = formatCounts.MP4 + formatCounts.M3U8 + formatCounts.TS + formatCounts.FLV + formatCounts.MKV + formatCounts.WEBM + formatCounts.AVI + formatCounts.MOV + formatCounts.WMV + formatCounts.VIDEO; let audioNum = formatCounts.AAC + formatCounts.MP3 + formatCounts.AUDIO; let imgNum = formatCounts.JPG + formatCounts.PNG + formatCounts.GIF + formatCounts.BMP + formatCounts.WEBP + formatCounts.SVG + formatCounts.ICO + formatCounts.TIFF + formatCounts.HEIC + formatCounts.AVIF + formatCounts.JFIF + formatCounts.PJPEG + formatCounts.JXR + formatCounts.IMAGE; let otherNum = formatCounts.PDF + formatCounts.ZIP + formatCounts.RAR + formatCounts.APK + formatCounts.EXE + formatCounts.OTHER; if (allItems.length > 0) { let v = allItems.filter(x => getFileCategory(x.type) === 'video').length; let a = allItems.filter(x => getFileCategory(x.type) === 'audio').length; let i = allItems.filter(x => getFileCategory(x.type) === 'image').length; let o = allItems.filter(x => ['other', 'document', 'archive', 'app'].includes(getFileCategory(x.type))).length; formatCountDisplay.innerHTML = `
视${v} 音${a} 图${i} 其${o}
`; } else { formatCountDisplay.innerHTML = `
资源嗅探
点击展开
`; } document.querySelectorAll('.category-tab').forEach(tab => { const key = tab.dataset.category; let num = 0; if (key === 'all') num = allItems.length; else num = allItems.filter(item => getFileCategory(item.type) === key).length; tab.querySelector('.category-count').innerText = num; }); document.getElementById('filterCount').innerText = filteredHideList.length; document.getElementById('invalidBadge').innerText = invalidLinkCount; } function renderFilterList() { if (window._renderFilterTimer) clearTimeout(window._renderFilterTimer); window._renderFilterTimer = setTimeout(() => { list.innerHTML = ''; const filterArr = currentFilter === 'all' ? allItems : allItems.filter(item => getFileCategory(item.type) === currentFilter); let index = 1; filterArr.forEach(item => renderItem(item, index++)); }, 120); } function renderItem(item, index) { const div = document.createElement('div'); div.className = `item ${item.type.toLowerCase()}`; let itemBg = ""; switch (item.type) { case 'MP4': itemBg = 'rgba(39, 174, 96, 0.15)'; break; case 'M3U8': itemBg = 'rgba(230, 126, 34, 0.15)'; break; case 'TS': itemBg = 'rgba(52, 152, 219, 0.15)'; break; case 'FLV': itemBg = 'rgba(155, 89, 182, 0.15)'; break; case 'MKV': itemBg = 'rgba(22, 160, 133, 0.15)'; break; case 'WEBM': itemBg = 'rgba(41, 128, 185, 0.15)'; break; case 'AVI': itemBg = 'rgba(192, 57, 43, 0.15)'; break; case 'MOV': itemBg = 'rgba(142, 68, 173, 0.15)'; break; case 'WMV': itemBg = 'rgba(127, 140, 141, 0.15)'; break; case 'MP3': itemBg = 'rgba(135, 206, 250, 0.15)'; break; case 'AAC': itemBg = 'rgba(9, 132, 227, 0.15)'; break; case 'JPG': itemBg = 'rgba(253, 121, 168, 0.15)'; break; case 'PNG': itemBg = 'rgba(0, 206, 201, 0.15)'; break; case 'GIF': itemBg = 'rgba(108, 92, 231, 0.15)'; break; case 'WEBP': itemBg = 'rgba(253, 203, 110, 0.15)'; break; case 'PDF': itemBg = 'rgba(214, 48, 49, 0.15)'; break; case 'ZIP': itemBg = 'rgba(0, 184, 148, 0.15)'; break; case 'RAR': itemBg = 'rgba(99, 110, 114, 0.15)'; break; case 'APK': itemBg = 'rgba(225, 112, 85, 0.15)'; break; default: itemBg = 'rgba(99, 110, 114, 0.15)'; } div.style.cssText = `margin:7px 0;padding:10px;border-radius:8px;background:${itemBg};`; div.innerHTML = `
${index}. ${item.type} ${item.info || '正常资源'}
${item.url}
复制 新标签打开 下载 转换
`; list.appendChild(div); div.querySelector('.cp').onclick = () => mgmapi.copyText(item.url); div.querySelector('.open-btn').onclick = () => mgmapi.openInTab(item.url); div.querySelector('.download-btn').onclick = function () { mgmapi.downloadFile({ url: this.dataset.url, name: this.dataset.name }); }; div.querySelector('.convert-btn').onclick = () => handleConversion(item.url); div.querySelector('.url').onclick = function () { this.classList.toggle('exp'); }; } async function addItem({ type, url }) { if (!url) return; const fixUrlStr = fixUrl(url); if (shownUrls.has(fixUrlStr)) return; if (filteredUrlSet.has(fixUrlStr)) return; if (!enabledFormats[type]) { filteredHideList.push({ type, url: fixUrlStr }); filteredUrlSet.add(fixUrlStr); filterCountNum++; updateFormatCountDisplay(); updateBadge(); return; } shownUrls.add(fixUrlStr); formatCounts[type]++; const resInfo = await getInfoByUrl(fixUrlStr, type); const itemData = { type, url: fixUrlStr, info: resInfo.info, size: resInfo.size, realUrl: resInfo.realUrl }; if (!checkSizeFilter(resInfo.size)) { filteredHideList.push(itemData); filteredUrlSet.add(fixUrlStr); filterCountNum++; updateFormatCountDisplay(); updateBadge(); return; } if (isInvalidItem(itemData)) { invalidLinkCount++; updateFormatCountDisplay(); } allItems.push(itemData); playRingAnim(url); renderFilterList(); updateBadge(); updateFormatCountDisplay(); } function toggleFormatSettingsPanel() { isFormatSettingsOpen = !isFormatSettingsOpen; if (isFormatSettingsOpen) { createFormatSettingsPanel(); } else { const p = document.querySelector('.format-settings-panel'); if (p) p.remove(); } } function createFormatSettingsPanel() { let old = document.querySelector('.format-settings-panel'); if (old) old.remove(); const panel = document.createElement('div'); panel.className = 'format-settings-panel'; panel.style.zIndex = '2147483647'; panel.innerHTML = `
格式过滤设置
全部全选 全部取消
视频格式
全选 取消
音频格式
全选 取消
图片格式
全选 取消
其他格式
全选 取消
启用大小过滤
最小KB:
最大KB:
保存设置
`; document.body.appendChild(panel); panel.querySelector('.format-settings-close').onclick = () => { document.querySelectorAll('.format-checkbox-container input[type="checkbox"]').forEach(ck => { const type = ck.id.replace('fmt_', ''); enabledFormats[type] = ck.checked; }); mgmapi.setValue('formatEnabledFormats', { ...enabledFormats }); const sizeEnable = document.querySelector('#sizeFilterEnable'); const minInput = document.querySelector('#minSizeInput'); const maxInput = document.querySelector('#maxSizeInput'); if (sizeEnable && minInput && maxInput) { sizeFilterSettings.enabled = sizeEnable.checked; sizeFilterSettings.minSize = parseInt(minInput.value) || 0; sizeFilterSettings.maxSize = parseInt(maxInput.value) || 0; mgmapi.setValue('sizeFilterEnable', sizeFilterSettings.enabled); mgmapi.setValue('sizeFilterMin', sizeFilterSettings.minSize); mgmapi.setValue('sizeFilterMax', sizeFilterSettings.maxSize); } panel.remove(); isFormatSettingsOpen = false; }; fillFormatGroup('video-format-group', ['MP4', 'M3U8', 'TS', 'FLV', 'MKV', 'WEBM', 'AVI', 'MOV', 'WMV', 'VIDEO']); fillFormatGroup('audio-format-group', ['AAC', 'MP3', 'AUDIO']); fillFormatGroup('image-format-group', ['JPG', 'PNG', 'GIF', 'BMP', 'WEBP', 'SVG', 'ICO', 'TIFF', 'HEIC', 'AVIF', 'JFIF', 'PJPEG', 'JXR', 'IMAGE']); fillFormatGroup('other-format-group', ['PDF', 'ZIP', 'RAR', 'APK', 'EXE', 'OTHER']); bindGroupCheck('check-all-video', 'video-format-group', true); bindGroupCheck('uncheck-all-video', 'video-format-group', false); bindGroupCheck('check-all-audio', 'audio-format-group', true); bindGroupCheck('uncheck-all-audio', 'audio-format-group', false); bindGroupCheck('check-all-image', 'image-format-group', true); bindGroupCheck('uncheck-all-image', 'image-format-group', false); bindGroupCheck('check-all-other', 'other-format-group', true); bindGroupCheck('uncheck-all-other', 'other-format-group', false); document.getElementById('allCheck').onclick = () => { document.querySelectorAll('.format-checkbox-item').forEach(item => { const type = item.querySelector('.name').textContent; enabledFormats[type] = true; item.classList.add('checked'); item.querySelector('.mark').textContent = '√'; }); mgmapi.setValue('formatEnabledFormats', { ...enabledFormats }); msg("✅ 全部格式已全选并保存"); }; document.getElementById('allUncheck').onclick = () => { document.querySelectorAll('.format-checkbox-item').forEach(item => { const type = item.querySelector('.name').textContent; enabledFormats[type] = false; item.classList.remove('checked'); item.querySelector('.mark').textContent = '□'; }); mgmapi.setValue('formatEnabledFormats', { ...enabledFormats }); msg("✅ 全部格式已取消并保存"); }; document.getElementById('saveSizeBtn').onclick = function () { const sizeEnable = document.querySelector('#sizeFilterEnable'); const minInput = document.querySelector('#minSizeInput'); const maxInput = document.querySelector('#maxSizeInput'); sizeFilterSettings.enabled = sizeEnable.checked; sizeFilterSettings.minSize = parseInt(minInput.value) || 0; sizeFilterSettings.maxSize = parseInt(maxInput.value) || 0; mgmapi.setValue('sizeFilterEnable', sizeFilterSettings.enabled); mgmapi.setValue('sizeFilterMin', sizeFilterSettings.minSize); mgmapi.setValue('sizeFilterMax', sizeFilterSettings.maxSize); msg("✅ 大小过滤设置已保存"); panel.remove(); isFormatSettingsOpen = false; }; } function fillFormatGroup(wrapId, typeList) { const wrap = document.getElementById(wrapId); typeList.forEach(type => { if (enabledFormats[type] === undefined) { enabledFormats[type] = true; } const item = document.createElement('div'); item.className = 'format-checkbox-item ' + (enabledFormats[type] ? 'checked' : ''); item.innerHTML = ` ${enabledFormats[type] ? '√' : '□'} ${type} `; wrap.appendChild(item); item.onclick = () => { enabledFormats[type] = !enabledFormats[type]; item.classList.toggle('checked', enabledFormats[type]); item.querySelector('.mark').textContent = enabledFormats[type] ? '√' : '□'; mgmapi.setValue('formatEnabledFormats', { ...enabledFormats }); }; }); } function bindGroupCheck(btnClass, wrapId, checkState) { const btn = document.querySelector(`.${btnClass}`); btn.onclick = () => { const wrap = document.getElementById(wrapId); wrap.querySelectorAll('.format-checkbox-item').forEach(item => { const type = item.querySelector('.name').textContent; enabledFormats[type] = checkState; item.classList.toggle('checked', checkState); item.querySelector('.mark').textContent = checkState ? '√' : '□'; }); mgmapi.setValue('formatEnabledFormats', { ...enabledFormats }); msg(checkState ? "✅ 已全选" : "✅ 已取消全选"); }; } function playRingAnim(url) { const ballIcon = document.querySelector('.icon'); if (!ballIcon) return; if (ballIcon._starTimer) clearTimeout(ballIcon._starTimer); let oldStarWrap = ballIcon.querySelector('.star-orbit-wrap'); if (oldStarWrap) oldStarWrap.remove(); let starWrap = document.createElement('div'); starWrap.className = "star-orbit-wrap circular-ring"; starWrap.style.animation = "starRotate 7s linear infinite"; // 不修改父球位置,只加外圈特效 ballIcon.appendChild(starWrap); let starType = "video"; let lowUrl = url.toLowerCase(); if (lowUrl.includes('.mp3') || lowUrl.includes('.aac')) starType = "audio"; else if (lowUrl.includes('.jpg') || lowUrl.includes('.png') || lowUrl.includes('.gif')) starType = "image"; else if (lowUrl.includes('.pdf')) starType = "doc"; else if (lowUrl.includes('.zip') || lowUrl.includes('.rar')) starType = "zip"; let starText = ['★', '✦', '✧', '☆', '✩', '✪', '✫', '✬']; for (let i = 0; i < 8; i++) { let star = document.createElement('span'); star.className = `star-item ${starType}`; star.innerText = starText[i]; star.style.position = "absolute"; star.style.left = "50%"; star.top = "0"; star.style.fontSize = "11px"; star.style.transformOrigin = "center 26px"; star.style.transform = `rotate(${i * 45}deg)`; star.style.animation = `starTwinkle 1.6s ease infinite ${i * 0.12}s`; starWrap.appendChild(star); } ballIcon._starTimer = setTimeout(() => { if (starWrap) starWrap.remove(); }, 1500); } //手机滑动隐藏 互不冲突版 let scrollTimer; document.addEventListener('touchmove', ()=>{ const ic = document.querySelector('.icon'); ic.style.transform = "translateY(-50%) translateX(45px) scale(0.5)"; ic.style.opacity = 0.14; clearTimeout(scrollTimer); }); document.addEventListener('touchend', ()=>{ scrollTimer = setTimeout(()=>{ const ic = document.querySelector('.icon'); ic.style.transform = "translateY(-50%)"; ic.style.opacity = 0.8; }, 1000); }); async function startInit() { try { await loadUserSettings(); createHideFilterPanel(); initUI(); initDetect(); } catch (e) { console.error('[Sniffer Init Error]', e); } } startInit(); })();