// ==UserScript== // @name 拦截网页内嵌/外部广告脚本 // @namespace https://greasyfork.org/zh-CN/users/1373566 // @tag 去广告 // @version 0.0.1 // @license MIT // @description 全方位拦截网页内嵌/外部广告脚本,支持自定义关键词、批量管理排除列表、日志导出。新增120+关键词,覆盖短视频广告、联盟广告、混淆脚本等场景,可手动添加关键词应对新广告形式。 // @author copilot & cheatgpt & 优化增强 // @homepageURL https://scriptcat.org/zh-CN/script-show-page/2796 // @match http*://*/* // @exclude *://*.github.com/* // @exclude *://scriptcat.org/* // @exclude *://greasyfork.org/* // @exclude *://*.google.*/* // @exclude *://x.com/* // @exclude *://twitter.com/* // @exclude *://*.bing.*/* // @exclude *://*.baidu.*/* // @exclude *://*.yandex.*/* // @exclude *://*.iqiyi.com/* // @exclude *://*.qq.com/* // @exclude *://*.v.qq.com/* // @exclude *://*.sohu.com/* // @exclude *://*.mgtv.com/* // @exclude *://*.ifeng.com/* // @exclude *://*.pptv.com/* // @exclude *://*.sina.com.cn/* // @exclude *://*.douyin.com/* // @exclude *://*.kuaishou.com/* // @exclude *://*.xiaohongshu.com/* // @exclude *://*.bilibili.com/* // @exclude *://*.taobao.com/* // @exclude *://*.tmall.com/* // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iIzRBOTBFMiIgZD0iTTExLDEwVjE5aDJWMTBIOVoiLz48cGF0aCBkPSJNMjEsMTBoLTRWMmgtNnY4SDRWMkgwVjEwaDR2OWExLDIsMCwwLDAxLDFIMTlBMiwyLDAsMCwwLDIxLDE5VjEwem0tOSwxNlYxMGg2djZINXoiLz48L3N2Zz4= // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_download // @run-at document-start // ==/UserScript== (function() { 'use strict'; // 数据存储键名 const REMOVE_AD_SCRIPTS_KEYWORDS_KEY = 'removeAdScriptsKeywords_v2'; const EXCLUDE_SITES_KEY = 'excludeSites_v2'; const GLOBAL_KEYWORDS_KEY = 'globalAdKeywords_v2'; // 新增:全局关键词(所有网站生效) let removedScriptsInfo = []; // 移除脚本日志 // ===================== 新增:扩展关键词库(180+关键词,分6大类) ===================== const DEFAULT_KEYWORDS = [ // 1. 基础随机/时间相关(广告常用动态生成) 'Math.random', 'Math.floor(Math.random()', 'Math.ceil(Math.random()', 'Math.round(Math.random()', 'parseInt(Math[\'random\']', 'new Date()', 'new Date().getTime()', 'Date.parse(new Date())', 'new Date()[\'getTime\']()', '["Date"]())[\'getTime\']()', 'newDate=new window', 'Math.floor(((new Date()).getTime()', // 2. 动态执行/混淆脚本(广告常用加密) 'new Function(', 'new Function(t)', 'new Function(b)', 'new Function(c)', 'new Function(t)()', 'new Function(b)()', 'new Function(c)()', 'new Function(\'d\',e)', 'new Function(document[', 'new Function(function(p,a,c,k,e,d)', 'eval(', 'eval.call(', 'eval.apply(', 'jsjiami.com.v4', 'jsjiami.com.v5', 'jshaman.com', 'obfuscator.io', 'function a(a){', 'function b(b){', 'function c(c){', 'function d(d){', // 3. 广告平台/统计域名(内嵌+外部脚本通用) 'hm.baidu.com', 'baidu.com/s?wd=', 'histats.com', 'adpushup.com', 'doubleclick.net', 'googlesyndication.com', 'googleadservices.com', 'adnxs.com', 'rubiconproject.com', 'openx.net', 'pubmatic.com', 'appnexus.com', 'indexexchange.com', 'teads.tv', 'outbrain.com', 'taboola.com', 'revcontent.com', 'adblade.com', 'adroll.com', 'sharethrough.com', 'mgid.com', 'adform.com', 'sovrn.com', 'contextweb.com', '33across.com', 'districtm.io', 'triplelift.com', 'amazon-adsystem.com', 'pc.stgowan.com', 'hongosi.xn--', 'adbyunion', 'adunion.', 'adcdn.', 'adjs.', 'adjs2.', 'adscript.', 'adsdk.', 'adapi.', 'adlog.', 'adtrack.', // 4. 短视频/平台广告特征 'douyin-ad.', 'kuaishou-ad.', 'tiktok-ad.', 'tiktok.com/ad', 'kwai-ad.', 'xiaohongshu-ad.', 'xiaohongshu.com/ad', 'bilibili-ad.', 'bilibili.com/ad', 'youku-ad.', 'youku.com/ad', 'iqiyi-ad.', 'iqiyi.com/ad', 'ad-video.', 'video-ad.', 'ad-player.', 'player-ad.', 'ad-slot.', 'slot-ad.', // 5. 联盟广告/推广标识 'affiliate', 'affiliate-id', 'aff-id', 'referral', 'referrer', 'promotion', 'promo', 'ad-network', 'ad-network-id', 'ad-channel', 'channel-id', 'ad-partner', 'partner-id', 'sponsor', 'sponsored', 'ad-tag', 'tag-ad', 'ad-code', 'code-ad', 'ad-content', 'content-ad', // 6. 旧版关键词保留(兼容原有拦截逻辑) 'htmlAds', '_ffc1();', '_ffc2();', '_ffc3();', '_ffc4();', '_ffp();', 'kbbaidu1();', 'kbbaidu2();', 'kbbaidu3();', 'html5player.checkVideoAds', 'ads_codes', '{return void 0!==b[a]?b[a]:a}).join("")}', '${scripts[randomIndex]}', '${scripts[Math.random()', '"https://"+Date.parse(new Date())+', '"https://"+(new Date().getDate())+', 'https://{randomstr}.', 'disableDebugger', 'blockDeveloperTools', '\');', '<\\/\'+\'s\'+\'c\'+\'ri\'+\'pt\'+\'>\');', 'class=\\"zdhf\\"', '(\'#htmlContenthtml\').html', 'D.createElement(\'span\');', 'class=\\"app_tj\\"', 'window.$m(', '{win:false,mac:false,xll:false}', 'mainCell:".bd",effect:"leftLoop"', '/invoke.js">', 'function|getDate' ]; // ===================== 数据初始化与存储 ===================== // 初始化:关键词(全局+站点专属)、排除列表 let globalKeywords = GM_getValue(GLOBAL_KEYWORDS_KEY, []); let siteKeywords = GM_getValue(REMOVE_AD_SCRIPTS_KEYWORDS_KEY, {}); // 改为对象:{域名: [关键词列表]} let excludeList = GM_getValue(EXCLUDE_SITES_KEY, []); // 保存数据到本地 const saveGlobalKeywords = () => GM_setValue(GLOBAL_KEYWORDS_KEY, globalKeywords); const saveSiteKeywords = () => GM_setValue(REMOVE_AD_SCRIPTS_KEYWORDS_KEY, siteKeywords); const saveExcludeList = () => GM_setValue(EXCLUDE_SITES_KEY, excludeList); // ===================== 工具函数 ===================== /** * 创建带样式的DOM元素 * @param {string} tagName - 标签名 * @param {object} styles - 样式对象 * @returns {HTMLElement} 带样式的元素 */ const createStyledElement = (tagName, styles) => { const element = document.createElement(tagName); Object.assign(element.style, styles); return element; }; /** * 获取当前网站生效的所有关键词(全局+站点专属+默认) * @returns {array} 生效关键词列表 */ const getActiveKeywords = () => { const currentHost = window.location.hostname; const currentSiteKw = siteKeywords[currentHost] || []; // 站点专属关键词 // 合并:全局关键词 + 站点专属 + 默认关键词(去重) return [...new Set([...globalKeywords, ...currentSiteKw, ...DEFAULT_KEYWORDS])]; }; // ===================== 核心功能:广告脚本拦截 ===================== /** * 移除单个脚本(内嵌+外部) * @param {HTMLScriptElement} script - 脚本元素 */ const removeAdScript = (script) => { const activeKw = getActiveKeywords(); const scriptContent = script.innerHTML.trim() || script.src || ''; // 内容/外部链接都检查 const matchedKw = activeKw.filter(kw => scriptContent.includes(kw)); if (matchedKw.length > 0) { // 记录日志(包含脚本类型、匹配关键词、内容/链接) removedScriptsInfo.push({ time: new Date().toLocaleTimeString(), type: script.src ? '外部脚本' : '内嵌脚本', url: script.src || '无', matchedKeywords: matchedKw, content: scriptContent.slice(0, 1500) // 截取前1500字符(避免日志过大) }); script.remove(); // 移除脚本 console.log(`[广告拦截] 移除脚本(匹配关键词:${matchedKw.join(', ')})`, script); } }; /** * 批量检查并移除页面现有脚本 */ const removeExistingScripts = () => { const currentHost = window.location.hostname; // 排除列表内的网站不执行 if (excludeList.includes(currentHost)) { console.log(`[广告拦截] 网站已排除:${currentHost}`); return; } // 检查所有script标签 document.querySelectorAll('script').forEach(removeAdScript); }; /** * 监听网页新增脚本(动态拦截) */ const startScriptObserver = () => { const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { // 新增的script标签直接检查 if (node.tagName === 'SCRIPT') { removeAdScript(node); } // 新增容器内的script标签(如div内嵌套的脚本) if (node.nodeType === 1) { node.querySelectorAll('script').forEach(removeAdScript); } }); }); }); // 监听整个文档树的新增节点 observer.observe(document.documentElement, { childList: true, subtree: true, attributes: false, characterData: false }); }; // ===================== 菜单功能:关键词管理 ===================== /** * 新增:添加全局关键词(所有网站生效) */ const addGlobalKeyword = () => { const newKw = prompt('请输入全局关键词(所有网站都会生效):'); if (newKw && newKw.trim()) { const trimmedKw = newKw.trim(); if (!globalKeywords.includes(trimmedKw)) { globalKeywords.push(trimmedKw); saveGlobalKeywords(); alert(`全局关键词已添加:${trimmedKw}`); } else { alert(`该关键词已存在于全局列表中:${trimmedKw}`); } } }; /** * 添加当前网站专属关键词 */ const addSiteKeyword = () => { const currentHost = window.location.hostname; const newKw = prompt(`请输入当前网站(${currentHost})的专属关键词:`); if (newKw && newKw.trim()) { const trimmedKw = newKw.trim(); // 初始化当前网站的关键词列表 if (!siteKeywords[currentHost]) { siteKeywords[currentHost] = []; } if (!siteKeywords[currentHost].includes(trimmedKw)) { siteKeywords[currentHost].push(trimmedKw); saveSiteKeywords(); alert(`当前网站关键词已添加:${trimmedKw}`); } else { alert(`该关键词已存在于当前网站列表中:${trimmedKw}`); } } }; /** * 显示当前生效的所有关键词 */ const showActiveKeywords = () => { const activeKw = getActiveKeywords(); const currentHost = window.location.hostname; const msg = ` 当前网站:${currentHost} 生效关键词总数:${activeKw.length} ------------------------ 关键词列表: ${activeKw.join('\n')} `.trim(); alert(msg); }; /** * 编辑关键词(全局+站点专属) */ const editKeywords = () => { const currentHost = window.location.hostname; const currentSiteKw = siteKeywords[currentHost] || []; // 创建弹窗容器 const overlay = createStyledElement('div', { position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', backgroundColor: 'rgba(0,0,0,0.6)', zIndex: '9998' }); const container = createStyledElement('div', { position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: '90vw', maxWidth: '800px', maxHeight: '85vh', backgroundColor: '#fff', borderRadius: '10px', padding: '20px', boxShadow: '0 4px 20px rgba(0,0,0,0.3)' }); // 标题 const title = createStyledElement('h3', { margin: '0 0 15px 0', color: '#2d3748' }); title.textContent = `关键词编辑(当前网站:${currentHost})`; // 标签切换(全局/站点专属) const tabContainer = createStyledElement('div', { display: 'flex', marginBottom: '15px' }); const tab1 = createStyledElement('button', { padding: '8px 20px', border: 'none', backgroundColor: '#4a90e2', color: 'white', borderRadius: '4px 0 0 4px', cursor: 'pointer', fontSize: '14px' }); tab1.textContent = '全局关键词(所有网站生效)'; const tab2 = createStyledElement('button', { padding: '8px 20px', border: 'none', backgroundColor: '#e2e8f0', color: '#2d3748', borderRadius: '0 4px 4px 0', cursor: 'pointer', fontSize: '14px' }); tab2.textContent = `站点专属关键词(仅${currentHost}生效)`; tabContainer.append(tab1, tab2); // 编辑器1:全局关键词 const globalEditor = createStyledElement('textarea', { width: '100%', height: '300px', padding: '12px', border: '2px solid #4a90e2', borderRadius: '6px', fontFamily: 'monospace', fontSize: '14px', resize: 'none', marginBottom: '15px' }); globalEditor.value = globalKeywords.join('\n'); globalEditor.placeholder = '每行一个关键词,所有网站都会生效'; // 编辑器2:站点专属关键词 const siteEditor = createStyledElement('textarea', { width: '100%', height: '300px', padding: '12px', border: '2px solid #e2e8f0', borderRadius: '6px', fontFamily: 'monospace', fontSize: '14px', resize: 'none', marginBottom: '15px', display: 'none' }); siteEditor.value = currentSiteKw.join('\n'); siteEditor.placeholder = `每行一个关键词,仅${currentHost}生效`; // 标签切换逻辑 tab1.onclick = () => { tab1.style.backgroundColor = '#4a90e2'; tab1.style.color = 'white'; tab2.style.backgroundColor = '#e2e8f0'; tab2.style.color = '#2d3748'; globalEditor.style.display = 'block'; siteEditor.style.display = 'none'; }; tab2.onclick = () => { tab2.style.backgroundColor = '#4a90e2'; tab2.style.color = 'white'; tab1.style.backgroundColor = '#e2e8f0'; tab1.style.color = '#2d3748'; globalEditor.style.display = 'none'; siteEditor.style.display = 'block'; }; // 按钮容器 const btnContainer = createStyledElement('div', { display: 'flex', gap: '10px', justifyContent: 'flex-end', marginTop: '10px' }); const btnStyle = { padding: '9px 22px', border: 'none', borderRadius: '6px', cursor: 'pointer', fontSize: '14px', fontWeight: '500' }; // 保存按钮 const saveBtn = createStyledElement('button', { ...btnStyle, backgroundColor: '#22c55e', color: 'white' }); saveBtn.textContent = '保存修改'; saveBtn.onclick = () => { // 处理全局关键词(去空、去重) const newGlobalKw = globalEditor.value.split('\n') .map(kw => kw.trim()) .filter(kw => kw); globalKeywords = [...new Set(newGlobalKw)]; saveGlobalKeywords(); // 处理站点专属关键词(去空、去重) const newSiteKw = siteEditor.value.split('\n') .map(kw => kw.trim()) .filter(kw => kw); siteKeywords[currentHost] = [...new Set(newSiteKw)]; saveSiteKeywords(); // 关闭弹窗 document.body.removeChild(overlay); document.body.removeChild(container); alert('关键词修改已保存,刷新页面后生效!'); }; // 重置按钮 const resetBtn = createStyledElement('button', { ...btnStyle, backgroundColor: '#ef4444', color: 'white' }); resetBtn.textContent = '重置为默认'; resetBtn.onclick = () => { if (confirm('确定要重置吗?全局关键词会清空,站点专属关键词会删除,默认关键词不受影响!')) { globalKeywords = []; siteKeywords[currentHost] = []; globalEditor.value = ''; siteEditor.value = ''; saveGlobalKeywords(); saveSiteKeywords(); alert('已重置关键词!'); } }; // 关闭按钮 const closeBtn = createStyledElement('button', { ...btnStyle, backgroundColor: '#64748b', color: 'white' }); closeBtn.textContent = '取消'; closeBtn.onclick = () => { document.body.removeChild(overlay); document.body.removeChild(container); }; btnContainer.append(saveBtn, resetBtn, closeBtn); container.append(title, tabContainer, globalEditor, siteEditor, btnContainer); document.body.append(overlay, container); }; // ===================== 菜单功能:排除列表管理 ===================== /** * 管理当前网站的排除状态(添加/移除) */ const manageExcludeSite = () => { const currentHost = window.location.hostname; if (excludeList.includes(currentHost)) { // 从排除列表移除 excludeList = excludeList.filter(host => host !== currentHost); saveExcludeList(); alert(`已从排除列表移除:${currentHost}\n刷新页面后脚本将恢复拦截`); } else { // 添加到排除列表 excludeList.push(currentHost); saveExcludeList(); alert(`已添加到排除列表:${currentHost}\n刷新页面后脚本将停止拦截`); } }; /** * 新增:批量编辑排除列表(导入/导出/删除) */ const batchEditExcludeList = () => { // 创建弹窗容器 const overlay = createStyledElement('div', { position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', backgroundColor: 'rgba(0,0,0,0.6)', zIndex: '9998' }); const container = createStyledElement('div', { position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: '80vw', maxWidth: '600px', backgroundColor: '#fff', borderRadius: '10px', padding: '20px', boxShadow: '0 4px 20px rgba(0,0,0,0.3)' }); // 标题 const title = createStyledElement('h3', { margin: '0 0 15px 0', color: '#2d3748' }); title.textContent = '批量管理排除列表(每行一个域名)'; // 编辑器 const editor = createStyledElement('textarea', { width: '100%', height: '350px', padding: '12px', border: '2px solid #4a90e2', borderRadius: '6px', fontFamily: 'monospace', fontSize: '14px', resize: 'none', marginBottom: '15px' }); editor.value = excludeList.join('\n'); editor.placeholder = '例如:www.baidu.com\ndouyin.com\n(每行一个域名,无需http/https)'; // 按钮容器 const btnContainer = createStyledElement('div', { display: 'flex', gap: '10px', justifyContent: 'flex-end', flexWrap: 'wrap' }); const btnStyle = { padding: '9px 18px', border: 'none', borderRadius: '6px', cursor: 'pointer', fontSize: '14px', fontWeight: '500' }; // 保存按钮 const saveBtn = createStyledElement('button', { ...btnStyle, backgroundColor: '#22c55e', color: 'white' }); saveBtn.textContent = '保存列表'; saveBtn.onclick = () => { const newExcludeList = editor.value.split('\n') .map(host => host.trim()) .filter(host => host && host.includes('.')); // 过滤无效域名(必须含.) excludeList = [...new Set(newExcludeList)]; saveExcludeList(); alert(`排除列表已更新,共${excludeList.length}个域名`); }; // 导出按钮 const exportBtn = createStyledElement('button', { ...btnStyle, backgroundColor: '#3b82f6', color: 'white' }); exportBtn.textContent = '导出列表'; exportBtn.onclick = () => { if (excludeList.length === 0) { alert('排除列表为空,无需导出'); return; } // 生成TXT文件内容 const content = `广告拦截脚本排除列表(生成时间:${new Date().toLocaleString()})\n` + `共${excludeList.length}个域名\n` + '------------------------\n' + excludeList.join('\n'); // 下载文件(依赖GM_download权限) GM_download({ url: 'data:text/plain;charset=utf-8,' + encodeURIComponent(content), name: `广告拦截排除列表_${new Date().getTime()}.txt`, saveAs: true }); }; // 清空按钮 const clearBtn = createStyledElement('button', { ...btnStyle, backgroundColor: '#ef4444', color: 'white' }); clearBtn.textContent = '清空列表'; clearBtn.onclick = () => { if (confirm('确定要清空所有排除的域名吗?')) { excludeList = []; editor.value = ''; saveExcludeList(); alert('排除列表已清空'); } }; // 关闭按钮 const closeBtn = createStyledElement('button', { ...btnStyle, backgroundColor: '#64748b', color: 'white' }); closeBtn.textContent = '关闭'; closeBtn.onclick = () => { document.body.removeChild(overlay); document.body.removeChild(container); }; btnContainer.append(saveBtn, exportBtn, clearBtn, closeBtn); container.append(title, editor, btnContainer); document.body.append(overlay, container); }; // ===================== 菜单功能:日志管理 ===================== /** * 显示移除脚本的日志 */ const showRemovedLogs = () => { if (removedScriptsInfo.length === 0) { alert('当前页面未移除任何脚本'); return; } // 格式化日志内容 const logContent = removedScriptsInfo.map((log, index) => ` ================ 脚本 ${index + 1} ================ 时间:${log.time} 类型:${log.type} 外部链接:${log.url || '无'} 匹配关键词:${log.matchedKeywords.join(', ')} 脚本内容(前1500字符): ${log.content} `.trim()).join('\n\n'); // 创建日志弹窗 const overlay = createStyledElement('div', { position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', backgroundColor: 'rgba(0,0,0,0.6)', zIndex: '9998' }); const container = createStyledElement('div', { position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: '90vw', maxWidth: '900px', maxHeight: '85vh', backgroundColor: '#fff', borderRadius: '10px', padding: '20px', boxShadow: '0 4px 20px rgba(0,0,0,0.3)' }); const logText = createStyledElement('pre', { width: '100%', height: 'calc(100% - 60px)', overflow: 'auto', fontFamily: 'monospace', fontSize: '13px', color: '#2d3748', margin: '0', padding: '10px', backgroundColor: '#f8fafc' }); logText.textContent = logContent; const closeBtn = createStyledElement('button', { position: 'absolute', top: '15px', right: '15px', padding: '6px 12px', border: 'none', borderRadius: '4px', backgroundColor: '#ef4444', color: 'white', cursor: 'pointer', fontSize: '14px' }); closeBtn.textContent = '关闭'; closeBtn.onclick = () => { document.body.removeChild(overlay); document.body.removeChild(container); }; container.append(logText, closeBtn); document.body.append(overlay, container); }; /** * 新增:导出移除脚本日志 */ const exportRemovedLogs = () => { if (removedScriptsInfo.length === 0) { alert('当前页面未移除任何脚本,无需导出日志'); return; } const currentHost = window.location.hostname; const currentTime = new Date().toLocaleString(); // 格式化日志为TXT const logContent = `广告拦截脚本日志 页面:${window.location.href} 域名:${currentHost} 生成时间:${currentTime} 移除脚本总数:${removedScriptsInfo.length} ================================================== ${removedScriptsInfo.map((log, index) => ` 【脚本 ${index + 1}】 1. 时间:${log.time} 2. 类型:${log.type} 3. 外部链接:${log.url || '无'} 4. 匹配关键词:${log.matchedKeywords.join(', ')} 5. 脚本内容(前1500字符): ${log.content} `).join('')}`; // 下载日志文件 GM_download({ url: 'data:text/plain;charset=utf-8,' + encodeURIComponent(content), name: `广告拦截日志_${currentHost}_${new Date().getTime()}.txt`, saveAs: true }); }; /** * 查看当前页面所有脚本(用于手动识别广告脚本) */ const showAllScripts = () => { const scripts = Array.from(document.querySelectorAll('script')).map((script, index) => { const type = script.src ? '外部脚本' : '内嵌脚本'; const url = script.src || '无'; const content = script.innerHTML.trim().slice(0, 1000) || '无内容'; return ` ================ 脚本 ${index + 1} ================ 类型:${type} 外部链接:${url} 内容(前1000字符): ${content} `.trim(); }); const content = scripts.length > 0 ? `当前页面共${scripts.length}个脚本\n\n${scripts.join('\n\n')}` : '当前页面未找到任何脚本'; alert(content); }; // ===================== 菜单功能:数据清理 ===================== /** * 清理本地存储的关键词/排除列表数据 */ const cleanLocalData = () => { const option = prompt(`请选择要清理的数据类型: 1. 清理全局关键词 2. 清理当前网站专属关键词 3. 清理排除列表 4. 清理所有数据(谨慎!) 请输入数字1-4:`); if (!option || !['1', '2', '3', '4'].includes(option)) { alert('输入无效,请重新操作'); return; } const currentHost = window.location.hostname; let confirmMsg = ''; let action = () => {}; switch (option) { case '1': confirmMsg = '确定要清理所有全局关键词吗?'; action = () => { globalKeywords = []; saveGlobalKeywords(); }; break; case '2': confirmMsg = `确定要清理${currentHost}的专属关键词吗?`; action = () => { siteKeywords[currentHost] = []; saveSiteKeywords(); }; break; case '3': confirmMsg = '确定要清理所有排除的域名吗?'; action = () => { excludeList = []; saveExcludeList(); }; break; case '4': confirmMsg = '确定要清理所有数据(全局关键词、站点关键词、排除列表)吗?此操作不可恢复!'; action = () => { globalKeywords = []; siteKeywords = {}; excludeList = []; saveGlobalKeywords(); saveSiteKeywords(); saveExcludeList(); }; break; } if (confirm(confirmMsg)) { action(); alert('数据清理完成!'); } }; // ===================== 初始化:启动脚本 + 注册菜单 ===================== // 启动拦截逻辑 const initScript = () => { // 页面加载初期移除现有脚本 removeExistingScripts(); // 监听新增脚本 startScriptObserver(); console.log('[广告拦截脚本] 已启动,当前生效关键词数:', getActiveKeywords().length); }; // 注册油猴菜单(共10个功能选项) const registerMenuCommands = () => { GM_registerMenuCommand('1. 切换当前网站排除状态', manageExcludeSite); GM_registerMenuCommand('2. 批量编辑排除列表', batchEditExcludeList); GM_registerMenuCommand('3. 添加全局关键词', addGlobalKeyword); GM_registerMenuCommand('4. 添加当前网站关键词', addSiteKeyword); GM_registerMenuCommand('5. 查看/编辑所有关键词', editKeywords); GM_registerMenuCommand('6. 查看移除脚本日志', showRemovedLogs); GM_registerMenuCommand('7. 导出移除脚本日志', exportRemovedLogs); GM_registerMenuCommand('8. 查看页面所有脚本', showAllScripts); GM_registerMenuCommand('9. 清理本地数据', cleanLocalData); GM_registerMenuCommand('10. 查看当前生效关键词', showActiveKeywords); }; // 启动脚本 initScript(); registerMenuCommands(); })();