// ==UserScript== // @name Porn Blocker | 色情内容过滤器 // @name:en Porn Blocker // @name:zh-CN 色情内容过滤器 // @name:zh-TW 色情內容過濾器 // @name:zh-HK 色情內容過濾器 // @name:ja アダルトコンテンツブロッカー // @name:ko 성인 컨텐츠 차단기 // @name:ru Блокировщик порнографии // @namespace https://noctiro.moe // @version 2.0.8 // @description A powerful content blocker that helps protect you from inappropriate websites. Features: Auto-detection of adult content, Multi-language support, Smart scoring system, Safe browsing protection. // @description:en A powerful content blocker that helps protect you from inappropriate websites. Features: Auto-detection of adult content, Multi-language support, Smart scoring system, Safe browsing protection. // @description:zh-CN 强大的网页过滤工具,帮助你远离不良网站。功能特点:智能检测色情内容,多语言支持,评分系统,安全浏览保护,支持自定义过滤规则。为了更好的网络环境,从我做起。 // @description:zh-TW 強大的網頁過濾工具,幫助你遠離不良網站。功能特點:智能檢測色情內容,多語言支持,評分系統,安全瀏覽保護,支持自定義過濾規則。為了更好的網絡環境,從我做起。 // @description:zh-HK 強大的網頁過濾工具,幫助你遠離不良網站。功能特點:智能檢測色情內容,多語言支持,評分系統,安全瀏覽保護,支持自定義過濾規則。為了更好的網絡環境,從我做起。 // @description:ja アダルトコンテンツを自動的にブロックする強力なツールです。機能:アダルトコンテンツの自動検出、多言語対応、スコアリングシステム、カスタマイズ可能なフィルタリング。より良いインターネット環境のために。 // @description:ko 성인 컨텐츠를 자동으로 차단하는 강력한 도구입니다. 기능: 성인 컨텐츠 자동 감지, 다국어 지원, 점수 시스템, 안전 브라우징 보호, 맞춤형 필터링 규칙。 // @description:ru Мощный инструмент для блокировки неприемлемого контента. Функции: автоматическое определение, многоязычная поддержка, система оценки, настраиваемые правила фильтрации。 // @license Apache-2.0 // @match *://*/* // @run-at document-start // @run-at document-end // @run-at document-idle // @grant none // @grant chrome.storage.sync // @grant chrome.storage.local // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 多语言支持 const i18n = { 'en': { title: '🚫 Access Blocked', message: 'This webpage has been identified as inappropriate content.', redirect: 'Redirecting in 4 seconds...', footer: 'Stay healthy · Stay away from harmful content' }, 'zh-CN': { title: '🚫 访问已被拦截', message: '该网页已被识别为不健康内容。', redirect: '4 秒后自动跳转...', footer: '注意身心健康 · 远离不良网站' }, 'zh-TW': { title: '🚫 訪問已被攔截', message: '該網頁已被識別為不健康內容。', redirect: '4 秒後自動跳轉...', footer: '注意身心健康 · 遠離不良網站' }, 'zh-HK': { title: '🚫 訪問已被攔截', message: '該網頁已被識別為不健康內容。', redirect: '4 秒後自動跳轉...', footer: '注意身心健康 · 遠離不良網站' }, 'ja': { title: '🚫 アクセスがブロックされました', message: 'このページは不適切なコンテンツとして識別されました。', redirect: '4 秒後にリダイレクトします...', footer: '健康に注意 · 有害サイトに近づかない' }, 'ko': { title: '🚫 접근이 차단됨', message: '이 웹페이지가 부적절한 콘텐츠로 식별되었습니다.', redirect: '4초 후 자동으로 이동됩니다...', footer: '건강 관리 · 유해 사이트 멀리하기' }, 'ru': { title: '🚫 Доступ заблокирован', message: 'Эта веб-страница определена как неподходящий контент.', redirect: 'Перенаправление через 4 секунды...', footer: 'Будьте здоровы · Держитесь подальше от вредного контента' } }; // 获取用户语言 const getUserLanguage = () => { const lang = navigator.language || navigator.userLanguage; // 检查完整语言代码 if (i18n[lang]) return lang; // 处理中文的特殊情况 if (lang.startsWith('zh')) { const region = lang.toLowerCase(); if (region.includes('tw') || region.includes('hant')) return 'zh-TW'; if (region.includes('hk')) return 'zh-HK'; return 'zh-CN'; } // 检查简单语言代码 const shortLang = lang.split('-')[0]; if (i18n[shortLang]) return shortLang; return 'en'; }; // 浏览器检测函数 const getBrowserType = () => { const ua = navigator.userAgent.toLowerCase(); // Add more browser detection if (ua.includes('ucbrowser')) return 'uc'; if (ua.includes('qqbrowser')) return 'qq'; if (ua.includes('2345explorer')) return '2345'; if (ua.includes('360') || ua.includes('qihu')) return '360'; if (ua.includes('maxthon')) return 'maxthon'; if (ua.includes('firefox')) return 'firefox'; if (ua.includes('edg')) return 'edge'; if (ua.includes('opr') || ua.includes('opera')) return 'opera'; if (ua.includes('brave')) return 'brave'; if (ua.includes('vivaldi')) return 'vivaldi'; if (ua.includes('yabrowser')) return 'yandex'; if (ua.includes('chrome')) return 'chrome'; if (ua.includes('safari') && !ua.includes('chrome')) return 'safari'; return 'other'; }; // 获取浏览器主页URL const getHomePageUrl = () => { switch (getBrowserType()) { case 'firefox': return 'about:home'; case 'chrome': return 'chrome://newtab'; case 'edge': return 'edge://newtab'; case 'safari': return 'topsites://'; case 'opera': return 'opera://startpage'; case 'brave': return 'brave://newtab'; case 'vivaldi': return 'vivaldi://newtab'; case 'yandex': return 'yandex://newtab'; case 'uc': return 'ucenterhome://'; case 'qq': return 'qbrowser://home'; case '360': return 'se://newtab'; case 'maxthon': return 'mx://newtab'; case '2345': return '2345explorer://newtab'; default: // Fallback to a safe default return 'about:blank'; } }; // ----------------- 预编译正则规则 (性能优化) ----------------- const regexCache = { // 色情关键词正则(预编译,避免重复生成) pornRegex: null, // 白名单正则(预编译) whitelistRegex: null, // .xxx后缀正则 xxxRegex: /\.xxx$/i }; // ----------------- 配置项(用户可按需修改) ----------------- const config = { // ================== 域名专用黑名单词汇 ================== domainKeywords: { // 常见成人网站域名关键词(权重4) 'pornhub': 4, 'xvideo': 4, 'redtube': 4, 'xnxx': 4, 'xhamster': 4, '4tube': 4, 'youporn': 4, 'spankbang': 4, 'myfreecams': 4, 'missav': 4, 'rule34': 4, 'youjizz': 4, 'onlyfans': 4, 'paidaa': 4, 'haijiao': 4, // 核心违规词(权重3-4) 'porn': 3, 'nsfw': 3, 'hentai': 3, 'incest': 4, 'rape': 4, 'childporn': 4, // 身体部位关键词(权重2) 'pussy': 2, 'cock': 2, 'dick': 2, 'boobs': 2, 'tits': 2, 'ass': 2, 'beaver': 1, // 特定群体(权重2-3) 'cuckold': 3, 'virgin': 2, 'luoli': 2, 'gay': 2, // 具体违规行为(权重2-3) 'blowjob': 3, 'creampie': 2, 'bdsm': 2, 'masturbat': 2, 'handjob': 3, 'footjob': 3, 'rimjob': 3, // 其他相关词汇(权重1-2) 'camgirl': 2, 'nude': 3, 'naked': 3, 'upskirt': 2, // 特定地区成人站点域名特征(权重4) 'jav': 4, // 域名变体检测(权重3) 'p0rn': 3, 'pr0n': 3, 'pron': 3, 's3x': 3, 'sexx': 3, }, // ================== 内容检测关键词 ================== contentKeywords: { // 核心违规词(权重3-4)- 严格边界检测 '\\b(?:po*r*n|pr[o0]n)\\b': 3, // porn及其变体 'nsfw': 3, '\\bhentai\\b': 3, '\\binces*t\\b': 4, '\\br[a@]pe\\b': 4, '(?:child|kid|teen)(?:po*r*n)': 4, '海角社区': 4, // 身体部位关键词(权重2)- 优化边界和上下文检测 'puss(?:y|ies)\\b': 2, '\\bco*ck(?:s)?(?!tail|roach|pit|er)\\b': 2, // 排除cocktail等 '\\bdick(?:s)?(?!ens|tionary|tate)\\b': 2, // 排除dickens等 '\\bb[o0]{2,}bs?\\b': 2, '\\btits?\\b': 2, '(? { return config.domainPatterns.some(pattern => pattern.test(hostname)); }; // 检查是否需要进行内容检测 const shouldCheckContent = (hostname) => { return config.contentCheckDomains.some(pattern => pattern.test(hostname)); }; // 内容检测辅助函数 const contentUtils = { // 优化文本获取算法 getAllText: (element) => { if (!element) return ""; // 使用Set去重 const textSet = new Set(); try { const walker = document.createTreeWalker( element, NodeFilter.SHOW_TEXT, { acceptNode: (node) => { const parent = node.parentElement; // 优化过滤条件 if (!parent || /^(SCRIPT|STYLE|NOSCRIPT|IFRAME|META|LINK)$/i.test(parent.tagName) || parent.hidden || getComputedStyle(parent).display === 'none') { return NodeFilter.FILTER_REJECT; } const text = node.textContent.trim(); if (!text || text.length < config.contentCheck.textNodeMinLength) { return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } } ); let node; while (node = walker.nextNode()) { textSet.add(node.textContent.trim()); } } catch (e) { console.error('Error in getAllText:', e); } return Array.from(textSet).join(' '); }, // 优化可疑元素获取 getSuspiciousElements: () => { try { const elements = new Set(); // 使用更高效的选择器 const fastSelectors = [ 'article', 'main', '.content', '[class*="content"]', '[class*="text"]', 'h1', 'h2', 'h3' ]; fastSelectors.forEach(selector => { document.querySelectorAll(selector).forEach(el => elements.add(el)); }); return Array.from(elements); } catch (e) { console.error('Error in getSuspiciousElements:', e); return []; } } }; // 修改:使内容检测累加多个元素的分数 function detectAdultContent() { console.log('\n[Content Detection] Starting content analysis...'); let totalScore = 0; let totalElements = 0; let violationCount = 0; const scoreCache = new WeakMap(); // 检查高风险元素并累加分数 const highRiskElements = document.querySelectorAll( config.contentCheck.localizedCheck.highRiskSelectors.join(',') ); console.log(`[High Risk Elements] Found: ${highRiskElements.length}`); highRiskElements.forEach(element => { const score = getElementScore(element, scoreCache); console.log(`[High Risk Element] Score: ${score}`); totalScore += score; if (score >= config.contentCheck.localizedCheck.elementThreshold) { violationCount++; } }); // 排除不需要检测的元素并累加其他可疑元素分数 const excludeSelector = config.contentCheck.localizedCheck.excludeSelectors.join(','); const excludeElements = new Set(document.querySelectorAll(excludeSelector)); const mainElements = contentUtils.getSuspiciousElements(); mainElements.forEach(element => { if ( excludeElements.has(element) || Array.from(excludeElements).some(excluded => excluded.contains(element)) ) { return; } totalElements++; const score = getElementScore(element, scoreCache); totalScore += score; if (score >= config.contentCheck.localizedCheck.elementThreshold) { violationCount++; } }); // 优化图片检测 const images = document.querySelectorAll('img[alt], img[title]'); for (const img of images) { const imgText = `${img.alt} ${img.title}`.trim(); if (imgText) { totalScore += calculateScore(imgText) * 0.5; // 降低图片文本权重 } } // 优化元数据检测 const metaTags = document.querySelectorAll('meta[name="description"], meta[name="keywords"]'); for (const meta of metaTags) { const content = meta.content; if (content) { totalScore += calculateScore(content) * 0.3; // 降低元数据权重 } } console.log(`[Content Detection] Total Score: ${totalScore}`); console.log(`[Violations] Count: ${violationCount} / Total Elements: ${totalElements}`); return totalScore >= config.contentCheck.adultContentThreshold; } // 添加获取元素评分的辅助函数 function getElementScore(element, scoreCache) { if (scoreCache.has(element)) { const cachedScore = scoreCache.get(element); console.log(`[Cached Element Score] ${cachedScore}`); return cachedScore; } const text = contentUtils.getAllText(element); console.log(`[Element Text] Length: ${text.length} chars`); const score = calculateScore(text); scoreCache.set(element, score); return score; } // Refactored content detector using helper function const checkPageContent = () => { return detectAdultContent(); }; // 预处理正则(仅初始化一次) (function initRegex() { // 域名关键词正则 const domainTerms = Object.keys(config.domainKeywords).join('|'); regexCache.domainRegex = new RegExp(`(${domainTerms})`, 'gi'); // 内容关键词正则 const contentTerms = Object.keys(config.contentKeywords).join('|'); regexCache.contentRegex = new RegExp(`(${contentTerms})`, 'gi'); // 白名单正则 const whitelistTerms = Object.keys(config.whitelist).join('|'); regexCache.whitelistRegex = new RegExp(`(${whitelistTerms})`, 'gi'); })(); // Helper function to sum weights from regex matches function sumMatches(text, regex, weightMap) { const matches = text.match(regex) || []; let total = 0; matches.forEach(match => { const weight = weightMap[match.toLowerCase()] || 0; total += weight; }); return total; } // 优化后的评分计算函数 const calculateScore = (text, isDomain = false) => { let score = isDomain ? sumMatches(text, regexCache.domainRegex, config.domainKeywords) : sumMatches(text, regexCache.contentRegex, config.contentKeywords); if (score >= config.thresholds.whitelist) { const whitelistScore = sumMatches(text, regexCache.whitelistRegex, config.whitelist); if (whitelistScore !== 0) { score += whitelistScore; } } return score; }; // 防抖函数 const debounce = (func, wait) => { let timeout; return (...args) => { clearTimeout(timeout); timeout = setTimeout(() => { func(...args); }, wait); }; }; // 检测结果处理函数 const handleBlockedContent = () => { const lang = getUserLanguage(); const text = i18n[lang]; window.stop(); document.documentElement.innerHTML = `

${text.title}

${text.message}
${text.redirect}

`; let timeLeft = 4; const countdownEl = document.querySelector('.countdown'); const countdownInterval = setInterval(() => { timeLeft--; if (countdownEl) countdownEl.textContent = timeLeft; if (timeLeft <= 0) { clearInterval(countdownInterval); try { const homeUrl = getHomePageUrl(); if (window.history.length > 1) { const iframe = document.createElement('iframe'); iframe.style.display = 'none'; document.body.appendChild(iframe); iframe.onload = () => { try { const prevUrl = iframe.contentWindow.location.href; const prevScore = calculateScore(new URL(prevUrl).hostname, true); if (prevScore >= config.thresholds.block) { window.location.href = homeUrl; } else { window.history.back(); } } catch (e) { window.location.href = homeUrl; } document.body.removeChild(iframe); }; iframe.src = 'about:blank'; } else { window.location.href = homeUrl; } } catch (e) { window.location.href = getHomePageUrl(); } } }, 1000); }; // 修改:在动态内容检测中实时累计内容分数 const setupDynamicContentCheck = () => { if (!document.body) return; let pendingCheck = false; let observer = null; const checkContent = debounce((mutations) => { if (pendingCheck) return; pendingCheck = true; try { const hostname = window.location.hostname; // 增加局部检测逻辑 const targetNode = mutations[0]?.target; if (targetNode) { // 检查变化的元素是否在排除列表中 const excludeSelector = config.contentCheck.localizedCheck.excludeSelectors.join(','); const isExcluded = targetNode.matches?.(excludeSelector) || targetNode.closest?.(excludeSelector); if (isExcluded) { pendingCheck = false; return; } } if (detectAdultContent()) { blacklistManager.addToBlacklist(hostname); observer?.disconnect(); handleBlockedContent(); } } finally { pendingCheck = false; } }, config.contentCheck.debounceWait); try { observer = new MutationObserver((mutations) => { // 过滤无关变化 const hasRelevantChanges = mutations.some(mutation => { return mutation.addedNodes.length > 0 || (mutation.type === 'characterData' && mutation.target.textContent.trim().length >= config.contentCheck.textNodeMinLength); }); if (hasRelevantChanges) { checkContent(mutations); } }); observer.observe(document.body, { childList: true, subtree: true, characterData: true }); // 清理机制 setTimeout(() => { observer?.disconnect(); observer = null; }, config.contentCheck.observerTimeout); } catch (e) { console.error('Error in setupDynamicContentCheck:', e); } return observer; }; // setupDynamicContentCheck 函数之前添加新函数 const setupTitleObserver = () => { let titleObserver = null; try { // 监听 title 标签变化 const titleElement = document.querySelector('title'); if (titleElement) { titleObserver = new MutationObserver(async (mutations) => { for (const mutation of mutations) { const newTitle = mutation.target.textContent; console.log(`[Title Change] New title: "${newTitle}"`); // 计算新标题的分数 const titleScore = calculateScore(newTitle || ""); if (titleScore >= config.thresholds.block) { console.log(`[Title Score] ${titleScore} exceeds threshold`); const hostname = window.location.hostname; await blacklistManager.addToBlacklist(hostname); titleObserver.disconnect(); handleBlockedContent(); return; } } }); titleObserver.observe(titleElement, { subtree: true, characterData: true, childList: true }); } // 监听 title 标签的添加 const headObserver = new MutationObserver((mutations) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.nodeName === 'TITLE') { setupTitleObserver(); headObserver.disconnect(); return; } } } }); headObserver.observe(document.head, { childList: true, subtree: true }); // 设置超时清理 setTimeout(() => { titleObserver?.disconnect(); headObserver?.disconnect(); }, config.contentCheck.observerTimeout); } catch (e) { console.error('Error in setupTitleObserver:', e); } return titleObserver; }; // ----------------- 黑名单储存 ----------------- const blacklistManager = { BLACKLIST_KEY: 'pornblocker-blacklist', BLACKLIST_VERSION_KEY: 'pornblocker-blacklist-version', CURRENT_VERSION: '2.0', // 检查并升级黑名单版本 async checkAndUpgradeVersion() { let storage; if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) { storage = chrome.storage.sync; } else if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) { storage = chrome.storage.local; } else { // localStorage 的情况 const storedVersion = localStorage.getItem(this.BLACKLIST_VERSION_KEY); if (storedVersion !== this.CURRENT_VERSION) { // 在版本不匹配时清理旧数据 localStorage.setItem(this.BLACKLIST_VERSION_KEY, this.CURRENT_VERSION); localStorage.setItem(this.BLACKLIST_KEY, JSON.stringify([])); } return; } try { // 获取存储的版本号 const result = await new Promise(resolve => { storage.get([this.BLACKLIST_VERSION_KEY, this.BLACKLIST_KEY], resolve); }); const storedVersion = result[this.BLACKLIST_VERSION_KEY]; if (storedVersion !== this.CURRENT_VERSION) { // 执行版本迁移 await this.migrateData(storage, storedVersion, result[this.BLACKLIST_KEY]); } } catch (e) { console.error('Error checking version:', e); } }, // 数据迁移函数 async migrateData(storage, oldVersion, oldData) { try { let newData = []; // 处理旧版本数据 if (oldData) { if (Array.isArray(oldData)) { // 如果是数组,保留有效的域名 newData = oldData.filter(item => typeof item === 'string' && item.includes('.')); } else if (typeof oldData === 'object') { // 如果是对象格式,提取域名 newData = Object.keys(oldData).filter(domain => domain.includes('.')); } } // 保存迁移后的数据 await new Promise(resolve => { storage.set({ [this.BLACKLIST_KEY]: newData, [this.BLACKLIST_VERSION_KEY]: this.CURRENT_VERSION }, resolve); }); console.log(`Blacklist migrated from ${oldVersion || 'unknown'} to ${this.CURRENT_VERSION}`); } catch (e) { console.error('Error migrating data:', e); } }, // 获取黑名单 async getBlacklist() { // 确保版本检查已完成 await this.checkAndUpgradeVersion(); try { // 优先使用同步存储 if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) { return new Promise((resolve) => { chrome.storage.sync.get([this.BLACKLIST_KEY], (result) => { const data = result[this.BLACKLIST_KEY]; resolve(Array.isArray(data) ? data : []); }); }); } // 降级使用本地存储 else if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) { return new Promise((resolve) => { chrome.storage.local.get([this.BLACKLIST_KEY], (result) => { const data = result[this.BLACKLIST_KEY]; resolve(Array.isArray(data) ? data : []); }); }); } // 最后降级使用 localStorage else { const data = localStorage.getItem(this.BLACKLIST_KEY); return Promise.resolve(data ? JSON.parse(data) : []); } } catch (e) { console.error('Error reading blacklist:', e); return Promise.resolve([]); } }, // 添加到黑名单 async addToBlacklist(hostname) { try { if (!hostname) return false; const blacklist = await this.getBlacklist(); if (blacklist.includes(hostname)) return true; blacklist.push(hostname); // 优先使用同步存储 if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) { return new Promise((resolve) => { chrome.storage.sync.set({ [this.BLACKLIST_KEY]: blacklist, [this.BLACKLIST_VERSION_KEY]: this.CURRENT_VERSION }, () => resolve(true)); }); } // 降级使用本地存储 else if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) { return new Promise((resolve) => { chrome.storage.local.set({ [this.BLACKLIST_KEY]: blacklist, [this.BLACKLIST_VERSION_KEY]: this.CURRENT_VERSION }, () => resolve(true)); }); } // 最后降级使用 localStorage else { localStorage.setItem(this.BLACKLIST_VERSION_KEY, this.CURRENT_VERSION); localStorage.setItem(this.BLACKLIST_KEY, JSON.stringify(blacklist)); return Promise.resolve(true); } } catch (e) { console.error('Error adding to blacklist:', e); return Promise.resolve(false); } }, // 检查是否在黑名单中 async isBlacklisted(hostname) { try { if (!hostname) return false; const blacklist = await this.getBlacklist(); return blacklist.includes(hostname); } catch (e) { console.error('Error checking blacklist:', e); return false; } }, // 从黑名单中移除 async removeFromBlacklist(hostname) { try { const blacklist = await this.getBlacklist(); const index = blacklist.indexOf(hostname); if (index > -1) { blacklist.splice(index, 1); // 优先使用同步存储 if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) { return new Promise((resolve) => { chrome.storage.sync.set({ [this.BLACKLIST_KEY]: blacklist }, () => { resolve(true); }); }); } // 降级使用本地存储 else if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.local) { return new Promise((resolve) => { chrome.storage.local.set({ [this.BLACKLIST_KEY]: blacklist }, () => { resolve(true); }); }); } // 最后降级使用 localStorage else { localStorage.setItem(this.BLACKLIST_KEY, JSON.stringify(blacklist)); return Promise.resolve(true); } } return Promise.resolve(false); } catch (e) { console.error('Error removing from blacklist:', e); return Promise.resolve(false); } } }; // 立即执行版本检查 (async function initBlacklist() { await blacklistManager.checkAndUpgradeVersion(); })(); // ----------------- 主检测逻辑 ----------------- const checkUrl = async () => { const url = new URL(window.location.href); const hostname = url.hostname; console.log(`\n[URL Check] Checking: ${url.href}`); console.log(`[Hostname] ${hostname}`); // 优化黑名单检查 if (await blacklistManager.isBlacklisted(hostname)) { return { shouldBlock: true, url: url, reason: 'blacklist' }; } // 如果域名匹配正则 if (checkDomainPatterns(url.hostname)) { return { shouldBlock: true, url: url }; } // 检查是否需要进行内容检测 if (shouldCheckContent(url.hostname)) { if (document.body) { const hasAdultContent = checkPageContent(); if (hasAdultContent) { blacklistManager.addToBlacklist(hostname); return { shouldBlock: true, url: url, reason: 'content' }; } setupDynamicContentCheck(); } else { document.addEventListener('DOMContentLoaded', () => { if (checkPageContent()) { blacklistManager.addToBlacklist(hostname); handleBlockedContent(); } setupDynamicContentCheck(); }); } } let score = 0; // 检查域名 const pornMatches = url.hostname.match(regexCache.domainRegex) || []; pornMatches.forEach(match => { const keyword = match.toLowerCase(); const domainScore = config.domainKeywords[keyword] || 0; if (domainScore !== 0) { console.log(`[Domain Match] "${match}" = ${domainScore}`); score += domainScore; } }); // 检查路径 const path = url.pathname + url.search; console.log(`[Path Check] "${path}"`); const pathScore = calculateScore(path) * 0.4; if (pathScore !== 0) { console.log(`[Path Score] ${pathScore} (after 0.4 multiplier)`); score += pathScore; } // 检查标题 console.log(`[Title Check] "${document.title}"`); const titleScore = calculateScore(document.title || ""); if (titleScore !== 0) { console.log(`[Title Score] ${titleScore}`); score += titleScore; } console.log(`[Initial Total Score] ${score}`); console.log(`[Block Threshold] ${config.thresholds.block}`); // 优化白名单评分: 如果超过阈值则进行白名单扣分 if (score >= config.thresholds.whitelist) { const hostMatches = url.hostname.match(regexCache.whitelistRegex) || []; const titleMatches = (document.title || "").match(regexCache.whitelistRegex) || []; // 累加白名单分数 let whitelistScore = 0; const whitelistMatchCount = (matches) => { matches.forEach(match => { const term = match.toLowerCase(); const reduction = config.whitelist[term] || 0; if (reduction !== 0) { console.log(`[Whitelist Match] "${term}" = ${reduction}`); whitelistScore += reduction; } }); }; whitelistMatchCount(hostMatches); whitelistMatchCount(titleMatches); if (whitelistScore !== 0) { console.log(`[Whitelist Score] ${whitelistScore}`); score += whitelistScore; // 加上白名单分数(负值会减分) } } console.log(`[Final Score] ${score}`); return { shouldBlock: score >= config.thresholds.block, url: url }; }; // 修改主执行函数,添加标题监听 (async function () { const { shouldBlock, url: currentUrl } = await checkUrl(); if (shouldBlock || regexCache.xxxRegex.test(currentUrl.hostname)) { handleBlockedContent(); } else { // 添加标题监听 setupTitleObserver(); } })(); })();