---
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 = ``;
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 = `
`;
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 = `
全部全选
全部取消
`;
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();
})();