移动端增强型广告拦截器

一个手机端via浏览器能用的强大的广告拦截器

// ==UserScript==
// @name         移动端增强型广告拦截器
// @namespace    http://tampermonkey.net/
// @version      3.9.9
// @author       DeepSeek&Gemini
// @description  一个手机端via浏览器能用的强大的广告拦截器
// @match        *://*/*
// @license      MIT
// @grant        unsafeWindow
// @grant        GM_registerMenuCommand
// @grant        GM_notification
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_getResourceText
// @grant        GM_addStyle
// @grant        GM_openInTab
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    const HOSTNAME = location.hostname.replace(/\./g, '\\.');
    const REGEX = {
        dynamicId: /^(?:([0-9a-f]{4}-?){4,}|[0-9a-f]{16,}|[\dA-F-]{18,}|[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12})$/i,
        jsAdPattern: /(?:window\.open|document\.write|createElement\(['"]script['"]|location\.replace|setTimeout\s*\([^)]*?\b(?:window\.open|document\.write)|eval\s*\(|new\s+Function\s*\(|appendChild\s*\(.*?\bscript\b|on(?:click|load)\s*=\s*['"]?\s*(?:window\.open))/i,
        adAttributes: /(推广|广告|gg|sponsor|推荐|guanggao|syad|bfad|弹窗|悬浮|葡京|banner|pop(?:up|under)|track(?:ing)?)(?:$|[_-])/i,
        thirdPartyHostCheck: new RegExp(`^(https?:\\/\\/(.*\\.)?${HOSTNAME}(\\/|$)|data:|about:blank)`, 'i'),
        obfuscationPatterns: [
            { type: '字符串/十六进制/Unicode混淆', pattern: /(?:\\(?:x[0-9a-f]{2}|u[0-9a-f]{4}){3,})/gi, riskLevel: 3 },
            { type: 'Base64/编码Payload执行', pattern: /['"](?:data:application\/javascript;base64,|(?:btoa|atob)\s*\(\s*['"][A-Za-z0-9+/=]{100,}['"])|(?:eval\(\s*(?:atob|decodeURIComponent\(\s*escape\(\s*atob\))\s*\(\s*["'][A-Za-z0-9+/=]{40,}["'])|[A-Za-z0-9+/=]{60,}/gi, riskLevel: 5 },
            { type: '动态代码执行', pattern: /(eval|new\s+Function\s*\(|set(?:Timeout|Interval|Immediate)\s*\(\s*function\s*\(\)\s*\{)/i, riskLevel: 4 },
            { type: '动态脚本注入', pattern: /(?:document\.(?:createElement\s*\(['"]script['"]\)\.src\s*=|(?:head|body)\.appendChild\s*\(|getElementsByTagName\(['"]head['"]\)\s*\[0\]\.appendChild)|document\s*\[\s*['"]createElement['"]\s*\]\s*\(\s*['"]script['"]\s*\))/gi, riskLevel: 4 },
            { type: '数学/日期/数值/数组/属性混淆', pattern: /(?:Math\[\s*['"]\w{5,}['"]\s*\]|new\s+Date\s*\(\s*\)\s*\[\s*['"]getTime['"]\s*\]|Math\.(?:round|floor|ceil)\s*\[\s*['"]constructor['"]\s*\]|0x[a-f0-9]{8}(?:\+0x[a-f0-9]{8}){3,}|\[(?:0x[0-9a-f]+|\d+),?(?:0x[0-9a-f]+|\d+)\]\.(?:join|reverse|map)|\b\w+\s*\[\s*(?:0x[0-9a-f]+|\d+|['"][^'"]{5,}['"])\s*\])/gi, riskLevel: 3 },
            { type: '随机数/时间混淆', pattern: /Math\.floor\(\s*(?:\d+\s*\*\s*)?Math\.random\(\s*\)(?:\s*\*\s*\w+\.length)?\s*\)|Math\.floor\(\s*\(\s*new\s+Date\s*\(\s*\)\.getTime\(\s*\)/i, riskLevel: 3 }
        ],
    };
    const DEFAULT_MODULES = {
        main: false,
        dynamicSystem: false,
        layoutSystem: false,
        mergedMediaSystem: false,
        thirdPartyBlock: false,
        specialUA: true
    };
    const DEFAULT_CSP_RULES = [
        { id: 1, name: '仅允许同源脚本', rule: "script-src 'self'", enabled: true },
        { id: 2, name: '禁止内联脚本', rule: "script-src 'unsafe-inline'", enabled: false },
        { id: 3, name: '禁止eval执行', rule: "script-src 'unsafe-eval'", enabled: false },
        { id: 4, name: '阻止外部样式加载', rule: "style-src 'self'", enabled: false },
        { id: 5, name: '阻止内联样式执行', rule: "style-src 'unsafe-inline'", enabled: false },
        { id: 6, name: '阻止外部图片加载', rule: "img-src 'self'", enabled: true },
        { id: 7, name: '禁止所有框架加载', rule: "frame-src 'none'", enabled: false },
        { id: 8, name: '禁止媒体资源加载', rule: "media-src 'none'", enabled: false },
        { id: 9, name: '禁止对象嵌入', rule: "object-src 'none'", enabled: false }
    ];
    const CONFIG = {
        modules: { ...DEFAULT_MODULES },
        protectionRules: {
            dynamicIdLength: 32,
            zIndexThreshold: 9999
        },
        csp: {
            enabled: false,
            rules: DEFAULT_CSP_RULES.map(rule => ({ ...rule }))
        },
        mobileOptimizations: {
            lazyLoadImages: true,
            removeImagePlaceholders: true
        },
        moduleNames: {
            dynamicSystem: '动态检测系统',
            layoutSystem: '布局检测系统',
            mergedMediaSystem: '图片广告移除',
            thirdPartyBlock: '第三方拦截',
            specialUA: '添加特殊UA'
        },
        modulePriority: [
            'thirdPartyBlock',
            'specialUA',
            'dynamicSystem',
            'mergedMediaSystem',
            'layoutSystem'
        ],
        performance: {
            highRiskModules: ['thirdPartyBlock', 'dynamicSystem', 'mergedMediaSystem', 'layoutSystem'],
            visibleAreaPriority: true,
            styleCacheTimeout: 600000,
            mutationProcessLimit: 40,
            mutationProcessTimeLimit: 10,
            idleCallbackTimeout: 2500,
            throttleScrollDelay: 200,
            debounceMutationDelay: 300,
            longTaskThreshold: 500,
            degradeThreshold: 5
        },
        originalUA: {
            userAgent: navigator.userAgent,
            platform: navigator.platform
        },
        whitelist: {}
    };
    const ElementFlags = {
        LOGGED: 1 << 0,
        WHITELISTED_EXPLICIT: 1 << 1,
        WHITELISTED_IMPLICIT: 1 << 2,
    };
    const Utils = {
        throttle(fn, delay) {
            let last = 0,
                timer = null;
            return function(...args) {
                const now = Date.now();
                if (now - last >= delay) {
                    fn.apply(this, args);
                    last = now;
                } else {
                    clearTimeout(timer);
                    timer = setTimeout(() => {
                        fn.apply(this, args);
                        last = now;
                    }, delay - (now - last));
                }
            };
        },
        debounce(fn, delay) {
            let timer = null;
            return function(...args) {
                clearTimeout(timer);
                timer = setTimeout(() => {
                    try {
                        fn.apply(this, args);
                    } catch (e) {
                        Logs.add('error', this, {
                            type: 'debounceError',
                            detail: e.message
                        });
                    }
                }, delay);
            }
        },
        truncateString(str, maxLength) {
            if (typeof str !== 'string') return '';
            if (str.length <= maxLength) return str;
            return str.slice(0, maxLength) + '...';
        },
        removeAttributeSafely(element, attributeName) {
            if (element instanceof Element && element.hasAttribute(attributeName)) {
                try {
                    element.removeAttribute(attributeName);
                } catch (e) {}
            }
        },
        isAdCharacteristic(element) {
            if (!(element instanceof Element)) return false;
            return REGEX.adAttributes.test(element.id) || REGEX.adAttributes.test(element.className) || Array.from(element.attributes).some(attr => REGEX.adAttributes.test(attr.name) || REGEX.adAttributes.test(attr.value));
        }
    };
    const elementStateTracker = {
        _flagsMap: new WeakMap(),
        setFlag(element, flag) {
            if (!(element instanceof Element)) return;
            let currentFlags = this._flagsMap.get(element) || 0;
            currentFlags |= flag;
            this._flagsMap.set(element, currentFlags);
        },
        hasFlag(element, flag) {
            if (!(element instanceof Element)) return false;
            const currentFlags = this._flagsMap.get(element);
            return (currentFlags & flag) === flag;
        }
    };
    const SharedUtils = {
        generateElementPattern(element) {
            try {
                if (!element || !(element instanceof Element)) return '';
                let pattern = element.tagName || '';
                if (element.id) pattern += `#${element.id}`;
                if (element.className) {
                    const firstClass = element.className.split(/\s+/)[0];
                    if (firstClass) pattern += `.${firstClass}`;
                }
                return pattern;
            } catch (e) {
                return '';
            }
        },
        getElementContent(element) {
            if (!element || !(element instanceof Element)) return '[无效元素]';
            let baseIdentifier = '';
            if (element.id) {
                baseIdentifier = `ID:${element.id}`;
            } else if (element.className) {
                baseIdentifier = `CLASS:${element.className.split(/\s+/)[0]}`;
            }
            if (element.dataset.url && element.dataset.tag) {
                let content = `${element.dataset.tag}: ${Utils.truncateString(element.dataset.url, 200)}`;
                if (element.dataset.detail) {
                    content += `, ${element.dataset.detail}`;
                }
                return content;
            }
            if (element.dataset.insertionType && element.dataset.originalHTML) {
                return `DYNAMIC_INSERT (${element.dataset.insertionType}${baseIdentifier ? `, ${baseIdentifier}` : ''}): ${Utils.truncateString(element.dataset.originalHTML, 2000)}`;
            }
            if (element.tagName === 'SCRIPT') {
                const src = element.src;
                const content = element.textContent;
                if (src) return `SCRIPT_SRC${baseIdentifier ? ` (${baseIdentifier})` : ''}: ${Utils.truncateString(src, 200)}`;
                if (content) return `SCRIPT_CONTENT${baseIdentifier ? ` (${baseIdentifier})` : ''}: ${Utils.truncateString(content.replace(/\s+/g, ' '), 2000)}`;
                return `SCRIPT_EMPTY${baseIdentifier ? ` (${baseIdentifier})` : ''}`;
            }
            if (element.tagName === 'IFRAME') {
                const src = element.src;
                if (src) return `IFRAME_SRC${baseIdentifier ? ` (${baseIdentifier})` : ''}: ${Utils.truncateString(src, 200)}`;
                return `IFRAME_EMPTY${baseIdentifier ? ` (${baseIdentifier})` : ''}`;
            }
            if (element.tagName === 'IMG') {
                const src = element.src || element.dataset.src;
                if (src) return `IMG_SRC${baseIdentifier ? ` (${baseIdentifier})` : ''}: ${Utils.truncateString(src, 200)}`;
                return `IMG_EMPTY${baseIdentifier ? ` (${baseIdentifier})` : ''}`;
            }
            const outerHTML = element.outerHTML;
            if (outerHTML) {
                return `ELEMENT_HTML${baseIdentifier ? ` (${baseIdentifier})` : ''}: ${Utils.truncateString(outerHTML.replace(/\s+/g, ' ').replace(/<!--.*?-->/g, ''), 200)}`;
            }
            return '[无法获取内容]';
        }
    };
    const Logs = {
        logs: [],
        maxLogs: 50,
        add(moduleKey, element, reason) {
            if (!(element instanceof Element) && element !== null) return;
            if (element !== null && (Whitelist.isWhitelisted(element) || Whitelist.isAncestorWhitelisted(element))) return;
            let fullContent;
            if (element !== null) {
                fullContent = SharedUtils.getElementContent(element);
                if (fullContent.trim() === '[无效元素]' || fullContent.trim() === '[无法获取内容]' || fullContent.includes('[安全限制无法获取内容]')) {
                    return;
                }
                if (elementStateTracker.hasFlag(element, ElementFlags.LOGGED)) {
                    return;
                }
                elementStateTracker.setFlag(element, ElementFlags.LOGGED);
            } else {
                fullContent = reason.detail || 'N/A';
            }
            const currentDomain = new URL(location.href).hostname;
            const getElementInfoForLogDisplay = (el) => {
                if (el === null) return { tag: 'N/A', id: '', class: '', src: '', attributes: {} };
                try {
                    const attrs = {};
                    const attributeNames = ['id', 'class', 'src', 'href', 'data-src', 'style'];
                    for (const name of attributeNames) {
                        if (el.hasAttribute(name)) {
                            attrs[name] = Utils.truncateString(el.getAttribute(name), 100);
                        }
                    }
                    return {
                        tag: el.tagName || '未知标签',
                        id: el.id ? `#${el.id}` : '',
                        class: el.className ? `.${el.className.split(/\s+/).join('.')}` : '',
                        src: el.src || el.href || el.dataset.src || '',
                        attributes: attrs
                    };
                } catch (e) {
                    return {
                        tag: '未知标签',
                        id: '',
                        class: '',
                        src: '',
                        attributes: {},
                        error: '元素解析失败'
                    };
                }
            };
            const elementInfoDisplay = getElementInfoForLogDisplay(element);
            let specificDetailsText = '';
            if (reason.type === '动态脚本风险' || reason.type === '流式特征阻断' || reason.type === '动态脚本源快速检测' || reason.type === '内联脚本快速检测' || reason.type === '内联脚本结构性混淆') {
                specificDetailsText = `AST阻断: ${reason.ruleName || reason.type}`;
            } else if (reason.ruleName) {
                specificDetailsText = reason.ruleName;
            } else if (reason.regex && reason.regex.length > 0) {
                let matchedRuleTypes = new Set();
                for (const patternSource of reason.regex) {
                    const matchedRule = REGEX.obfuscationPatterns.find(rule => rule.pattern.source === patternSource);
                    if (matchedRule) {
                        matchedRuleTypes.add(matchedRule.type);
                    } else if (patternSource === REGEX.jsAdPattern.source) {
                        matchedRuleTypes.add('可疑JS广告模式');
                    }
                }
                if (matchedRuleTypes.size > 0) {
                    specificDetailsText = Array.from(matchedRuleTypes).join('; ');
                } else {
                    specificDetailsText = reason.detail || reason.type || '自动拦截';
                }
            } else {
                specificDetailsText = reason.detail || reason.type || '自动拦截';
            }
            specificDetailsText = Utils.truncateString(specificDetailsText, 150);
            this.logs.push({
                module: CONFIG.moduleNames[moduleKey] || moduleKey,
                elementSummary: `${elementInfoDisplay.tag}${elementInfoDisplay.id}${elementInfoDisplay.class}`,
                content: fullContent,
                specificDetailsForDisplay: specificDetailsText,
                originalReason: {
                    type: reason.type || '自动拦截',
                    detail: Utils.truncateString(reason.detail || '', 150),
                    pattern: reason.regex ? reason.regex.map(r => Utils.truncateString(r.source, 100)) : [],
                    ruleName: reason.ruleName
                },
                contextInfo: {
                    src: Utils.truncateString(elementInfoDisplay.src || '', 200),
                    attributes: elementInfoDisplay.attributes || {},
                    parentTag: element ? (element.parentElement ? element.parentElement.tagName : '无父节点') : 'N/A',
                    domain: currentDomain
                },
                timestamp: Date.now(),
            });
            if (this.logs.length > this.maxLogs) {
                this.logs = this.logs.slice(this.logs.length - this.maxLogs);
            }
        },
        clear() {
            this.logs = [];
            GM_notification('日志已清空');
        },
        showInAlert() {
            const logText = this.logs.map((log, index) => {
                const parts = [];
                if (log.specificDetailsForDisplay) parts.push(`具体详情: ${log.specificDetailsForDisplay}`);
                return [
                    `序号: ${index + 1}`,
                    `模块: ${log.module}`,
                    `元素: ${log.elementSummary}`,
                    `内容: ${log.content}`,
                    ...parts
                ].filter(line => line.trim() !== '').join('\n');
            }).join('\n\n');
            const promptMessage = `广告拦截日志(最近${this.logs.length}条):\n\n${logText || '暂无日志'}\n\n请输入序号,支持格式:\n123(序号1, 2, 3)\n1,3,5(序号1, 3, 5)\n1-12(序号1到12)\n输入 0 清空当前域名的白名单:`;
            let input = prompt(promptMessage, "");
            if (input === null) return;
            input = input.trim();
            if (input === "0") {
                if (confirm(`确定清空当前域名 (${location.hostname}) 的白名单吗?`)) {
                    Whitelist.clearCurrentDomain();
                    GM_notification('白名单已清空', `当前域名 (${location.hostname}) 的白名单已清空`);
                    location.reload();
                }
            } else {
                let inputIndices = [];
                const cleanedInput = input.replace(/,/g, ',');
                if (cleanedInput.includes('-')) {
                    const parts = cleanedInput.split('-');
                    if (parts.length === 2) {
                        const start = parseInt(parts[0].trim(), 10);
                        const end = parseInt(parts[1].trim(), 10);
                        if (!isNaN(start) && !isNaN(end) && start >= 1 && end >= start) {
                            for (let i = start; i <= end; i++) {
                                inputIndices.push(i - 1);
                            }
                        } else {
                            alert("无效的范围格式。请使用 '开始序号-结束序号',例如 '1-12'");
                            return;
                        }
                    } else {
                        alert("无效的范围格式。请使用 '开始序号-结束序号',例如 '1-12'");
                        return;
                    }
                } else if (cleanedInput.includes(',')) {
                    inputIndices = cleanedInput.split(',')
                        .map(s => parseInt(s.trim(), 10))
                        .filter(n => !isNaN(n) && n >= 1)
                        .map(n => n - 1);
                } else if (/^\d+$/.test(cleanedInput)) {
                    inputIndices = cleanedInput.split('')
                        .map(s => parseInt(s, 10))
                        .filter(n => !isNaN(n) && n >= 1)
                        .map(n => n - 1);
                } else {
                    alert("无效的输入格式。请按提示输入序号、范围或 0");
                    return;
                }
                const validIndices = [...new Set(inputIndices)]
                    .filter(index => index >= 0 && index < this.logs.length);
                let addedCount = 0;
                if (validIndices.length > 0) {
                    validIndices.forEach(index => {
                        const logEntry = this.logs[index];
                        if (logEntry && logEntry.content && !Whitelist.isWhitelistedContent(location.hostname, logEntry.content)) {
                            Whitelist.add(location.hostname, logEntry.content);
                            addedCount++;
                        }
                    });
                    if (addedCount > 0) {
                        UIController.saveConfig();
                        GM_notification('已添加到白名单', `${addedCount} 项内容已添加到白名单`);
                        location.reload();
                    } else {
                        alert('未添加任何新的内容到白名单');
                    }
                } else if (input.length > 0) {
                    alert('未找到匹配的日志序号或输入格式无效');
                }
            }
        }
    };
    const Whitelist = {
        init() {
            if (!CONFIG.whitelist) {
                CONFIG.whitelist = {};
            }
            const currentDomain = new URL(location.href).hostname;
            if (!CONFIG.whitelist[currentDomain]) {
                CONFIG.whitelist[currentDomain] = [];
            }
            CONFIG.whitelist[currentDomain] = CONFIG.whitelist[currentDomain].filter(content => content && content.trim() !== '' && !content.includes('[无法获取内容]') && !content.includes('[安全限制无法获取内容]'));
        },
        add(domain, content) {
            if (!domain || !content || content.trim() === '' || content.includes('[无法获取内容]') || content.includes('[安全限制无法获取内容]')) {
                return;
            }
            if (!CONFIG.whitelist[domain]) {
                CONFIG.whitelist[domain] = [];
            }
            if (!CONFIG.whitelist[domain].includes(content)) {
                CONFIG.whitelist[domain].push(content);
            }
        },
        isWhitelisted(element) {
            if (!(element instanceof Element)) return false;
            const currentDomain = new URL(location.href).hostname;
            if (!CONFIG.whitelist[currentDomain] || CONFIG.whitelist[currentDomain].length === 0) {
                return false;
            }
            if (elementStateTracker.hasFlag(element, ElementFlags.WHITELISTED_EXPLICIT)) return true;
            const elementContent = SharedUtils.getElementContent(element);
            const isWhitelisted = CONFIG.whitelist[currentDomain].includes(elementContent);
            if (isWhitelisted) {
                elementStateTracker.setFlag(element, ElementFlags.WHITELISTED_EXPLICIT);
            }
            return isWhitelisted;
        },
        isWhitelistedContent(domain, content) {
            if (!domain || !content || content.trim() === '') return false;
            if (!CONFIG.whitelist[domain]) {
                return false;
            }
            return CONFIG.whitelist[domain].includes(content);
        },
        isAncestorWhitelisted(element) {
            if (!(element instanceof Element)) return false;
            if (elementStateTracker.hasFlag(element, ElementFlags.WHITELISTED_IMPLICIT)) {
                return true;
            }
            let current = element.parentElement;
            while (current) {
                if (this.isWhitelisted(current)) {
                    elementStateTracker.setFlag(element, ElementFlags.WHITELISTED_IMPLICIT);
                    return true;
                }
                current = current.parentElement;
            }
            return false;
        },
        clear(domain) {
            if (CONFIG.whitelist[domain]) {
                CONFIG.whitelist[domain] = [];
            }
        },
        clearCurrentDomain() {
            const currentDomain = new URL(location.href).hostname;
            this.clear(currentDomain);
            UIController.saveConfig();
        },
        clearAll() {
            CONFIG.whitelist = {};
            UIController.saveConfig();
        }
    };
    const perf = {
        adElements: new Set(),
        processed: new WeakSet(),
        styleCache: new Map(),
        lastStyleCacheClear: Date.now(),
        performanceEntries: [],
        degraded: false,
        isProcessing: false
    };
    const canProcessElement = (element) => {
        if (!CONFIG.modules.main || perf.degraded) return false;
        if (!(element instanceof Element)) return false;
        if (Whitelist.isWhitelisted(element) || Whitelist.isAncestorWhitelisted(element)) {
            return false;
        }
        if (element.dataset.adCleaned === 'true' || element.dataset.adNuclearRemoved === 'true') return false;
        return true;
    };
    const Detector = {
        getCachedStyle(el) {
            if (!canProcessElement(el)) return {};
            if (Date.now() - perf.lastStyleCacheClear > CONFIG.performance.styleCacheTimeout) {
                perf.styleCache.clear();
                perf.lastStyleCacheClear = Date.now();
            }
            const key = `${el.nodeName}#${el.id}.${Array.from(el.classList).join('.')}`;
            if (!perf.styleCache.has(key)) {
                try {
                    perf.styleCache.set(key, getComputedStyle(el));
                } catch (e) {
                    return {};
                }
            }
            return perf.styleCache.get(key);
        },
        isVisible(el) {
            if (!canProcessElement(el)) return false;
            const style = Detector.getCachedStyle(el);
            if (style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity) < 0.01) return false;
            const rect = el.getBoundingClientRect();
            return !(
                rect.width === 0 ||
                rect.height === 0 ||
                (rect.top >= window.innerHeight || rect.bottom <= 0) ||
                (rect.left >= window.innerWidth || rect.right <= 0)
            );
        }
    };
    const ModuleManager = {
        modules: {},
        register(name, module) {
            this.modules[name] = module;
        },
        init() {
            Object.values(this.modules).forEach(module => {
                if (typeof module.init === 'function') {
                    module.init();
                }
            });
        },
        run(moduleKey, element) {
            if (!canProcessElement(element)) return false;
            if (!CONFIG.modules[moduleKey] || element.dataset.adCleaned === 'true' || element.dataset.adNuclearRemoved === 'true') return false;
            const module = this.modules[moduleKey];
            if (module && typeof module.check === 'function') {
                const isBlocked = module.check(element);
                if (isBlocked) {
                    perf.processed.add(element);
                }
                return isBlocked;
            }
            return false;
        }
    };
    const AdUtils = {
        abortControllers: new WeakMap(),
        scriptObserver: null,
        isScriptHooksActive: false,
        _originalInnerHTMLGetter: null,
        _originalInnerHTMLSetter: null,
        _originalAppendChild: null,
        _originalCreateElement: null,
        _originalSetAttribute: null,
        removeElement(element, moduleKey, reason, isNuclear = false) {
            if (!canProcessElement(element)) return false;
            if (isNuclear) {
                element.dataset.adNuclearRemoved = 'true';
            } else {
                element.dataset.adCleaned = 'true';
            }
            Logs.add(moduleKey, element, {
                ...reason,
                detail: (isNuclear ? '[原子级移除] ' : '') + (reason.detail || ''),
                nuclear: isNuclear
            });
            perf.processed.add(element);
            try {
                if (isNuclear) {
                    const unsafeAttributes = element.tagName === 'SCRIPT' ?
                        ['src', 'onload', 'onerror', 'integrity', 'type'] :
                        ['src', 'href', 'data-src'];
                    unsafeAttributes.forEach(attr => Utils.removeAttributeSafely(element, attr));
                    if (element.parentNode) {
                        try {
                            const comment = document.createComment(`Removed ad by ${moduleKey} [Nuclear]: ${reason.type}`);
                            element.parentNode.replaceChild(comment, element);
                        } catch (e) {
                            element.remove();
                        }
                    } else {
                        element.remove();
                    }
                } else {
                    if (element.parentNode) {
                        element.parentNode.removeChild(element);
                    } else {
                        element.remove();
                    }
                }
                return true;
            } catch (e) {
                if (element instanceof Element) {
                    element.dataset.adRemovalFailed = 'true';
                }
                return false;
            }
        },
        safeRemove(element, moduleKey, reason) {
            return this.removeElement(element, moduleKey, reason, false);
        },
        nuclearRemove(element, moduleKey, reason) {
            return this.removeElement(element, moduleKey, reason, true);
        },
        initScriptHooks() {
            if (this.isScriptHooksActive || perf.degraded || !CONFIG.modules.main) return;
            this.isScriptHooksActive = true;
            const self = this;
            if (!this._originalAppendChild) this._originalAppendChild = Node.prototype.appendChild;
            if (!this._originalCreateElement) this._originalCreateElement = document.createElement;
            if (!this._originalSetAttribute) this._originalSetAttribute = Element.prototype.setAttribute;
            Node.prototype.appendChild = function(node) {
                if (!canProcessElement(this) || !canProcessElement(node)) {
                    return self._originalAppendChild.call(this, node);
                }
                if (node.nodeType === 1) {
                    if (node.tagName === 'SCRIPT') {
                        self.processScriptElementHook(node);
                        if (node.dataset.adCleaned === 'true' || node.dataset.adNuclearRemoved === 'true') {
                            return node;
                        }
                    } else {
                        const potentialHTML = node.innerHTML;
                        if (potentialHTML && REGEX.jsAdPattern.test(potentialHTML)) {
                            const tempDiv = self._originalCreateElement.call(document, 'div');
                            tempDiv.innerHTML = potentialHTML;
                            if (self.checkDynamicContent(tempDiv, node)) {
                                AdUtils.safeRemove(node, 'dynamicSystem', {
                                    type: '非脚本元素可疑HTML内容',
                                    detail: `父元素appendChild: ${Utils.truncateString(potentialHTML, 100)}`,
                                });
                                return null;
                            }
                        }
                    }
                }
                return self._originalAppendChild.call(this, node);
            };
            document.createElement = function(tagName) {
                const el = self._originalCreateElement.call(document, tagName);
                if (tagName.toLowerCase() === 'script') {
                    if (!canProcessElement(el)) {
                        return el;
                    }
                    return self.createScriptProxy(el);
                }
                return el;
            };
            Element.prototype.setAttribute = function(name, value) {
                if (!canProcessElement(this)) {
                    return self._originalSetAttribute.call(this, name, value);
                }
                if (name === 'innerHTML' && typeof value === 'string') {
                    const tempDiv = self._originalCreateElement.call(document, 'div');
                    tempDiv.innerHTML = value;
                    if (self.checkDynamicContent(tempDiv, this)) {
                        AdUtils.safeRemove(this, 'dynamicSystem', {
                            type: 'innerHTML注入广告',
                            detail: `内容命中混淆/广告模式: ${Utils.truncateString(value, 100)}`,
                        });
                        return;
                    }
                }
                return self._originalSetAttribute.call(this, name, value);
            };
            const innerHTMLDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
            if (innerHTMLDescriptor && innerHTMLDescriptor.set && innerHTMLDescriptor.get) {
                self._originalInnerHTMLSetter = innerHTMLDescriptor.set;
                self._originalInnerHTMLGetter = innerHTMLDescriptor.get;
                Object.defineProperty(Element.prototype, 'innerHTML', {
                    get: function() {
                        return self._originalInnerHTMLGetter.call(this);
                    },
                    set: function(value) {
                        if (!canProcessElement(this)) {
                            return self._originalInnerHTMLSetter.call(this, value);
                        }
                        if (typeof value === 'string') {
                            const tempDiv = self._originalCreateElement.call(document, 'div');
                            tempDiv.innerHTML = value;
                            if (self.checkDynamicContent(tempDiv, this)) {
                                AdUtils.safeRemove(this, 'dynamicSystem', {
                                    type: 'innerHTML属性注入广告',
                                    detail: `属性设置命中混淆/广告模式: ${Utils.truncateString(value, 100)}`,
                                });
                                return self._originalInnerHTMLSetter.call(this, '');
                            }
                        }
                        return self._originalInnerHTMLSetter.call(this, value);
                    },
                    configurable: true,
                    enumerable: innerHTMLDescriptor.enumerable
                });
            }
            this.scriptObserver = new MutationObserver(mutations => {
                if (!CONFIG.modules.main || perf.degraded) return;
                mutations.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === 1 && node.tagName === 'SCRIPT') {
                            if (!canProcessElement(node)) return;
                            self.processScriptElementHook(node);
                        }
                    });
                });
            });
            if (document.documentElement) {
                this.scriptObserver.observe(document.documentElement, {
                    childList: true,
                    subtree: true
                });
            } else {
                window.addEventListener('DOMContentLoaded', () => {
                    if (!CONFIG.modules.main || perf.degraded) return;
                    this.scriptObserver.observe(document.documentElement, {
                        childList: true,
                        subtree: true
                    });
                }, { once: true });
            }
        },
        cleanupScriptHooks() {
            if (!this.isScriptHooksActive) return;
            this.isScriptHooksActive = false;
            if (this._originalAppendChild) {
                Node.prototype.appendChild = this._originalAppendChild;
                this._originalAppendChild = null;
            }
            if (this._originalCreateElement) {
                document.createElement = this._originalCreateElement;
                this._originalCreateElement = null;
            }
            if (this._originalSetAttribute) {
                Element.prototype.setAttribute = this._originalSetAttribute;
                this._originalSetAttribute = null;
            }
            if (this._originalInnerHTMLGetter && this._originalInnerHTMLSetter) {
                Object.defineProperty(Element.prototype, 'innerHTML', {
                    get: this._originalInnerHTMLGetter,
                    set: this._originalInnerHTMLSetter,
                    configurable: true,
                    enumerable: Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML')?.enumerable || true
                });
                this._originalInnerHTMLGetter = null;
                this._originalInnerHTMLSetter = null;
            }
            if (this.scriptObserver) {
                this.scriptObserver.disconnect();
                this.scriptObserver = null;
            }
            this.abortControllers.forEach(controller => controller.abort());
            this.abortControllers.clear();
        },
        createScriptProxy(scriptElement) {
            return new Proxy(scriptElement, {
                set: (target, prop, value) => {
                    if (!canProcessElement(target)) {
                        target[prop] = value;
                        return true;
                    }
                    if ((prop === 'src' || prop === 'innerHTML') && typeof value === 'string') {
                        AdUtils.processScriptSource(target, prop, value);
                    }
                    target[prop] = value;
                    return true;
                },
                get: (target, prop) => {
                    if (!canProcessElement(target)) {
                        return Reflect.get(target, prop);
                    }
                    return Reflect.get(target, prop);
                }
            });
        },
        processScriptElementHook(scriptElement) {
            if (!canProcessElement(scriptElement)) return;
            scriptElement.dataset.adProcessedHook = 'true';
            if (CONFIG.modules.thirdPartyBlock && ModuleManager.modules.thirdPartyBlock?.isThirdParty(scriptElement.src || scriptElement.getAttribute('data-src') || '')) {
                AdUtils.nuclearRemove(scriptElement, 'thirdPartyBlock', {
                    type: '第三方脚本标签',
                    detail: `SRC: ${Utils.truncateString(scriptElement.src || scriptElement.getAttribute('data-src') || '', 100)}`
                });
                return;
            }
            if (CONFIG.modules.dynamicSystem && ModuleManager.modules.dynamicSystem) {
                ModuleManager.modules.dynamicSystem.handleScriptElement(scriptElement);
            }
        },
        processScriptSource(scriptElement, prop, value) {
            if (!canProcessElement(scriptElement)) return;
            scriptElement.dataset.adProcessedSource = 'true';
            if (CONFIG.modules.thirdPartyBlock && ModuleManager.modules.thirdPartyBlock?.isThirdParty(value)) {
                AdUtils.nuclearRemove(scriptElement, 'thirdPartyBlock', {
                    type: '第三方脚本内容',
                    detail: `${prop}: ${Utils.truncateString(value, 100)}`
                });
                return;
            }
            if (CONFIG.modules.dynamicSystem && ModuleManager.modules.dynamicSystem) {
                ModuleManager.modules.dynamicSystem.handleScriptSource(scriptElement, value);
            }
        },
        checkDynamicContent(htmlElement, contextElement = null) {
            if (!htmlElement || !(htmlElement instanceof Element)) return false;
            const dummyLogElementForContentCheck = document.createElement('span');
            dummyLogElementForContentCheck.dataset.insertionType = contextElement ? contextElement.tagName : 'UNKNOWN_INSERT';
            dummyLogElementForContentCheck.dataset.originalHTML = htmlElement.innerHTML;
            if (contextElement instanceof Element) {
                if (contextElement.id) dummyLogElementForContentCheck.id = contextElement.id;
                if (contextElement.className) dummyLogElementForContentCheck.className = contextElement.className;
            }
            const contentForWhitelistComparison = SharedUtils.getElementContent(dummyLogElementForContentCheck);
            if (Whitelist.isWhitelistedContent(location.hostname, contentForWhitelistComparison)) {
                return false;
            }
            const scripts = htmlElement.querySelectorAll('script');
            for (const script of scripts) {
                if (Whitelist.isWhitelisted(script)) continue;
                if (script.src) {
                    if (ModuleManager.modules.thirdPartyBlock?.isThirdParty(script.src)) return true;
                } else if (script.textContent) {
                    const { dangerLevel } = ASTAnalyzer.calculateDangerLevel(script.textContent);
                    if (dangerLevel >= 3) return true;
                }
            }
            const iframes = htmlElement.querySelectorAll('iframe');
            for (const iframe of iframes) {
                if (Whitelist.isWhitelisted(iframe)) continue;
                if (iframe.src && ModuleManager.modules.thirdPartyBlock?.isThirdParty(iframe.src)) return true;
            }
            if (REGEX.adAttributes.test(htmlElement.outerHTML) || REGEX.jsAdPattern.test(htmlElement.outerHTML)) return true;
            return false;
        }
    };
    const StyleManager = {
        styleElement: null,
        injectedSheets: new Set(),
        inject() {
            if (!CONFIG.modules.main || perf.degraded) return this.remove();
            if (typeof CSSStyleSheet === 'function') {
                let isAdopted = false;
                for (const sheet of document.adoptedStyleSheets) {
                    if (this.injectedSheets.has(sheet)) {
                        isAdopted = true;
                        break;
                    }
                }
                if (!isAdopted) {
                    try {
                        const sheet = new CSSStyleSheet();
                        sheet.replaceSync(`
                            [data-ad-cleaned="true"], [data-ad-nuclear-removed="true"] {
                                all: initial !important;
                                display: none !important;
                                visibility: hidden !important;
                                opacity: 0 !important;
                                position: absolute !important;
                                z-index: -9999 !important;
                                width: 0 !important;
                                height: 0 !important;
                                pointer-events: none !important;
                                overflow: hidden !important;
                                transform: translate(-9999px, -9999px) !important;
                                contain: layout style !important;
                                animation: none !important;
                                transition: none !important;
                                filter: none !important;
                                will-change: auto !important;
                            }
                            [data-ad-cleaned="true"] *,
                            [data-ad-cleaned="true"] *::before,
                            [data-ad-cleaned="true"] *::after,
                            [data-ad-nuclear-removed="true"] *,
                            [data-ad-nuclear-removed="true"] *::before,
                            [data-ad-nuclear-removed="true"] *::after {
                                all: unset !important;
                                display: none !important;
                                visibility: hidden !important;
                                opacity: 0 !important;
                                width: 0 !important;
                                height: 0 !important;
                                pointer-events: none !important;
                                z-index: -9999 !important;
                                contain: layout style !important;
                                animation: none !important;
                                transition: none !important;
                                filter: none !important;
                                will-change: auto !important;
                            }
                        `);
                        document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
                        this.injectedSheets.add(sheet);
                    } catch (e) {}
                }
            }
            if (!this.styleElement || !document.head || !document.head.contains(this.styleElement)) {
                this.styleElement = document.createElement('style');
                this.styleElement.textContent = `
                    @layer adBlocker {
                        *[data-ad-permanent="true"] {
                            animation: none !important;
                            transition: none !important;
                        }
                    }
                `;
                this.styleElement.setAttribute('data-ad-permanent', 'true');
                if (document.head) {
                    document.head.appendChild(this.styleElement);
                } else if (document.documentElement) {
                    document.documentElement.insertBefore(this.styleElement, document.documentElement.firstChild);
                }
            }
            const checkStylesContinuously = () => {
                if (!CONFIG.modules.main || perf.degraded) return;
                if (this.styleElement && (!document.head || !document.head.contains(this.styleElement))) {
                    if (document.head) {
                        document.head.prepend(this.styleElement);
                    } else if (document.documentElement) {
                        document.documentElement.prepend(this.styleElement);
                    }
                }
                if (typeof CSSStyleSheet === 'function') {
                    let foundAdopted = false;
                    for (const sheet of document.adoptedStyleSheets) {
                        if (this.injectedSheets.has(sheet)) {
                            foundAdopted = true;
                            break;
                        }
                    }
                    if (!foundAdopted && this.injectedSheets.size > 0) {
                        const firstSheet = Array.from(this.injectedSheets)[0];
                        if (firstSheet) {
                            document.adoptedStyleSheets = [...document.adoptedStyleSheets, firstSheet];
                        }
                    }
                }
                requestAnimationFrame(checkStylesContinuously);
            };
            if (CONFIG.modules.main && !perf.degraded) {
                requestAnimationFrame(checkStylesContinuously);
            }
        },
        remove() {
            this.injectedSheets.forEach(sheet => {
                document.adoptedStyleSheets = document.adoptedStyleSheets.filter(s => s !== sheet);
            });
            this.injectedSheets.clear();
            if (this.styleElement) {
                this.styleElement.remove();
                this.styleElement = null;
            }
            document.querySelectorAll('style[data-ad-permanent]').forEach(s => s.remove());
        },
        toggle(enable) {
            enable ? this.inject() : this.remove();
        }
    };
    const CSPManager = {
        currentPolicy: null,
        generatePolicy() {
            const merged = {};
            CONFIG.csp.rules.filter(rule => rule.enabled).forEach(rule => {
                const [directive, ...values] = rule.rule.split(/\s+/);
                merged[directive] = (merged[directive] || []).concat(values);
            });
            return Object.entries(merged)
                .map(([k, v]) => `${k} ${[...new Set(v)].join(' ')}`)
                .join('; ');
        },
        inject() {
            this.remove();
            if (!CONFIG.csp.enabled || perf.degraded) return;
            const policy = this.generatePolicy();
            this.currentPolicy = policy;
            const meta = document.createElement('meta');
            meta.httpEquiv = "Content-Security-Policy";
            meta.content = policy;
            if (document.head) {
                document.head.appendChild(meta);
            } else {
                document.documentElement.insertBefore(meta, document.documentElement.firstChild);
            }
        },
        remove() {
            const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
            if (meta) meta.remove();
        },
        toggleRule(ruleId, enable) {
            const rule = CONFIG.csp.rules.find(r => r.id === ruleId);
            if (rule) rule.enabled = enable;
        },
        injectInitialCSP() {
            if (!CONFIG.csp.enabled || perf.degraded) return;
            const initialRules = CONFIG.csp.rules
                .filter(rule => [1, 6].includes(rule.id) && rule.enabled)
                .map(rule => rule.rule)
                .join('; ');
            if (initialRules) {
                const meta = document.createElement('meta');
                meta.httpEquiv = "Content-Security-Policy";
                meta.content = initialRules;
                if (document.head) {
                    document.head.appendChild(meta);
                } else {
                    document.documentElement.insertBefore(meta, document.documentElement.firstChild);
                }
            }
        }
    };
    const Processor = {
        scheduleProcess() {
            if (!CONFIG.modules.main || perf.isProcessing || perf.degraded) return;
            perf.isProcessing = true;
            requestIdleCallback(() => {
                if (!CONFIG.modules.main || perf.degraded) {
                    perf.isProcessing = false;
                    setTimeout(() => Processor.scheduleProcess(), 1000);
                    return;
                }
                const startTime = performance.now();
                const elementsToProcess = Array.from(perf.adElements).filter(el => canProcessElement(el));
                perf.adElements.clear();
                let processedCount = 0;
                for (const element of elementsToProcess) {
                    if (performance.now() - startTime > CONFIG.performance.mutationProcessTimeLimit ||
                        processedCount >= CONFIG.performance.mutationProcessLimit) {
                        for (let i = processedCount; i < elementsToProcess.length; i++) {
                            if (canProcessElement(elementsToProcess[i])) {
                                perf.adElements.add(elementsToProcess[i]);
                            }
                        }
                        perf.isProcessing = false;
                        Processor.scheduleProcess();
                        return;
                    }
                    if (!canProcessElement(element)) {
                        continue;
                    }
                    this.processElement(element);
                    processedCount++;
                }
                perf.isProcessing = false;
                if (perf.adElements.size > 0) {
                    Processor.scheduleProcess();
                }
            }, { timeout: CONFIG.performance.idleCallbackTimeout });
        },
        processElement(element) {
            if (!canProcessElement(element)) return;
            let modulePriority = [...CONFIG.modulePriority];
            if (CONFIG.performance.visibleAreaPriority && Detector.isVisible(element)) {
                const highRisk = CONFIG.performance.highRiskModules;
                modulePriority = [...highRisk, ...modulePriority.filter(m => !highRisk.includes(m))];
            }
            for (const moduleKey of modulePriority) {
                if (moduleKey === 'specialUA') continue;
                if (moduleKey === 'dynamicSystem' && element.tagName === 'SCRIPT') {
                    continue;
                }
                if (moduleKey === 'thirdPartyBlock' && ['SCRIPT', 'IFRAME', 'IMG', 'LINK'].includes(element.tagName.toUpperCase())) {
                    continue;
                }
                if (ModuleManager.run(moduleKey, element)) {
                    return;
                }
            }
            if (ModuleManager.modules.dynamicSystem.checkCoreProcessor(element)) {
                return;
            }
        },
        collectInitialElements() {
            if (!CONFIG.modules.main || perf.degraded) return;
            const treeWalker = document.createTreeWalker(
                document.documentElement,
                NodeFilter.SHOW_ELEMENT,
                null,
                false
            );
            while (treeWalker.nextNode()) {
                const element = treeWalker.currentNode;
                if (!canProcessElement(element)) continue;
                perf.adElements.add(element);
            }
        }
    };
    const mainObserver = new MutationObserver(mutations => {
        if (!CONFIG.modules.main || perf.degraded) return;
        mutations.forEach(mutation => {
            if (mutation.type === 'childList') {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 8 && typeof node.data === 'string' && node.data.includes('Removed ad')) {
                        try {
                            if (node.parentNode) node.parentNode.removeChild(node);
                        } catch (e) {}
                    }
                });
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 1) {
                        if (!canProcessElement(node)) return;
                        if (node.matches('[data-ad-permanent="true"],[data-ad-cleaned="true"],[data-ad-nuclear-removed="true"]')) {
                            if (AdUtils.safeRemove(node, 'mutationClean', {
                                type: 'DOM清理',
                                detail: '检测到被移除元素的重新插入'
                            })) return;
                        }
                        const walker = document.createTreeWalker(
                            node,
                            NodeFilter.SHOW_ELEMENT,
                            {
                                acceptNode: (n) => {
                                    if (!(n instanceof Element)) return NodeFilter.FILTER_SKIP;
                                    if (!canProcessElement(n)) return NodeFilter.FILTER_SKIP;
                                    return n.hasAttribute('data-ad-permanent') ||
                                        n.hasAttribute('data-ad-cleaned') ||
                                        n.hasAttribute('data-ad-nuclear-removed') ?
                                        NodeFilter.FILTER_ACCEPT :
                                        NodeFilter.FILTER_SKIP;
                                }
                            }
                        );
                        let currentNode;
                        while ((currentNode = walker.nextNode())) {
                            AdUtils.safeRemove(currentNode, 'mutationDepthClean', {
                                type: 'DOM深度清理',
                                detail: '检测到被移除元素的子元素'
                            });
                        }
                        if (canProcessElement(node)) {
                            perf.adElements.add(node);
                        }
                    }
                });
            } else if (mutation.type === 'attributes') {
                if (!canProcessElement(mutation.target)) return;
                if (mutation.target instanceof Element) {
                    if (mutation.target.hasAttribute('data-ad-permanent') &&
                        mutation.attributeName !== 'data-ad-permanent') {
                        Utils.removeAttributeSafely(mutation.target, mutation.attributeName);
                    }
                    if (canProcessElement(mutation.target)) {
                        perf.adElements.add(mutation.target);
                    }
                }
            }
        });
        if (perf.adElements.size > 0 && !perf.isProcessing) {
            debouncedScheduleProcess();
        }
    });
    const debouncedScheduleProcess = Utils.debounce(Processor.scheduleProcess, CONFIG.performance.debounceMutationDelay);
    const UIController = {
        init() {
            this.loadConfig();
            this._applyModuleDependencies();
            Whitelist.init();
            this.registerMenuCommands();
            StyleManager.toggle(CONFIG.modules.main);
        },
        _applyModuleDependencies() {
            const detectionModulesControlledByMain = ['dynamicSystem', 'layoutSystem', 'mergedMediaSystem', 'thirdPartyBlock'];
            CONFIG.modules.main = detectionModulesControlledByMain.some(key => CONFIG.modules[key]);
        },
        registerMenuCommands() {
            GM_registerMenuCommand(
                `🔘 主开关 [${CONFIG.modules.main ? '✅' : '❌'}]`,
                () => this.toggleMain()
            );
            Object.entries(CONFIG.moduleNames).forEach(([key, name]) => {
                if (key === 'main') return;
                GM_registerMenuCommand(
                    `${name} [${CONFIG.modules[key] ? '✅' : '❌'}]`,
                    () => this.toggleModule(key, name)
                );
            });
            GM_registerMenuCommand('📜 查看拦截日志', () => Logs.showInAlert());
            GM_registerMenuCommand('🧹 清空日志', () => Logs.clear());
            GM_registerMenuCommand('🚫 清空当前域名白名单', () => {
                if (confirm(`确定清空当前域名 (${location.hostname}) 的白名单吗?`)) {
                    Whitelist.clearCurrentDomain();
                    GM_notification('白名单已清空', `当前域名 (${location.hostname}) 的白名单已清空`);
                    location.reload();
                }
            });
            GM_registerMenuCommand('🛡️ CSP策略管理', () => this.manageCSP());
            GM_registerMenuCommand('🔄 重置设置', () => this.resetSettings());
        },
        toggleMain() {
            const newState = !CONFIG.modules.main;
            const modulesToToggle = ['dynamicSystem', 'layoutSystem', 'mergedMediaSystem', 'thirdPartyBlock'];
            modulesToToggle.forEach(key => {
                CONFIG.modules[key] = newState;
            });
            this._applyModuleDependencies();
            this.saveConfig();
            location.reload();
        },
        toggleModule(key, name) {
            CONFIG.modules[key] = !CONFIG.modules[key];
            this._applyModuleDependencies();
            this.saveConfig();
            location.reload();
        },
        manageCSP() {
            const rulesDisplay = CONFIG.csp.rules
                .map(r => `${r.id}. ${r.name} (${r.enabled ? '✅' : '❌'})`)
                .join('\n');
            let input = prompt(
                `当前CSP策略状态: ${CONFIG.csp.enabled ? '✅' : '❌'}\n\n` +
                "当前策略规则:\n" + rulesDisplay + "\n\n" +
                "输入选项:\nenable: 开启策略\ndisable: 关闭策略\n" +
                "修改规则示例:1on 启用规则1\n23off 禁用规则2和规则3\n\n" +
                "请输入你的选择:",
                ""
            );
            if (input === null) return;
            input = input.trim().toLowerCase();
            if (input === 'enable') {
                CONFIG.csp.enabled = true;
                this.saveConfig();
                CSPManager.inject();
                alert("CSP策略已启用");
                location.reload();
            } else if (input === 'disable') {
                CONFIG.csp.enabled = false;
                this.saveConfig();
                CSPManager.remove();
                alert("CSP策略已禁用");
                location.reload();
            } else if (/^\d+(?:on|off)$/i.test(input)) {
                this.modifyCSPRules(input);
            } else {
                alert("无效输入");
            }
        },
        modifyCSPRules(actionInput) {
            const matches = actionInput.match(/^(\d+)(on|off)$/i);
            if (matches) {
                const ruleIds = matches[1].split('').map(Number);
                const enable = matches[2].toLowerCase() === 'on';
                let updatedRules = [];
                ruleIds.forEach(id => {
                    const rule = CONFIG.csp.rules.find(r => r.id === id);
                    if (rule) {
                        rule.enabled = enable;
                        updatedRules.push(id);
                    }
                });
                if (updatedRules.length > 0) {
                    this.saveConfig();
                    CSPManager.inject();
                    alert(`规则 ${updatedRules.join(',')} 已更新为 ${enable ? '启用' : '禁用'}`);
                    location.reload();
                } else {
                    alert("未找到匹配的规则ID");
                }
            } else {
                alert("输入格式错误,请按示例输入如'1on'或'123off'");
            }
        },
        resetSettings() {
            if (confirm("确定要重置所有设置吗?这将清空设置和白名单")) {
                Object.assign(CONFIG.modules, DEFAULT_MODULES);
                this._applyModuleDependencies();
                CONFIG.csp.enabled = false;
                CONFIG.csp.rules = DEFAULT_CSP_RULES.map(rule => ({ ...rule }));
                Whitelist.clearAll();
                this.saveConfig();
                CSPManager.remove();
                Logs.clear();
                alert("所有设置已重置为默认值");
                location.reload();
            }
        },
        saveConfig() {
            try {
                GM_setValue(`adblockConfig_${location.hostname}`, JSON.stringify({
                    modules: CONFIG.modules,
                    csp: CONFIG.csp,
                    whitelist: CONFIG.whitelist
                }));
            } catch (e) {
                console.error("Error saving adblock config:", e);
            }
        },
        loadConfig() {
            try {
                const savedConfig = JSON.parse(GM_getValue(`adblockConfig_${location.hostname}`, '{}'));
                if (savedConfig.modules) {
                    Object.keys(CONFIG.modules).forEach(key => {
                        if (savedConfig.modules.hasOwnProperty(key)) {
                            CONFIG.modules[key] = savedConfig.modules[key];
                        }
                    });
                }
                if (savedConfig.csp) {
                    CONFIG.csp.enabled = savedConfig.csp.enabled;
                    CONFIG.csp.rules = DEFAULT_CSP_RULES.map(defaultRule => {
                        const savedRule = savedConfig.csp.rules.find(sr => sr.id === defaultRule.id);
                        return savedRule ? { ...defaultRule, enabled: savedRule.enabled } : defaultRule;
                    });
                }
                if (savedConfig.whitelist) {
                    CONFIG.whitelist = savedConfig.whitelist;
                }
            } catch (e) {
                console.error("Error loading adblock config, resetting to default:", e);
                Object.assign(CONFIG.modules, DEFAULT_MODULES);
                CONFIG.csp.enabled = false;
                CONFIG.csp.rules = DEFAULT_CSP_RULES.map(rule => ({ ...rule }));
                CONFIG.whitelist = {};
            }
        }
    };
    const ASTAnalyzer = (function() {
        return {
            getObfuscationRules: function(minLevel) {
                return REGEX.obfuscationPatterns.filter(r => r.riskLevel >= minLevel);
            },
            checkObfuscation: function(code, minLevel) {
                const rules = this.getObfuscationRules(minLevel);
                for (let i = 0; i < rules.length; i++) {
                    try {
                        if (rules[i].pattern.test(code)) {
                            return { found: true, type: rules[i].type, ruleName: rules[i].type };
                        }
                    } catch (e) {}
                }
                return { found: false, type: null, ruleName: null };
            },
            checkHighRiskPatterns: function(code) {
                for (const p of REGEX.obfuscationPatterns) {
                    if (p.riskLevel >= 3 && p.pattern.test(code)) {
                        return { found: true, type: p.type, ruleName: p.type };
                    }
                }
                return { found: false, type: null, ruleName: null };
            },
            calculateDangerLevel: function(content) {
                let dangerLevel = 0;
                let specificRules = new Set();
                const generalObfResult = this.checkObfuscation(content, 2);
                if (generalObfResult.found) {
                    dangerLevel += 2;
                    specificRules.add(generalObfResult.type);
                }
                const higherObfResult = this.checkObfuscation(content, 3);
                if (higherObfResult.found) {
                    dangerLevel += 3;
                    specificRules.add(higherObfResult.type);
                }
                if (REGEX.jsAdPattern.test(content)) {
                    dangerLevel += 2;
                    specificRules.add('可疑JS广告模式');
                }
                const highRiskPatternsResult = this.checkHighRiskPatterns(content);
                if (highRiskPatternsResult.found) {
                    if (!specificRules.has(highRiskPatternsResult.type)) {
                        dangerLevel += 3;
                    }
                    specificRules.add(highRiskPatternsResult.type);
                }
                return { dangerLevel, specificRules: Array.from(specificRules) };
            }
        };
    })();
    ModuleManager.register('thirdPartyBlock', {
        originals: {
            createElement: null,
            setAttribute: null,
            appendChild: null,
            fetch: null,
            xhrOpen: null,
            documentWrite: null,
            documentWriteln: null,
            insertAdjacentHTML: null
        },
        blockedUrls: new Set(),
        enabled: false,
        hostCache: new Map(),
        init() {
            if (CONFIG.modules.thirdPartyBlock) this.enable();
            else this.disable();
        },
        enable() {
            if (this.enabled) return;
            this.enabled = true;
            this.originals.createElement = document.createElement;
            this.originals.setAttribute = Element.prototype.setAttribute;
            this.originals.appendChild = Node.prototype.appendChild;
            this.originals.fetch = window.fetch;
            this.originals.xhrOpen = XMLHttpRequest.prototype.open;
            this.originals.documentWrite = document.write;
            this.originals.documentWriteln = document.writeln;
            this.originals.insertAdjacentHTML = Element.prototype.insertAdjacentHTML;
            document.createElement = this.wrapElementCreation.bind(this);
            Element.prototype.setAttribute = this.wrapSetAttribute.bind(this);
            Node.prototype.appendChild = this.wrapAppendChild.bind(this);
            window.fetch = this.wrapFetch.bind(this);
            XMLHttpRequest.prototype.open = this.wrapXHROpen.bind(this);
            document.write = this.wrapDocumentWrite.bind(this);
            document.writeln = this.wrapDocumentWriteln.bind(this);
            Element.prototype.insertAdjacentHTML = this.wrapInsertAdjacentHTML.bind(this);
            document.addEventListener('beforescriptexecute', this.handleBeforeScriptExecute.bind(this));
        },
        disable() {
            if (!this.enabled) return;
            this.enabled = false;
            document.createElement = this.originals.createElement;
            Element.prototype.setAttribute = this.originals.setAttribute;
            Node.prototype.appendChild = this.originals.appendChild;
            window.fetch = this.originals.fetch;
            XMLHttpRequest.prototype.open = this.originals.xhrOpen;
            document.write = this.originals.documentWrite;
            document.writeln = this.originals.documentWriteln;
            Element.prototype.insertAdjacentHTML = this.originals.insertAdjacentHTML;
            document.removeEventListener('beforescriptexecute', this.handleBeforeScriptExecute);
        },
        logAndBlock(element, type, url, detail = '') {
            if (!canProcessElement(element)) {
                return false;
            }
            if (this.blockedUrls.has(url)) {
                return false;
            }
            this.blockedUrls.add(url);
            const finalDetail = `URL: ${Utils.truncateString(url, 150)}` + (detail ? `, ${detail}` : '');
            const isScriptOrIframe = element?.tagName === 'SCRIPT' || element?.tagName === 'IFRAME';
            const removed = isScriptOrIframe ?
                AdUtils.nuclearRemove(element, 'thirdPartyBlock', {
                    type: `第三方${type}`,
                    detail: finalDetail
                }) :
                AdUtils.safeRemove(element, 'thirdPartyBlock', {
                    type: `第三方${type}`,
                    detail: finalDetail
                });
            return removed;
        },
        isThirdParty(url) {
            if (!url || typeof url !== 'string') return false;
            if (url.startsWith('data:') || url.startsWith('blob:') || url.startsWith('about:blank')) return false;
            const currentHost = new URL(location.href).hostname;
            if (this.hostCache.has(url)) {
                return this.hostCache.get(url);
            }
            try {
                const resourceHost = new URL(url, location.href).hostname;
                const isTP = !(resourceHost.endsWith(`.${currentHost}`) || resourceHost === currentHost);
                this.hostCache.set(url, isTP);
                return isTP;
            } catch (e) {
                this.hostCache.set(url, true);
                return true;
            }
        },
        wrapSetAttribute(name, value) {
            if (!canProcessElement(this) || perf.degraded) return this.originals.setAttribute.call(this, name, value);
            if (name === 'src' || name === 'href' || name === 'data-src') {
                if (typeof value === 'string' && this.isThirdParty(value)) {
                    if (this.logAndBlock(this, `${this.tagName}属性拦截`, value, `属性: ${name}`)) {
                        return;
                    }
                }
            }
            return this.originals.setAttribute.call(this, name, value);
        },
        wrapAppendChild(node) {
            if (!canProcessElement(this) || !canProcessElement(node) || perf.degraded) {
                return this.originals.appendChild.call(this, node);
            }
            if (node.nodeType === 1) {
                const src = node.src || node.getAttribute('data-src') || node.href || '';
                if (src && this.isThirdParty(src)) {
                    if (this.logAndBlock(node, `${node.tagName}插入拦截`, src, `父元素: ${this.tagName}`)) {
                        return null;
                    }
                }
            }
            return this.originals.appendChild.call(this, node);
        },
        wrapElementCreation(tagName) {
            const element = this.originals.createElement.call(document, tagName);
            const lowerTag = tagName.toLowerCase();
            if (['script', 'iframe', 'img', 'link'].includes(lowerTag)) {
                return new Proxy(element, {
                    set: (target, prop, value) => {
                        if (!canProcessElement(target) || perf.degraded) {
                            target[prop] = value;
                            return true;
                        }
                        if ((prop === 'src' || prop === 'href' || prop === 'data-src') && typeof value === 'string') {
                            if (this.isThirdParty(value)) {
                                this.logAndBlock(target, `${target.tagName}创建属性设置`, value, `属性: ${prop}`);
                                target[prop] = '';
                                target.setAttribute('data-tpi-blocked', 'true');
                                return true;
                            }
                        }
                        target[prop] = value;
                        return true;
                    },
                    get: (target, prop) => {
                        if (!canProcessElement(target) || perf.degraded) {
                            return Reflect.get(target, prop);
                        }
                        if ((prop === 'src' || prop === 'href' || prop === 'data-src') && target.hasAttribute('data-tpi-blocked')) {
                            return '';
                        }
                        return Reflect.get(target, prop);
                    }
                });
            }
            return element;
        },
        wrapFetch(input, init) {
            if (perf.degraded) return this.originals.fetch(input, init);
            const url = typeof input === 'string' ? input : input?.url;
            if (url && typeof url === 'string') {
                const dummyElement = document.createElement('span');
                dummyElement.dataset.url = url;
                dummyElement.dataset.tag = 'FETCH';
                dummyElement.dataset.detail = `Method: ${init?.method || 'GET'}`;
                const logContent = SharedUtils.getElementContent(dummyElement);
                if (Whitelist.isWhitelistedContent(location.hostname, logContent)) {
                    return this.originals.fetch(input, init);
                }
                if (this.isThirdParty(url)) {
                    this.logAndBlock(dummyElement, 'Fetch请求', url, `Method: ${init?.method || 'GET'}`);
                    return Promise.reject(new Error('第三方请求被拦截'));
                }
            }
            return this.originals.fetch(input, init);
        },
        wrapXHROpen(method, url) {
            if (perf.degraded) return this.originals.xhrOpen.call(this, method, url);
            if (url && typeof url === 'string') {
                const dummyElement = document.createElement('span');
                dummyElement.dataset.url = url;
                dummyElement.dataset.tag = 'XHR';
                dummyElement.dataset.detail = `Method: ${method}`;
                const logContent = SharedUtils.getElementContent(dummyElement);
                if (Whitelist.isWhitelistedContent(location.hostname, logContent)) {
                    return this.originals.xhrOpen.call(this, method, url);
                }
                if (this.isThirdParty(url)) {
                    this.logAndBlock(dummyElement, 'XHR请求', url, `Method: ${method}`);
                    this._blocked = true;
                    return;
                }
            }
            return this.originals.xhrOpen.call(this, method, url);
        },
        handleHTMLInsertion(html, insertionType, originalFunction, contextElement = null) {
            if (perf.degraded) return originalFunction(html);
            const dummyLogElementForContentCheck = document.createElement('span');
            dummyLogElementForContentCheck.dataset.insertionType = insertionType;
            dummyLogElementForContentCheck.dataset.originalHTML = html;
            if (contextElement instanceof Element) {
                if (contextElement.id) dummyLogElementForContentCheck.id = contextElement.id;
                if (contextElement.className) dummyLogElementForContentCheck.className = contextElement.className;
            }
            const contentForWhitelistComparison = SharedUtils.getElementContent(dummyLogElementForContentCheck);
            if (Whitelist.isWhitelistedContent(location.hostname, contentForWhitelistComparison)) {
                return originalFunction(html);
            }
            const tempDiv = document.createElement('div');
            tempDiv.innerHTML = html;
            if (AdUtils.checkDynamicContent(tempDiv, contextElement)) {
                AdUtils.safeRemove(dummyLogElementForContentCheck, 'thirdPartyBlock', {
                    type: `动态插入HTML内容`,
                    detail: `插入方式: ${insertionType}, 包含可疑内容`
                });
                return;
            }
            return originalFunction(html);
        },
        wrapDocumentWrite(content) {
            return this.handleHTMLInsertion(content, 'document.write', this.originals.documentWrite);
        },
        wrapDocumentWriteln(content) {
            return this.handleHTMLInsertion(content, 'document.writeln', this.originals.documentWriteln);
        },
        wrapInsertAdjacentHTML(position, html) {
            return this.handleHTMLInsertion(html, `insertAdjacentHTML:${position}`,
                (processedHtml) => this.originals.insertAdjacentHTML.call(this, position, processedHtml), this);
        },
        handleBeforeScriptExecute(e) {
            const script = e.target;
            if (!canProcessElement(script) || perf.degraded) return;
            const src = script.src || script.getAttribute('data-src') || '';
            if (src && this.isThirdParty(src)) {
                if (this.logAndBlock(script, '预执行脚本', src)) {
                    e.preventDefault();
                    e.stopImmediatePropagation();
                    script.remove();
                    return;
                }
            }
        },
        check(el) {
            if (!canProcessElement(el) || perf.degraded || !this.enabled) return false;
            if (!(el instanceof Element)) return false;
            if (el.dataset.adCleaned || el.dataset.adNuclearRemoved) return false;
            const src = el.src || el.getAttribute('data-src') || el.href || '';
            if (src && this.isThirdParty(src)) {
                const tagName = el.tagName;
                if (['SCRIPT', 'IFRAME', 'IMG', 'LINK'].includes(tagName.toUpperCase())) {
                    return this.logAndBlock(el, 'DOM元素检查', src, `标签: ${tagName}`);
                }
            }
            const style = Detector.getCachedStyle(el);
            if (style?.backgroundImage && style.backgroundImage.includes('url(')) {
                const bgUrlMatch = style.backgroundImage.match(/url\((['"]?)(.*?)\1\)/);
                if (bgUrlMatch && bgUrlMatch[2] && this.isThirdParty(bgUrlMatch[2])) {
                    return this.logAndBlock(el, '背景图片', bgUrlMatch[2], `CSS背景: ${el.tagName}`);
                }
            }
            return false;
        }
    });
    ModuleManager.register('dynamicSystem', {
        checkedScripts: new WeakSet(),
        scriptAnalysisQueue: [],
        isProcessingAnalysisQueue: false,
        enabled: false,
        init() {
            if (CONFIG.modules.dynamicSystem) {
                this.enable();
            } else {
                this.disable();
            }
            this.startScriptRecoveryCheck();
            this.startAnalysisQueueProcessor();
        },
        enable() {
            if (this.enabled || perf.degraded) return;
            this.enabled = true;
            AdUtils.initScriptHooks();
        },
        disable() {
            if (!this.enabled) return;
            this.enabled = false;
            this.scriptAnalysisQueue = [];
            AdUtils.cleanupScriptHooks();
        },
        handleScriptElement(scriptEl) {
            if (!canProcessElement(scriptEl) || perf.degraded) return;
            if (scriptEl.dataset.adCleaned || scriptEl.dataset.adNuclearRemoved) return;
            if (!this.enabled) return;
            this.checkedScripts.add(scriptEl);
            if (this.quickDetect(scriptEl)) {
                return;
            }
            this.scriptAnalysisQueue.push(scriptEl);
            if (!this.isProcessingAnalysisQueue) {
                this.processAnalysisQueue();
            }
        },
        handleScriptSource(scriptEl, sourceValue) {
            if (!canProcessElement(scriptEl) || perf.degraded) return;
            if (scriptEl.dataset.adCleaned || scriptEl.dataset.adNuclearRemoved) return;
            if (!this.enabled) return;
            this.checkedScripts.add(scriptEl);
            const highRiskResult = ASTAnalyzer.checkHighRiskPatterns(sourceValue);
            if (highRiskResult.found) {
                AdUtils.nuclearRemove(scriptEl, 'dynamicSystem', {
                    type: '动态脚本源快速检测',
                    detail: '源内容命中高危模式',
                    ruleName: highRiskResult.type
                });
                return;
            }
            this.scriptAnalysisQueue.push(scriptEl);
            if (!this.isProcessingAnalysisQueue) {
                this.processAnalysisQueue();
            }
        },
        async processAnalysisQueue() {
            if (!this.enabled || this.isProcessingAnalysisQueue || this.scriptAnalysisQueue.length === 0 || perf.degraded) return;
            this.isProcessingAnalysisQueue = true;
            while (this.scriptAnalysisQueue.length > 0) {
                const script = this.scriptAnalysisQueue.shift();
                if (!document.contains(script) || !canProcessElement(script) || script.dataset.adCleaned || script.dataset.adNuclearRemoved) {
                    continue;
                }
                await this.analyzeScript(script);
                if (this.scriptAnalysisQueue.length > 5 || performance.now() % 100 < 10) {
                    await new Promise(resolve => requestIdleCallback(resolve, { timeout: 50 }));
                }
            }
            this.isProcessingAnalysisQueue = false;
        },
        async analyzeScript(scriptEl) {
            if (!canProcessElement(scriptEl) || perf.degraded) return;
            if (scriptEl.dataset.adCleaned || scriptEl.dataset.adNuclearRemoved) return;
            if (!this.enabled) return;
            try {
                if (scriptEl.src) {
                    await this.analyzeRemoteScript(scriptEl);
                } else {
                    await this.analyzeInlineScript(scriptEl);
                }
            } catch (e) {}
        },
        async analyzeRemoteScript(scriptEl) {
            if (!canProcessElement(scriptEl) || perf.degraded) return;
            if (scriptEl.dataset.adCleaned || scriptEl.dataset.adNuclearRemoved) return;
            if (!this.enabled) return;
            const controller = new AbortController();
            AdUtils.abortControllers.set(scriptEl, controller);
            try {
                const response = await fetch(scriptEl.src, {
                    signal: controller.signal,
                    priority: 'low'
                });
                const reader = response.body.getReader();
                const { value, done } = await reader.read();
                if (done) return;
                const chunk = new TextDecoder().decode(value);
                reader.cancel();
                const highRiskResult = ASTAnalyzer.checkHighRiskPatterns(chunk);
                if (highRiskResult.found) {
                    AdUtils.nuclearRemove(scriptEl, 'dynamicSystem', {
                        type: '流式特征阻断',
                        detail: `检测到脚本前${chunk.length}字节风险内容`,
                        ruleName: highRiskResult.type
                    });
                }
            } catch (e) {
                if (e.name === 'AbortError') {
                } else {
                }
            } finally {
                AdUtils.abortControllers.delete(scriptEl);
            }
        },
        async analyzeInlineScript(scriptEl) {
            if (!canProcessElement(scriptEl) || perf.degraded) return;
            if (scriptEl.dataset.adCleaned || scriptEl.dataset.adNuclearRemoved) return;
            if (!this.enabled) return;
            const content = scriptEl.textContent;
            const { dangerLevel, specificRules } = ASTAnalyzer.calculateDangerLevel(content);
            if (dangerLevel >= 3) {
                AdUtils.nuclearRemove(scriptEl, 'dynamicSystem', {
                    type: '内联脚本风险',
                    detail: `危险级别: ${dangerLevel}`,
                    ruleName: specificRules.join('; ')
                });
            }
        },
        quickDetect(scriptEl) {
            if (!canProcessElement(scriptEl) || perf.degraded) return false;
            if (scriptEl.dataset.adCleaned || scriptEl.dataset.adNuclearRemoved) return false;
            if (!this.enabled) return false;
            const attrs = Array.from(scriptEl.attributes);
            const shortVarPattern = /^[a-z\d]{1,3}$/i;
            const signaturePattern = /^(?:[\da-f]{32}|[\w+/=]{40,})$/i;
            const alphanumAlternate = /(?:[a-z]\d|\d[a-z]){5,}/gi;
            let removed = false;
            for (const attr of attrs) {
                const isShortVar = shortVarPattern.test(attr.name);
                const isSignatureValue = signaturePattern.test(attr.value);
                const isAlphanumAlternateValue = (typeof attr.value === 'string' && attr.value.match(alphanumAlternate)?.length > 3);
                const isDynamicName = /\[(?:0x[a-f\d]+|\d+)\]/.test(attr.name);
                const isLongComplexValue = (typeof attr.value === 'string' && attr.value.includes(';') && attr.value.length > 60);
                const isLongName = attr.name.length > 20;
                let ruleName = '';
                let detail = '';
                if (isShortVar && (isSignatureValue || isAlphanumAlternateValue)) {
                    ruleName = `短变量名/${isSignatureValue ? '签名' : '字母数字交替'}混淆`;
                    detail = `短变量名结合签名/编码值: ${attr.name}=${attr.value.slice(0, 50)}`;
                } else if (isLongName) {
                    ruleName = '超长属性名混淆';
                    detail = `超长属性名: ${attr.name.slice(0, 50)}`;
                } else if (isDynamicName) {
                    ruleName = '动态属性名混淆';
                    detail = `动态属性名: ${attr.name.slice(0, 50)}`;
                } else if (isLongComplexValue) {
                    ruleName = '复杂内联属性值混淆';
                    detail = `复杂内联属性值: ${attr.name}=${attr.value.slice(0, 50)}`;
                }
                if (ruleName) {
                    removed = AdUtils.nuclearRemove(scriptEl, 'dynamicSystem', {
                        type: '属性混淆快速检测',
                        detail: detail,
                        ruleName: ruleName
                    });
                    if (removed) return true;
                }
            }
            if (!scriptEl.src && scriptEl.textContent) {
                const content = scriptEl.textContent;
                const highRiskResult = ASTAnalyzer.checkHighRiskPatterns(content);
                if (highRiskResult.found) {
                    removed = AdUtils.nuclearRemove(scriptEl, 'dynamicSystem', {
                        type: '内联脚本快速检测',
                        detail: '内联脚本命中高危模式',
                        ruleName: highRiskResult.type
                    });
                    if (removed) return true;
                }
                const specificObfResult = ASTAnalyzer.checkObfuscation(content, 5);
                if (specificObfResult.found) {
                    removed = AdUtils.nuclearRemove(scriptEl, 'dynamicSystem', {
                        type: '内联脚本结构性混淆',
                        detail: `检测到高风险结构性混淆: ${specificObfResult.ruleName}`,
                        ruleName: specificObfResult.ruleName
                    });
                    if (removed) return true;
                }
            }
            return removed;
        },
        startScriptRecoveryCheck() {
            setInterval(() => {
                if (!this.enabled || perf.degraded) return;
                document.querySelectorAll('script:not([data-ad-cleaned]):not([data-ad-nuclear-removed]):not([data-ad-processed-hook]):not([data-ad-processed-source])').forEach(script => {
                    if (!canProcessElement(script) || perf.degraded) return;
                    this.handleScriptElement(script);
                });
            }, 1000);
        },
        startAnalysisQueueProcessor() {
            setInterval(() => {
                if (!this.enabled || perf.degraded) return;
                if (!this.isProcessingAnalysisQueue && this.scriptAnalysisQueue.length > 0) {
                    this.processAnalysisQueue();
                }
            }, 500);
        },
        check(el) {
            if (!canProcessElement(el) || perf.degraded || !this.enabled) return false;
            return false;
        },
        checkCoreProcessor(el) {
            if (!canProcessElement(el) || !this.enabled || perf.degraded) return false;
            const shortVarPattern = /^[a-z\d]{1,3}$/i;
            const signaturePattern = /^(?:[\da-f]{32}|[\w+/=]{40,})$/i;
            const alphanumAlternate = /(?:[a-z]\d|\d[a-z]){5,}/gi;
            const isObfuscated = Array.from(el.attributes).some(attr => {
                const isShortVar = shortVarPattern.test(attr.name);
                const isObfuscatedValue = signaturePattern.test(attr.value) ||
                    (typeof attr.value === 'string' && attr.value.match(alphanumAlternate)?.length > 3);
                const isDynamicName = /\[(?:0x[a-f\d]+|\d+)\]/.test(attr.name);
                return (isShortVar && isObfuscatedValue) ||
                    attr.name.length > 20 ||
                    isDynamicName ||
                    (typeof attr.value === 'string' && attr.value.includes(';') && attr.value.length > 60);
            });
            if (isObfuscated) {
                return AdUtils.safeRemove(el, 'dynamicSystem', {
                    type: '核心检测: 可疑混淆属性',
                    detail: `元素属性疑似混淆`
                });
            }
            if (el.id && (
                el.id.length > CONFIG.protectionRules.dynamicIdLength ||
                REGEX.dynamicId.test(el.id)
            )) {
                return AdUtils.safeRemove(el, 'dynamicSystem', {
                    type: '核心检测: 可疑动态ID',
                    detail: `ID特征: ${Utils.truncateString(el.id, 50)}`
                });
            }
            if (el.tagName === 'A') {
                const href = el.getAttribute('href') || '';
                if (href.startsWith('javascript:') && REGEX.jsAdPattern.test(href)) {
                    return AdUtils.nuclearRemove(el, 'dynamicSystem', {
                        type: '核心检测: 可疑JS链接广告',
                        detail: `执行代码: ${Utils.truncateString(href, 100)}`,
                        regex: [REGEX.jsAdPattern.source]
                    });
                }
            }
            return false;
        }
    });
    ModuleManager.register('layoutSystem', {
        enabled: false,
        LAYOUT_SEMANTIC_WHITELIST_TAGS: new Set([
            'HEADER', 'FOOTER', 'NAV', 'ASIDE', 'MAIN', 'ARTICLE', 'SECTION', 'DIV', 'SPAN',
            'BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'FORM', 'LABEL', 'OPTION', 'DATALIST', 'OPTGROUP',
            'IMG', 'SVG', 'I', 'B', 'STRONG', 'EM', 'SMALL', 'BR', 'HR',
            'UL', 'OL', 'LI', 'DL', 'DT', 'DD',
            'TABLE', 'THEAD', 'TBODY', 'TR', 'TH', 'TD', 'TFOOT', 'CAPTION', 'COLGROUP', 'COL',
            'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'BLOCKQUOTE', 'PRE', 'CODE',
            'PROGRESS', 'CANVAS', 'AUDIO', 'VIDEO', 'SOURCE', 'TRACK', 'EMBED', 'OBJECT',
            'DIALOG', 'DETAILS', 'SUMMARY', 'FIGURE', 'FIGCAPTION', 'PICTURE'
        ]),
        LAYOUT_SEMANTIC_WHITELIST_CLASSES: new Set([
            'modal', 'navbar', 'toolbar', 'menu', 'button', 'link', 'icon', 'spinner', 'loader', 'carousel', 'slider',
            'tab', 'tabs', 'accordion', 'overlay', 'backdrop', 'dropdown-menu', 'tooltip', 'popover',
            'alert', 'toast', 'notification', 'header', 'footer', 'nav', 'sidebar', 'content', 'main',
            'wrapper', 'container', 'item', 'card', 'box', 'panel', 'widget', 'title', 'text', 'image',
            'scroll-container', 'scroller', 'lazyload', 'placeholder', 'skeleton', 'skip-link', 'sr-only',
            'btn', 'form-control', 'input-group', 'badge', 'chip', 'tag', 'avatar', 'thumbnail', 'product-image', 'user-icon',
            'post-content', 'news-article', 'article-body', 'ad-container-false', 'footer-bottom', 'back-to-top', 'scroll-top',
            'cookie-banner', 'cookie-consent', 'gdpr-banner', 'privacy-policy', 'message-bar', 'mobile-nav', 'offcanvas-menu'
        ]),
        init() {
            if (CONFIG.modules.layoutSystem) this.enable();
            else this.disable();
        },
        enable() {
            if (this.enabled || perf.degraded) return;
            this.enabled = true;
        },
        disable() {
            this.enabled = false;
        },
        isLegitimateSemanticElement(el) {
            if (!el || !(el instanceof Element)) return false;
            const tagName = el.tagName.toUpperCase();
            const classList = Array.from(el.classList);
            if (this.LAYOUT_SEMANTIC_WHITELIST_TAGS.has(tagName)) {
                if (['DIV', 'SPAN'].includes(tagName)) {
                    if (classList.some(cls => this.LAYOUT_SEMANTIC_WHITELIST_CLASSES.has(cls.toLowerCase())) ||
                        el.hasAttribute('role') || el.hasAttribute('aria-label') || el.hasAttribute('aria-hidden') || el.hasAttribute('tabindex')) {
                        return true;
                    }
                    if (el.textContent.trim().length > 50 && el.children.length > 2 && !Utils.isAdCharacteristic(el)) {
                        return true;
                    }
                    const rect = el.getBoundingClientRect();
                    if ((rect.width > 0 && rect.width < 20 && rect.height > 0 && rect.height < 20) && (classList.some(cls => cls.includes('icon') || cls.includes('spinner') || cls.includes('loader') || cls.includes('placeholder')) || el.hasAttribute('aria-hidden'))) {
                        return true;
                    }
                } else if (['IMG', 'SVG', 'I', 'PICTURE'].includes(tagName)) {
                    const altText = el.getAttribute('alt')?.toLowerCase() || '';
                    const ariaLabel = el.getAttribute('aria-label')?.toLowerCase() || '';
                    if (altText.length > 5 && !REGEX.adAttributes.test(altText) ||
                        ariaLabel.length > 5 && !REGEX.adAttributes.test(ariaLabel) ||
                        classList.some(cls => cls.includes('icon') || cls.includes('logo') || cls.includes('avatar') || cls.includes('thumbnail')) ||
                        el.hasAttribute('aria-hidden')
                    ) {
                        return true;
                    }
                    const rect = el.getBoundingClientRect();
                    if (rect.width === 1 && rect.height === 1 && !el.hasAttribute('aria-hidden') && !classList.some(cls => cls.includes('icon') || cls.includes('logo'))) {
                        return false;
                    }
                    return true;
                } else {
                    return true;
                }
            }
            const role = el.getAttribute('role');
            if (role && (
                role === 'dialog' || role === 'button' || role === 'link' || role === 'navigation' ||
                role === 'banner' || role === 'contentinfo' || role === 'main' || role === 'complementary' ||
                role === 'alert' || role === 'status' || role === 'log' ||
                role === 'tablist' || role === 'tab' || role === 'tabpanel' ||
                role === 'toolbar' || role === 'menu' || role === 'menubar' || role === 'menuitem' ||
                role === 'grid' || role === 'gridcell' || role === 'row' || role === 'rowgroup' ||
                role === 'columnheader' || role === 'rowheader' || role === 'group' || role === 'figure'
            )) {
                return true;
            }
            if (el.hasAttribute('aria-modal') || el.hasAttribute('aria-label') || el.hasAttribute('aria-labelledby') || el.hasAttribute('aria-describedby') || el.getAttribute('aria-hidden') === 'true') {
                return true;
            }
            if (classList.some(cls => this.LAYOUT_SEMANTIC_WHITELIST_CLASSES.has(cls.toLowerCase()))) {
                return true;
            }
            const textContent = el.textContent.trim();
            if (textContent.length > 5 && !Utils.isAdCharacteristic(el)) {
                return true;
            }
            if (['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'LABEL'].includes(tagName)) return true;
            const parent = el.parentElement;
            if (parent && this.isLegitimateSemanticElement(parent)) {
                if (!Utils.isAdCharacteristic(el)) {
                    return true;
                }
            }
            return false;
        },
        check(el) {
            if (!canProcessElement(el) || perf.degraded || !this.enabled) return false;
            if (!(el instanceof Element)) return false;
            if (this.isLegitimateSemanticElement(el)) {
                return false;
            }
            if (['HTML', 'BODY'].includes(el.tagName.toUpperCase())) return false;
            if (el.tagName.toUpperCase() === 'IMG') return false;
            const style = Detector.getCachedStyle(el);
            if (!style) return false;
            const rect = el.getBoundingClientRect();
            const zIndex = parseInt(style.zIndex, 10);
            if (!isNaN(zIndex) && zIndex > CONFIG.protectionRules.zIndexThreshold) {
                const isLegitHighZUI = (
                    el.closest('[role="dialog"], [aria-modal="true"], dialog[open], .modal-content, .fancybox-container, .lightbox-container, .swiper-slide, .toast, .alert, .notification') ||
                    el.classList.contains('modal') || el.classList.contains('dialog') || el.classList.contains('overlay') || el.classList.contains('popup') ||
                    el.classList.contains('notification-bar') || el.classList.contains('cookie-banner')
                );
                if (!isLegitHighZUI) {
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '高Z轴元素',
                        detail: `z-index: ${zIndex}`
                    });
                }
            }
            if (style.pointerEvents === 'none') {
                const isAdRelatedName = Utils.isAdCharacteristic(el);
                const isLargeArea = rect.width >= window.innerWidth * 0.5 && rect.height >= window.innerHeight * 0.5;
                const isFixedOrAbsolute = ['fixed', 'absolute'].includes(style.position);
                const hasClickableChildren = el.querySelector('a[href]:not([href="#"]), button, [onclick], [role="button"], [tabindex]') !== null;
                const hasSignificantContent = el.textContent.trim().length > 50 || el.children.length > 3;
                const isPurelyVisualChild = el.children.length === 1 && ['IMG', 'VIDEO', 'CANVAS', 'SVG'].includes(el.children[0].tagName.toUpperCase());
                const isDecorativeOrLoadingElement = (
                    (rect.width > 0 && rect.width < 10 && rect.height > 0 && rect.height < 10) ||
                    (parseFloat(style.opacity) < 0.2 && style.backgroundImage === 'none' && style.backgroundColor === 'rgba(0, 0, 0, 0)') ||
                    el.matches('[class*="icon"], [class*="spinner"], [class*="loading"], [class*="backdrop"], [class*="overlay-transparent"]')
                );
                if (isLargeArea && isFixedOrAbsolute && (isAdRelatedName || isPurelyVisualChild) && !isDecorativeOrLoadingElement && !hasSignificantContent && !hasClickableChildren) {
                    if (el.parentNode === document.documentElement || el.parentNode === document.body) {
                        return false;
                    }
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '不可交互覆盖层',
                        detail: `pointer-events:none, 大尺寸固定/绝对定位, ${isAdRelatedName?'广告特征':''}${isPurelyVisualChild?'单视觉子元素':''}`
                    });
                }
            }
            const isScrollable = (el.scrollWidth > el.clientWidth && (style.overflowX === 'scroll' || style.overflowX === 'auto')) ||
                (el.scrollHeight > el.clientHeight && (style.overflowY === 'scroll' || style.overflowY === 'auto'));
            if (style.overflow === 'hidden' && !isScrollable) {
                const isAdRelated = Utils.isAdCharacteristic(el);
                const isEmptyContainer = el.textContent.trim() === '' && el.children.length === 0;
                const isLegitHiddenContent = (
                    el.classList.contains('hidden') || el.classList.contains('collapse') || el.classList.contains('tab-pane') ||
                    el.hasAttribute('aria-hidden') || el.matches('[role="tabpanel"]')
                );
                if ((isAdRelated || isEmptyContainer) && !isLegitHiddenContent) {
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '隐藏溢出内容的容器',
                        detail: `overflow:hidden, 非滚动, ${isAdRelated ? '广告特征' : '空容器'}`
                    });
                }
            }
            const isTiny = rect.width > 0 && rect.height > 0 && (rect.width < 5 && rect.height < 5);
            const isZeroSize = rect.width === 0 || rect.height === 0 || style.width === '0px' || style.height === '0px';
            const isEffectivelyInvisible = style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity) < 0.01;
            const hasNoMeaningfulContent = el.textContent.trim() === '' && el.children.length === 0;
            if ((isTiny || isZeroSize || isEffectivelyInvisible) && hasNoMeaningfulContent) {
                const isLegitSmallElement = (
                    el.tagName === 'I' || (el.tagName === 'SPAN' && (el.matches('[class*="icon"],[class*="fa"]'))) ||
                    el.classList.contains('spacer') || el.classList.contains('divider') || el.classList.contains('clear') ||
                    el.matches('[role="separator"], [role="presentation"]') ||
                    el.hasAttribute('aria-hidden')
                );
                if (!isLegitSmallElement) {
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '空的不可见或极小容器',
                        detail: `尺寸: ${rect.width}x${rect.height}, display:${style.display}, visibility:${style.visibility}, opacity:${parseFloat(style.opacity).toFixed(2)}`
                    });
                }
            }
            if (el.children.length > 0 &&
                Array.from(el.children).every(child => {
                    if (!canProcessElement(child)) return true;
                    const childStyle = Detector.getCachedStyle(child);
                    return childStyle && (childStyle.display === 'none' || childStyle.visibility === 'hidden' || parseFloat(childStyle.opacity) < 0.01);
                })) {
                const isLegitParentContainer = (
                    el.tagName === 'NAV' || el.tagName === 'UL' || el.tagName === 'OL' || el.tagName === 'LI' || el.tagName === 'MENU' ||
                    el.closest('.menu, .dropdown, .tabs, .accordion, .collapse, .lazyload-container, .image-wrapper') ||
                    el.classList.contains('hidden-content') || el.hasAttribute('aria-hidden')
                );
                if (!isLegitParentContainer) {
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '子元素全部不可见容器',
                        detail: `所有子元素不可见且父元素可疑`
                    });
                }
            }
            if (['fixed', 'sticky'].includes(style.position)) {
                const isLegitFixedUI = (
                    el.tagName === 'NAV' || el.tagName === 'HEADER' || el.tagName === 'FOOTER' || el.tagName === 'BUTTON' ||
                    el.classList.contains('navbar') || el.classList.contains('toolbar') || el.classList.contains('scroll-to-top') ||
                    el.classList.contains('cookie-banner') || el.classList.contains('notification-bar') || el.classList.contains('message-bar') ||
                    el.matches('[role="navigation"], [role="banner"], [role="contentinfo"], [role="alert"]') ||
                    (el.children.length > 0 && !Array.from(el.children).some(c => c.tagName === 'IMG' || c.tagName === 'IFRAME')) &&
                    el.textContent.trim().length > 20
                );
                const isLargeFixed = (rect.width >= window.innerWidth * 0.8 && rect.height >= window.innerHeight * 0.8);
                const isBottomFloat = (rect.bottom > window.innerHeight - 50 && rect.height < 150 && rect.width > window.innerWidth * 0.5);
                const isTopFloat = (rect.top < 50 && rect.height < 150 && rect.width > window.innerWidth * 0.5);
                const isSideFloat = ((rect.left < 50 || rect.right > window.innerWidth - 50) && rect.height > window.innerHeight * 0.3 && rect.width < 150);
                if (isLargeFixed && !isLegitFixedUI) {
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '大型固定定位元素',
                        detail: `位置: ${style.position}, 尺寸: ${rect.width}x${rect.height}px`
                    });
                }
                if (isBottomFloat && Utils.isAdCharacteristic(el) && !isLegitFixedUI) {
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '底部悬浮广告',
                        detail: `位置: bottom=${rect.bottom}px, 尺寸: ${rect.width}x${rect.height}px`
                    });
                }
                if (isTopFloat && Utils.isAdCharacteristic(el) && !isLegitFixedUI) {
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '顶部悬浮广告',
                        detail: `位置: top=${rect.top}px, 尺寸: ${rect.width}x${rect.height}px`
                    });
                }
                if (isSideFloat && Utils.isAdCharacteristic(el) && !isLegitFixedUI) {
                    return AdUtils.safeRemove(el, 'layoutSystem', {
                        type: '侧边悬浮广告',
                        detail: `位置: side, 尺寸: ${rect.width}x${rect.height}px`
                    });
                }
            }
            return false;
        }
    });
    ModuleManager.register('mergedMediaSystem', {
        imageExtensions: /\.(gif|webp|png|jpe?g|svg|bmp|tiff)(\?.*)?$/i,
        jsExtensionPattern: /\.js(\?|$)/i,
        visibilityThreshold: 0.01,
        minValidSize: 16,
        minConsideredAdSize: 32,
        mobileAdRatios: [
            { w: 320, h: 50 }, { w: 300, h: 250 }, { w: 336, h: 280 }, { w: 728, h: 90 }, { w: 468, h: 60 }, { w: 120, h: 600 }, { w: 160, h: 600 }, { w: 300, h: 600 }, { w: 1, h: 1 }
        ],
        commonBannerSizes: [
            { width: 320, height: 50 }, { width: 300, height: 250 }, { width: 336, height: 280 }, { width: 728, height: 90 }, { width: 468, height: 60 }, { width: 250, height: 250 }, { width: 200, height: 200 }, { width: 180, height: 150 }, { width: 125, height: 125 }, { width: 300, height: 50 }, { width: 234, height: 60 }, { width: 120, height: 600 }, { width: 160, height: 600 }, { width: 300, height: 600 }, { width: 1, height: 1 }
        ],
        mobileRatioThreshold: { min: 0.05, max: 20 },
        minClickableAdSize: 48,
        enabled: false,
        init() {
            if (CONFIG.modules.mergedMediaSystem) this.enable();
            else this.disable();
        },
        enable() {
            if (this.enabled || perf.degraded) return;
            this.enabled = true;
        },
        disable() {
            this.enabled = false;
        },
        isLegitimateImageOrBackground(el, rect, srcOrBg) {
            if (!el || !(el instanceof Element)) return false;
            const tagName = el.tagName.toUpperCase();
            const classList = Array.from(el.classList);
            const altText = el.getAttribute('alt')?.toLowerCase() || '';
            const ariaLabel = el.getAttribute('aria-label')?.toLowerCase() || '';
            const titleText = el.getAttribute('title')?.toLowerCase() || '';
            if (el.closest('nav, header, footer, article, section, figure, picture, main, aside, dialog, .post-content, .news-article, .product-detail, .user-profile, .thumbnail-list, .gallery, .comic-page, .video-player, .content-body, .article-image')) {
                if (rect.width < 500 && rect.height < 500) {
                    if (altText.includes('logo') || altText.includes('icon') || altText.includes('avatar') || altText.includes('profile') || altText.includes('thumbnail') || altText.includes('product') || altText.includes('gallery') || altText.includes('comic') || altText.includes('video') ||
                        ariaLabel.includes('logo') || ariaLabel.includes('icon') || ariaLabel.includes('avatar') || ariaLabel.includes('product') || ariaLabel.includes('gallery') ||
                        classList.some(cls => cls.includes('logo') || cls.includes('avatar') || cls.includes('thumbnail') || cls.includes('product-image') || cls.includes('user-icon') || cls.includes('gallery-item') || cls.includes('icon') || cls.includes('media-item') || cls.includes('content-image') || cls.includes('post-thumbnail') || cls.includes('comic-image'))
                    ) {
                        return true;
                    }
                }
            }
            if (altText.length > 5 && !REGEX.adAttributes.test(altText) ||
                ariaLabel.length > 5 && !REGEX.adAttributes.test(ariaLabel) ||
                titleText.length > 5 && !REGEX.adAttributes.test(titleText)) {
                return true;
            }
            if (classList.some(cls => cls.includes('logo') || cls.includes('avatar') || cls.includes('thumbnail') || cls.includes('product-image') || cls.includes('user-icon') || cls.includes('gallery-item') || cls.includes('icon') || cls.includes('banner-false') || cls.includes('ad-off'))) {
                return true;
            }
            if (srcOrBg) {
                const lowerSrcOrBg = srcOrBg.toLowerCase();
                if (lowerSrcOrBg.includes('logo') || lowerSrcOrBg.includes('avatar') || lowerSrcOrBg.includes('icon') || lowerSrcOrBg.includes('user') || lowerSrcOrBg.includes('profile') || lowerSrcOrBg.includes('gallery') || lowerSrcOrBg.includes('product') || lowerSrcOrBg.includes('thumb') || lowerSrcOrBg.includes('comic') || lowerSrcOrBg.includes('video-preview')) {
                    return true;
                }
            }
            if (el.hasAttribute('aria-hidden') || el.getAttribute('role') === 'presentation') {
                if (!el.hasAttribute('onclick') && !el.querySelector('a[href], button, [onclick]')) {
                    return true;
                }
            }
            return false;
        },
        check(el) {
            if (!canProcessElement(el) || perf.degraded || !this.enabled) return false;
            if (!(el instanceof Element)) return false;
            if (['A', 'BODY', 'HTML', 'HEAD', 'TITLE', 'META', 'LINK', 'STYLE', 'SCRIPT', 'BUTTON', 'INPUT', 'TEXTAREA', 'SELECT', 'FORM', 'LABEL'].includes(el.tagName.toUpperCase())) return false;
            const rect = el.getBoundingClientRect();
            if (rect.width <= 0 || rect.height <= 0) return false;
            if (el.tagName === 'IMG' || el.tagName === 'IMAGE') {
                if (this.checkImageElement(el, rect)) return true;
            }
            if (this.hasImageBackground(el)) {
                if (this.checkImageBackgroundElement(el, rect)) return true;
            }
            const isLargeEnough = rect.width >= this.minClickableAdSize && rect.height >= this.minClickableAdSize;
            if (this.checkClickableCharacteristics(el, rect, isLargeEnough)) {
                return true;
            }
            if (this.checkBackgroundCharacteristics(el, rect, isLargeEnough)) {
                return true;
            }
            if (this.isSuspiciousContainer(el)) {
                if (this.handleSuspiciousContainer(el)) return true;
            }
            return false;
        },
        checkImageElement(el, rect) {
            if (!canProcessElement(el) || perf.degraded) return false;
            const src = el.src || el.getAttribute('data-src') || '';
            if (this.isLegitimateImageOrBackground(el, rect, src)) {
                return false;
            }
            if (this.jsExtensionPattern.test(src) || (src.startsWith('data:image/') && REGEX.adAttributes.test(src))) {
                return this.handleAd(el, 'JS扩展名图片/可疑数据URL', `异常图片源: ${Utils.truncateString(src, 80)}`, 3);
            }
            if (!Detector.isVisible(el)) {
                if (!(rect.width === 1 && rect.height === 1)) {
                    if (rect.width < this.minValidSize / 2 && rect.height < this.minValidSize / 2) return false;
                    return this.handleAd(el, '不可见大尺寸图片', `尺寸: ${rect.width}x${rect.height}px`, 1);
                }
            }
            if (rect.width === 1 && rect.height === 1) {
                return this.handleAd(el, '追踪像素', `尺寸: ${rect.width}x${rect.height}px`, 2);
            }
            if (rect.width > 0 && rect.height > 0 && (rect.width < this.minValidSize || rect.height < this.minValidSize)) {
                return false;
            }
            const naturalWidth = el.naturalWidth || rect.width;
            const naturalHeight = el.naturalHeight || rect.height;
            if (naturalWidth > 0 && naturalHeight > 0) {
                if (this.isCommonAdSize(naturalWidth, naturalHeight)) {
                    if (Utils.isAdCharacteristic(el) || !this.isLegitimateImageOrBackground(el, rect, src)) {
                        return this.handleAd(el, '标准广告尺寸图片', `${naturalWidth}x${naturalHeight}`, 2);
                    }
                }
                const aspectRatio = naturalWidth / naturalHeight;
                if (aspectRatio < this.mobileRatioThreshold.min || aspectRatio > this.mobileRatioThreshold.max) {
                    if (Utils.isAdCharacteristic(el) || !this.isLegitimateImageOrBackground(el, rect, src)) {
                        return this.handleAd(el, '异常宽高比图片', `比例:${aspectRatio.toFixed(1)} (${naturalWidth}x${naturalHeight})`, 2);
                    }
                }
            }
            return false;
        },
        checkImageBackgroundElement(el, rect) {
            if (!canProcessElement(el) || perf.degraded) return false;
            if (!Detector.isVisible(el)) return false;
            const style = Detector.getCachedStyle(el);
            if (!style || style.backgroundImage === 'none' || !this.imageExtensions.test(style.backgroundImage)) return false;
            const bgUrlMatch = style.backgroundImage.match(/url\((['"]?)(.*?)\1\)/);
            const bgUrl = bgUrlMatch ? bgUrlMatch[2] : '';
            if (this.isLegitimateImageOrBackground(el, rect, bgUrl)) {
                return false;
            }
            if ((rect.width < this.minValidSize * 2 && rect.height < this.minValidSize * 2) && Utils.isAdCharacteristic(el)) {
                return this.handleAd(el, '微型背景图片', `尺寸: ${rect.width}x${rect.height}px`, 2);
            }
            if (typeof style.backgroundImage === 'string' && REGEX.adAttributes.test(style.backgroundImage)) {
                return this.handleAd(el, '广告背景图片源', `背景源: ${Utils.truncateString(style.backgroundImage, 80)}`, 3);
            }
            return false;
        },
        isCommonAdSize(width, height) {
            return this.commonBannerSizes.some(size => {
                if (width === 1 && height === 1) return true;
                if (width <= 0 || height <= 0) return false;
                const tolerance = 0.15;
                return (width >= size.width * (1 - tolerance) && width <= size.width * (1 + tolerance) &&
                        height >= size.height * (1 - tolerance) && height <= size.height * (1 + tolerance));
            });
        },
        hasImageBackground(el) {
            if (!canProcessElement(el) || perf.degraded) return false;
            const style = Detector.getCachedStyle(el);
            return (
                style &&
                style.backgroundImage &&
                style.backgroundImage !== 'none' &&
                style.backgroundImage.includes('url(') &&
                this.imageExtensions.test(style.backgroundImage)
            );
        },
        isSuspiciousContainer(el) {
            if (!canProcessElement(el) || perf.degraded) return false;
            const rect = el.getBoundingClientRect();
            if (rect.width < this.minConsideredAdSize || rect.height < this.minConsideredAdSize) return false;
            const style = Detector.getCachedStyle(el);
            if (!style) return false;
            const zIndex = parseInt(style.zIndex, 10);
            const isAdRelated = Utils.isAdCharacteristic(el);
            const hasTrackingPixel = this.containsTrackingPixel(el);
            const hasHiddenIframes = el.querySelector('iframe[width="0"][height="0"], iframe[display="none"], iframe[visibility="hidden"]') !== null;
            return (
                (!isNaN(zIndex) && zIndex > CONFIG.protectionRules.zIndexThreshold) ||
                (isAdRelated && (!isNaN(zIndex) && zIndex > 10 || hasTrackingPixel || hasHiddenIframes)) ||
                hasTrackingPixel ||
                hasHiddenIframes
            );
        },
        containsTrackingPixel(el) {
            if (!canProcessElement(el) || perf.degraded) return false;
            return el.querySelector('img[width="1"][height="1"], img[width="0"][height="0"], img[src*="track"], img[src*="adlog"], img[src*="beacon"]') !== null;
        },
        handleSuspiciousContainer(el) {
            if (!canProcessElement(el) || perf.degraded) return false;
            const style = Detector.getCachedStyle(el);
            const zIndex = parseInt(style.zIndex, 10);
            const isAdRelated = Utils.isAdCharacteristic(el);
            const hasTrackingPixel = this.containsTrackingPixel(el);
            const hasHiddenIframes = el.querySelector('iframe[width="0"][height="0"], iframe[display="none"], iframe[visibility="hidden"]') !== null;
            if (!isNaN(zIndex) && zIndex > CONFIG.protectionRules.zIndexThreshold) {
                return this.handleAd(el, '极高Z轴容器', `z-index: ${zIndex}`, 4);
            }
            if (isAdRelated && !isNaN(zIndex) && zIndex > 10) {
                return this.handleAd(el, '高Z轴广告容器', `z-index: ${zIndex}`, 3);
            }
            if (hasTrackingPixel) {
                return this.handleAd(el, '包含跟踪像素', '找到1x1图片或其他跟踪像素', 3);
            }
            if (hasHiddenIframes) {
                return this.handleAd(el, '包含隐藏iframe', '找到隐藏iframe', 3);
            }
            if (isAdRelated) {
                return this.handleAd(el, '基础广告特征容器', `ID/Class/Attr匹配`, 2);
            }
            return false;
        },
        checkClickableCharacteristics(el, rect, isLargeEnough) {
            if (!canProcessElement(el) || perf.degraded) return false;
            if (!Detector.isVisible(el)) return false;
            if (!isLargeEnough) return false;
            const style = Detector.getCachedStyle(el);
            if (!style) return false;
            const isLegitClickableUI = (
                el.tagName === 'BUTTON' || el.tagName === 'INPUT' || el.tagName === 'SELECT' || el.tagName === 'TEXTAREA' ||
                el.closest('nav, .pagination, .tab-bar, .menu, .dropdown-toggle, .form-control, .btn-group, .product-actions, .add-to-cart, .read-more, .view-details, .comment-button') ||
                el.hasAttribute('aria-label') && !REGEX.adAttributes.test(el.getAttribute('aria-label')) ||
                el.hasAttribute('title') && !REGEX.adAttributes.test(el.getAttribute('title')) ||
                el.matches('[role="button"], [role="link"], [role="checkbox"], [role="radio"], [role="option"], [tabindex]')
            );
            if (isLegitClickableUI) return false;
            const isClickable = style.cursor === 'pointer' || el.hasAttribute('onclick') || !!el.querySelector('[onclick], a[href], button, [role="button"]');
            const isAdRelated = Utils.isAdCharacteristic(el);
            const zIndex = parseInt(style.zIndex, 10);
            const hasImageOrFlash = el.querySelector('img, object, embed, iframe') !== null || this.hasImageBackground(el);
            const hasOnlyMinimalText = el.textContent.trim().length < 50;
            if (isClickable && isLargeEnough && hasImageOrFlash && hasOnlyMinimalText &&
                (isAdRelated || (!isNaN(zIndex) && zIndex > (CONFIG.protectionRules.zIndexThreshold / 2)) || this.containsTrackingPixel(el))) {
                let detail = `点击/尺寸:${rect.width}x${rect.height}`;
                if (!isNaN(zIndex)) detail += `/Z:${zIndex}`;
                if (isAdRelated) detail += '/广告属性';
                if (hasImageOrFlash) detail += '/包含媒体';
                if (this.containsTrackingPixel(el)) detail += '/跟踪像素';
                return this.handleAd(el, '可疑可点击容器', detail, 3);
            }
            return false;
        },
        checkBackgroundCharacteristics(el, rect, isLargeEnough) {
            if (!canProcessElement(el) || perf.degraded) return false;
            if (!Detector.isVisible(el)) return false;
            if (!isLargeEnough) return false;
            const style = Detector.getCachedStyle(el);
            if (!style) return false;
            const hasBackground = style.backgroundImage !== 'none' || (style.backgroundColor && style.backgroundColor !== 'rgba(0, 0, 0, 0)' && style.backgroundColor !== 'transparent');
            const isGradient = typeof style.backgroundImage === 'string' && (style.backgroundImage.includes('linear-gradient') || style.backgroundImage.includes('radial-gradient'));
            const isSolidColor = hasBackground && !isGradient && style.backgroundImage === 'none';
            const isLegitBackgroundElement = (
                el.tagName === 'HEADER' || el.tagName === 'FOOTER' || el.tagName === 'NAV' ||
                el.classList.contains('card') || el.classList.contains('bg-primary') || el.classList.contains('btn') ||
                el.matches('[role="banner"], [role="contentinfo"], [role="region"], [role="alert"]') ||
                el.closest('.header, .footer, .navbar, .toolbar, .card, .alert, .toast, .hero-section, .background-image-container, .post-cover')
            );
            if (isLegitBackgroundElement) return false;
            const isAdRelated = Utils.isAdCharacteristic(el);
            const zIndex = parseInt(style.zIndex, 10);
            if ((isGradient || isSolidColor || this.hasImageBackground(el)) && isLargeEnough &&
                (isAdRelated || (!isNaN(zIndex) && zIndex > (CONFIG.protectionRules.zIndexThreshold / 2)) || this.containsTrackingPixel(el) || el.hasAttribute('onclick') || !!el.querySelector('[onclick], a[href]'))) {
                let detail = `背景:${isSolidColor ? '纯色' : (isGradient ? '渐变' : '图片')}/尺寸:${rect.width}x${rect.height}`;
                if (!isNaN(zIndex)) detail += `/Z:${zIndex}`;
                if (isAdRelated) detail += '/广告属性';
                if (this.containsTrackingPixel(el)) detail += '/跟踪像素';
                if (el.hasAttribute('onclick') || !!el.querySelector('[onclick], a[href]')) detail += '/可点击';
                return this.handleAd(el, '可疑背景容器', detail, 3);
            }
            return false;
        },
        handleAd(el, type, detail, priority = 1) {
            return AdUtils.safeRemove(el, 'mergedMediaSystem', {
                type: `媒体检测[${type}]`,
                detail: detail,
                priority: priority
            });
        }
    });
    ModuleManager.register('specialUA', {
        navigatorProxy: null,
        originalNavigator: window.navigator,
        fakeUA: 'NokiaE7-00/5.0 UCWEB/2.0 Mozilla/5.0 (Symbian/3; Series60/5.2; Windows Phone 10.0; Android 14; Microsoft; Lumia 950 XL Dual SIM; Java) Gecko/131 Firefox/131 SearchCraft/3.10.2 (Baidu; P1 13) baiduboxapp/4.3.0.10',
        fakePlatform: 'Win32',
        fakeAppVersion: 'Mozilla/5.0 (Linux; Android 12; LIO-AN00 Build/HUAWEILIO-AN00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.196 Mobile Safari/537.36',
        init() {
            this.createProxy();
        },
        createProxy() {
            if (this.navigatorProxy) return;
            this.navigatorProxy = new Proxy(this.originalNavigator, {
                get: (target, prop) => {
                    if (!CONFIG.modules.specialUA)
                        return Reflect.get(target, prop);
                    switch (prop) {
                        case 'userAgent':
                            return this.fakeUA;
                        case 'platform':
                            return this.fakePlatform;
                        case 'appVersion':
                            return this.fakeAppVersion;
                        case 'vendor':
                            return 'Google Inc.';
                        default:
                            return Reflect.get(target, prop);
                    }
                }
            });
            try {
                Object.defineProperty(window, 'navigator', {
                    value: this.navigatorProxy,
                    configurable: true,
                    writable: false
                });
            } catch (e) {}
        },
        enable() {
            CONFIG.modules.specialUA = true;
        },
        disable() {
            CONFIG.modules.specialUA = false;
            if (this.navigatorProxy && window.navigator === this.navigatorProxy) {
                try {
                    Object.defineProperty(window, 'navigator', {
                        value: this.originalNavigator,
                        configurable: true,
                        writable: false
                    });
                } catch (e) {}
            }
        },
        check() {
            return false;
        }
    });
    ModuleManager.register('performanceOptimizer', {
        performanceEntries: [],
        degradationThreshold: CONFIG.performance.degradeThreshold,
        isMonitoring: false,
        perfObserver: null,
        init() {
            if (CONFIG.modules.main) {
                this.setupPerformanceMonitor();
                this.startPerformanceObserver();
            } else {
                this.stopPerformanceMonitor();
            }
        },
        setupPerformanceMonitor() {
            if (this.isMonitoring || !CONFIG.modules.main) return;
            this.isMonitoring = true;
            const checkPerformance = () => {
                if (!CONFIG.modules.main) {
                    this.isMonitoring = false;
                    return;
                }
                const now = performance.now();
                this.performanceEntries = this.performanceEntries.filter(
                    entry => entry.startTime > now - 10000
                );
                const longTasks = this.performanceEntries.filter(
                    entry => entry.duration > CONFIG.performance.longTaskThreshold
                );
                if (longTasks.length >= this.degradationThreshold && !perf.degraded) {
                    this.activateDegradedMode();
                } else if (longTasks.length < this.degradationThreshold / 2 && perf.degraded) {
                    this.deactivateDegradedMode();
                }
                requestAnimationFrame(checkPerformance);
            };
            requestAnimationFrame(checkPerformance);
        },
        startPerformanceObserver() {
            if (typeof PerformanceObserver === 'function' && !this.perfObserver) {
                try {
                    this.perfObserver = new PerformanceObserver(list => {
                        if (!CONFIG.modules.main) return;
                        this.performanceEntries.push(...list.getEntries());
                    });
                    this.perfObserver.observe({ entryTypes: ['longtask'] });
                } catch (e) {
                    console.warn("PerformanceObserver for longtask not supported or failed:", e);
                    this.perfObserver = null;
                }
            }
        },
        stopPerformanceMonitor() {
            this.isMonitoring = false;
            if (this.perfObserver) {
                this.perfObserver.disconnect();
                this.perfObserver = null;
            }
            if (perf.degraded) {
                this.deactivateDegradedMode();
            }
        },
        activateDegradedMode() {
            if (perf.degraded || !CONFIG.modules.main) return;
            perf.degraded = true;
            mainObserver.disconnect();
            AdUtils.cleanupScriptHooks();
            ModuleManager.modules.dynamicSystem?.disable();
            perf.adElements.clear();
            perf.processed = new WeakSet();
            Logs.add('performanceOptimizer', null, { type: '性能降级', detail: `检测到 ${this.degradationThreshold} 个长期任务,部分功能已暂停。` });
            GM_notification('AdBlocker', '性能降级模式:部分功能已暂停');
        },
        deactivateDegradedMode() {
            if (!perf.degraded || !CONFIG.modules.main) return;
            perf.degraded = false;
            if (document.documentElement) {
                mainObserver.observe(document.documentElement, {
                    childList: true,
                    subtree: true,
                    attributes: true,
                    attributeFilter: ['id', 'class', 'style', 'src', 'href', 'data-src']
                });
            }
            if (CONFIG.modules.dynamicSystem) {
                ModuleManager.modules.dynamicSystem?.enable();
            }
            Processor.collectInitialElements();
            Processor.scheduleProcess();
            Logs.add('performanceOptimizer', null, { type: '性能恢复', detail: '性能降级模式结束:功能已恢复。' });
            GM_notification('AdBlocker', '性能降级模式结束:功能已恢复');
        },
        check() {
            return false;
        }
    });
    if (!window.requestIdleCallback) {
        window.requestIdleCallback = (callback, options) => {
            const options_timeout = options?.timeout || 0;
            const start = Date.now();
            return setTimeout(() => {
                callback({
                    didTimeout: Date.now() - start > 50,
                    timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
                });
            }, options_timeout);
        };
        window.cancelIdleCallback = (id) => clearTimeout(id);
    }
    function init() {
        UIController.init();
        CSPManager.injectInitialCSP();
        ModuleManager.init();
        if (CONFIG.modules.main) {
            AdUtils.initScriptHooks();
            if (document.readyState === 'loading') {
                window.addEventListener('DOMContentLoaded', () => {
                    if (document.documentElement && CONFIG.modules.main && !perf.degraded) {
                        mainObserver.observe(document.documentElement, {
                            childList: true,
                            subtree: true,
                            attributes: true,
                            attributeFilter: ['id', 'class', 'style', 'src', 'href', 'data-src']
                        });
                    }
                    Processor.collectInitialElements();
                    Processor.scheduleProcess();
                }, { once: true });
            } else {
                if (document.documentElement && CONFIG.modules.main && !perf.degraded) {
                    mainObserver.observe(document.documentElement, {
                        childList: true,
                        subtree: true,
                        attributes: true,
                        attributeFilter: ['id', 'class', 'style', 'src', 'href', 'data-src']
                    });
                }
                Processor.collectInitialElements();
                Processor.scheduleProcess();
            }
            window.addEventListener('scroll', Utils.throttle(() => {
                if (CONFIG.modules.main && !perf.degraded) {
                    Processor.collectInitialElements();
                    Processor.scheduleProcess();
                }
            }, CONFIG.performance.throttleScrollDelay));
            window.addEventListener('resize', Utils.debounce(() => {
                if (CONFIG.modules.main && !perf.degraded) {
                    perf.styleCache.clear();
                    Processor.collectInitialElements();
                    Processor.scheduleProcess();
                }
            }, 150));
            StyleManager.inject();
        } else {
            mainObserver.disconnect();
            AdUtils.cleanupScriptHooks();
            StyleManager.remove();
            ModuleManager.modules.performanceOptimizer?.stopPerformanceMonitor();
        }
        if (CONFIG.modules.main && CONFIG.mobileOptimizations.lazyLoadImages) {
            document.addEventListener('DOMContentLoaded', () => {
                document.querySelectorAll('img[data-src]:not([src])').forEach(img => {
                    if (!(img instanceof Element) || !canProcessElement(img)) return;
                    if (img.dataset.src) {
                        img.src = img.dataset.src;
                        img.removeAttribute('data-src');
                    }
                });
            }, { once: true });
        }
        if (CONFIG.modules.main && CONFIG.mobileOptimizations.removeImagePlaceholders) {
            document.addEventListener('DOMContentLoaded', () => {
                const placeholders = document.querySelectorAll('.image-placeholder, [placeholder], [aria-hidden="true"], [role="presentation"]');
                placeholders.forEach(ph => {
                    if (!(ph instanceof Element) || !canProcessElement(ph)) return;
                    try {
                        if (ph.tagName === 'INPUT' || ph.tagName === 'TEXTAREA' || ph === document.activeElement || ph.contains(document.activeElement)) return;
                        const rect = ph.getBoundingClientRect();
                        const style = getComputedStyle(ph);
                        if (rect.width > 0 && rect.width < 5 && rect.height > 0 && rect.height < 5 && style.position === 'absolute' && parseFloat(style.opacity) < 0.1) {
                            if (ph.parentNode) ph.parentNode.removeChild(ph);
                        } else if (ph.textContent.trim() === '' && ph.children.length === 0 && style.display === 'none') {
                            if (ph.parentNode) ph.parentNode.removeChild(ph);
                        } else if (ph.tagName === 'IMG' && (!ph.src || ph.src.startsWith('data:')) && ph.width < 100 && ph.height < 100 && ph.naturalWidth === 0 && ph.naturalHeight === 0) {
                            if (ph.parentNode) ph.parentNode.removeChild(ph);
                        }
                    } catch (e) {}
                });
            }, { once: true });
        }
    }
    init();
})();