🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

小说漫画网页广告拦截器

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

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name         小说漫画网页广告拦截器
// @namespace    http://tampermonkey.net/
// @version      4.5.1
// @author       DeepSeek&Gemini
// @description  一个手机端via浏览器能用的强大的广告拦截器
// @match        *://*/*
// @license      MIT
// @grant        unsafeWindow
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_notification
// @grant        GM_xmlhttpRequest
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    const DEFAULT_MODULE_STATE = {
        smartInterception: false,
        removeInlineScripts: false,
        removeExternalScripts: false,
        interceptThirdPartyResources: false,
        interceptSubdomains: false,
        manageCSP: false,
    };
    const MODULE_NAMES = {
        smartInterception: '智能拦截',
        removeInlineScripts: '移除内嵌脚本',
        removeExternalScripts: '移除外联脚本',
        interceptThirdPartyResources: '拦截第三方资源',
        interceptSubdomains: '拦截子域名资源',
        manageCSP: 'CSP策略管理',
    };
    const DEFAULT_CSP_RULES_TEMPLATE = [
        { id: 1, name: '仅允许同源外部脚本 (禁止内嵌)', rule: "script-src 'self'", enabled: false },
        { id: 2, name: '允许同源脚本和内嵌脚本', rule: "script-src 'self' 'unsafe-inline'", enabled: false },
        { id: 3, name: '禁止eval和Function执行', rule: "script-src 'unsafe-eval'", enabled: false },
        { id: 4, name: '仅允许同源外部样式 (禁止内联)', rule: "style-src 'self'", enabled: false },
        { id: 5, name: '允许同源样式和内联样式', rule: "style-src 'self' 'unsafe-inline'", enabled: false },
        { id: 6, name: '仅允许同源图片', rule: "img-src 'self'", enabled: false },
        { 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_STORAGE_KEY_PREFIX = `customAdBlockerConfig_`;
    let currentConfig = {
        modules: { ...DEFAULT_MODULE_STATE },
        cspRules: DEFAULT_CSP_RULES_TEMPLATE.map(rule => ({ ...rule })),
        whitelist: {},
    };

    class LRUCache {
        constructor(capacity = 100, defaultTTL = 0) {
            this.capacity = capacity;
            this.defaultTTL = defaultTTL;
            this.cache = new Map();
        }

        get(key) {
            if (!this.cache.has(key)) return null;
            const entry = this.cache.get(key);
            if (this.defaultTTL > 0 && (Date.now() - entry.timestamp) > this.defaultTTL) {
                this.cache.delete(key);
                return null;
            }
            this.cache.delete(key);
            this.cache.set(key, entry);
            return entry.value;
        }

        set(key, value, ttl) {
            const finalTTL = ttl !== undefined ? ttl : this.defaultTTL;
            const entry = {
                value: value,
                timestamp: Date.now(),
                ttl: finalTTL
            };
            if (this.cache.has(key)) {
                this.cache.delete(key);
            } else if (this.cache.size >= this.capacity) {
                const firstKey = this.cache.keys().next().value;
                this.cache.delete(firstKey);
            }
            this.cache.set(key, entry);
        }

        has(key) {
            const entry = this.cache.get(key);
            if (!entry) return false;
            if (this.defaultTTL > 0 && (Date.now() - entry.timestamp) > this.defaultTTL) {
                this.cache.delete(key);
                return false;
            }
            return true;
        }

        delete(key) {
            return this.cache.delete(key);
        }

        clear() {
            this.cache.clear();
        }

        get size() {
            return this.cache.size;
        }
    }

    class URLResolutionCache {
        constructor() {
            this.hostnameCache = new LRUCache(1000, 300000);
            this.domainCache = new LRUCache(1000, 300000);
            this.absoluteUrlCache = new LRUCache(1000, 300000);
            this.thirdPartyCache = new LRUCache(1000, 300000);
        }

        isDynamicURL(url) {
            if (!url || typeof url !== 'string') return false;
            const dynamicPatterns = [
                /\?.*[tT]=/,
                /\?.*timestamp/,
                /\?.*rand/,
                /\?.*rnd/,
                /\?.*[0-9]{13,}/,
                /\?.*\d{10,}/,
                /\?.*[a-zA-Z0-9]{32,}/,
                /\/\d{10,}\./,
                /\/[0-9a-f]{32,}\./
            ];
            return dynamicPatterns.some(pattern => pattern.test(url));
        }

        getHostname(url) {
            if (!url || typeof url !== 'string') return null;
            const cacheKey = `hostname_${url}`;
            
            if (this.hostnameCache.has(cacheKey)) {
                return this.hostnameCache.get(cacheKey);
            }

            if (url.startsWith('data:') || url.startsWith('blob:') || url.startsWith('about:blank')) {
                this.hostnameCache.set(cacheKey, null, 60000);
                return null;
            }

            try {
                const hostname = new URL(url, location.href).hostname;
                const ttl = this.isDynamicURL(url) ? 30000 : 300000;
                this.hostnameCache.set(cacheKey, hostname, ttl);
                return hostname;
            } catch (e) {
                this.hostnameCache.set(cacheKey, null, 30000);
                return null;
            }
        }

        getDomain(hostname) {
            if (!hostname) return null;
            const cacheKey = `domain_${hostname}`;
            
            if (this.domainCache.has(cacheKey)) {
                return this.domainCache.get(cacheKey);
            }

            const parts = hostname.split('.');
            const domain = parts.length <= 2 ? hostname : parts.slice(-2).join('.');
            this.domainCache.set(cacheKey, domain, 300000);
            return domain;
        }

        getAbsoluteURL(url) {
            if (!url) return '';
            const cacheKey = `absolute_${url}_${location.href}`;
            
            if (this.absoluteUrlCache.has(cacheKey)) {
                return this.absoluteUrlCache.get(cacheKey);
            }

            try {
                const absoluteUrl = new URL(url, location.href).href;
                const ttl = this.isDynamicURL(url) ? 30000 : 300000;
                this.absoluteUrlCache.set(cacheKey, absoluteUrl, ttl);
                return absoluteUrl;
            } catch (e) {
                this.absoluteUrlCache.set(cacheKey, url, 30000);
                return url;
            }
        }

        isThirdPartyHost(resourceHostname, currentHost, interceptSubdomains = false) {
            if (!resourceHostname) return false;
            
            const cacheKey = `thirdparty_${resourceHostname}_${currentHost}_${interceptSubdomains}`;
            if (this.thirdPartyCache.has(cacheKey)) {
                return this.thirdPartyCache.get(cacheKey);
            }

            const currentHostDomain = this.getDomain(currentHost);
            const resourceHostDomain = this.getDomain(resourceHostname);
            
            let isThirdParty = false;
            
            if (!currentHostDomain || !resourceHostDomain) {
                isThirdParty = false;
            } else if (resourceHostDomain === currentHostDomain) {
                if (interceptSubdomains && resourceHostname !== currentHost) {
                    isThirdParty = true;
                } else {
                    isThirdParty = false;
                }
            } else {
                isThirdParty = true;
            }
            
            this.thirdPartyCache.set(cacheKey, isThirdParty, 300000);
            return isThirdParty;
        }

        clear() {
            this.hostnameCache.clear();
            this.domainCache.clear();
            this.absoluteUrlCache.clear();
            this.thirdPartyCache.clear();
        }
    }

    const urlCache = new URLResolutionCache();

    const Utils = {
        truncateString(str, maxLength) {
            if (typeof str !== 'string') return '';
            if (str.length <= maxLength) return str;
            return str.slice(0, maxLength) + '...';
        },
        getCurrentHostname() {
            return location.hostname;
        },
        isElement(el) {
            return el instanceof Element;
        },
        getScriptContentPreview(scriptElement) {
            if (!scriptElement || scriptElement.tagName !== 'SCRIPT') return '';
            const content = scriptElement.textContent;
            if (content.length > 200) {
                return content.slice(0, 100) + '...';
            }
            return content.split(/\s+/).join(' ').slice(0, 100);
        },
        getIframeSrcPreview(iframeElement) {
            if (!iframeElement || iframeElement.tagName !== 'IFRAME') return '';
            return Utils.truncateString(iframeElement.src, 100);
        },
        getResourceHostname(url) {
            return urlCache.getHostname(url);
        },
        getDomain(hostname) {
            return urlCache.getDomain(hostname);
        },
        isThirdPartyHost(resourceHostname, currentHost) {
            return urlCache.isThirdPartyHost(resourceHostname, currentHost, currentConfig.modules.interceptSubdomains);
        },
        getAbsoluteURL(url) {
            return urlCache.getAbsoluteURL(url);
        },
        getContentIdentifier(element, reasonType = null) {
            if (!element && !reasonType) return null;
            
            if (element && Utils.isElement(element)) {
                const tagName = element.tagName;
                const src = element.src || element.getAttribute('data-src') || element.href || element.action || '';

                if (tagName === 'SCRIPT') {
                    return element.src ? `SCRIPT_SRC: ${Utils.truncateString(element.src, 100)}` : `SCRIPT_CONTENT: ${Utils.getScriptContentPreview(element)}`;
                } else if (tagName === 'IFRAME') {
                    return `IFRAME_SRC: ${Utils.truncateString(element.src, 100)}`;
                } else if (tagName === 'IMG') {
                    return src ? `IMG_SRC: ${Utils.truncateString(src, 100)}` : null;
                } else if (tagName === 'A') {
                    return src ? `A_HREF: ${Utils.truncateString(src, 100)}` : null;
                } else if (tagName === 'LINK' && element.rel === 'stylesheet' && element.href) {
                    return `CSS_HREF: ${Utils.truncateString(element.href, 100)}`;
                } else if (['VIDEO', 'AUDIO', 'SOURCE'].includes(tagName) && src) {
                    return `${tagName}_SRC: ${Utils.truncateString(src, 100)}`;
                } else if (tagName === 'STYLE') {
                    return `STYLE_CONTENT: ${Utils.truncateString(element.textContent, 100)}`;
                }
                return null;
            } else if (reasonType && typeof reasonType.detail === 'string') {
                if (reasonType.detail.startsWith('SRC:')) {
                    return `${reasonType.type || 'INTERCEPTED'}_SRC: ${Utils.truncateString(reasonType.detail.substring(4).trim(), 100)}`;
                } else if (reasonType.detail.startsWith('URL:')) {
                    return `${reasonType.type || 'INTERCEPTED'}_URL: ${Utils.truncateString(reasonType.detail.substring(5).trim(), 100)}`;
                } else if (reasonType.type === 'EVAL') {
                    return `EVAL_CODE: ${Utils.truncateString(reasonType.detail, 100)}`;
                } else if (reasonType.type === 'FUNCTION_CONSTRUCTOR') {
                    return `FUNCTION_CODE: ${Utils.truncateString(reasonType.detail, 100)}`;
                } else if (reasonType.type === 'SETTIMEOUT') {
                    return `SETTIMEOUT: ${Utils.truncateString(reasonType.detail, 100)}`;
                } else if (reasonType.type === 'SETINTERVAL') {
                    return `SETINTERVAL: ${Utils.truncateString(reasonType.detail, 100)}`;
                } else if (reasonType.type === 'STYLE_ADS') {
                    return `STYLE_ADS: ${Utils.truncateString(reasonType.detail, 100)}`;
                }
                return `LOG_DETAIL: ${Utils.truncateString(reasonType.detail, 100)}`;
            }
            return null;
        },
        isParentProcessed(element) {
            let parent = element.parentElement;
            while (parent) {
                if (parent.dataset.adblockProcessed === 'true' || ProcessedElementsCache.isProcessed(parent)) {
                    return true;
                }
                parent = parent.parentElement;
            }
            return false;
        },
        debounce(func, wait) {
            let timeout;
            return function executedFunction(...args) {
                const later = () => {
                    clearTimeout(timeout);
                    func(...args);
                };
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
            };
        },
        throttle(func, limit) {
            let inThrottle;
            return function(...args) {
                if (!inThrottle) {
                    func.apply(this, args);
                    inThrottle = true;
                    setTimeout(() => inThrottle = false, limit);
                }
            };
        }
    };

    const LogManager = {
        logs: [],
        maxLogs: 150,
        logEntryData: new LRUCache(150, 300000),
        loggedContentIdentifiers: new LRUCache(150, 300000),

        add(moduleKey, element, reason) {
            if (!currentConfig.modules.interceptThirdPartyResources && !currentConfig.modules.removeInlineScripts && !currentConfig.modules.removeExternalScripts && !currentConfig.modules.smartInterception) {
                return;
            }
            if (!Utils.isElement(element) && element !== null && typeof reason !== 'object') return;

            const currentDomain = Utils.getCurrentHostname();

            if (Whitelisting.isElementWhitelisted(element) || Whitelisting.isReasonWhitelisted(reason)) {
                return;
            }

            let elementIdentifier = '[未知元素]';
            let interceptedContent = '[无法获取内容]';
            let contentIdentifier = null;

            if (Utils.isElement(element)) {
                const tagName = element.tagName;
                const id = element.id ? `#${element.id}` : '';
                const className = element.className ? `.${element.className.split(/\s+/).join('.')}` : '';
                elementIdentifier = `${tagName}${id}${className}`;

                contentIdentifier = Utils.getContentIdentifier(element);

                if (tagName === 'SCRIPT') {
                    interceptedContent = element.src ? `SRC: ${Utils.truncateString(element.src, 100)}` : Utils.getScriptContentPreview(element);
                } else if (tagName === 'IFRAME') {
                    interceptedContent = Utils.getIframeSrcPreview(element);
                } else if (tagName === 'IMG') {
                    const src = element.src || element.dataset.src;
                    interceptedContent = Utils.truncateString(src || '', 100);
                } else if (tagName === 'A') {
                    interceptedContent = Utils.truncateString(element.href || '', 100);
                } else if (tagName === 'LINK' && element.rel === 'stylesheet' && element.href) {
                    interceptedContent = Utils.truncateString(element.href || '', 100);
                } else if (['VIDEO', 'AUDIO', 'SOURCE'].includes(tagName)) {
                    interceptedContent = Utils.truncateString(element.src || '', 100);
                } else if (tagName === 'STYLE') {
                    interceptedContent = Utils.truncateString(element.textContent, 100);
                } else {
                    interceptedContent = Utils.truncateString(element.outerHTML, 100);
                }
            } else if (reason && typeof reason.detail === 'string') {
                interceptedContent = Utils.truncateString(reason.detail, 100);
                elementIdentifier = reason.type ? `[${reason.type}]` : '[未知类型]';
                contentIdentifier = Utils.getContentIdentifier(null, reason);
            }

            if (!contentIdentifier) {
                return;
            }

            if (this.loggedContentIdentifiers.has(contentIdentifier)) {
                return;
            }

            const logId = this.logs.length + 1;
            const logEntry = {
                id: logId,
                module: MODULE_NAMES[moduleKey] || moduleKey,
                element: elementIdentifier,
                content: interceptedContent,
            };
            
            this.logs.push(logEntry);
            this.logEntryData.set(logId, {
                contentIdentifier: contentIdentifier,
                element: element,
                reason: reason,
            });
            this.loggedContentIdentifiers.set(contentIdentifier, true);

            if (this.logs.length > this.maxLogs) {
                const removedLogEntry = this.logs.shift();
                this.logEntryData.delete(removedLogEntry.id);
            }
        },

        showInAlert() {
            const currentDomain = Utils.getCurrentHostname();
            const logEntries = this.logs.map(log =>
                `序号: ${log.id}\n` +
                `模块: ${log.module}\n` +
                `元素: ${log.element}\n` +
                `内容: ${log.content}`
            ).join('\n\n');
            const promptMessage = `广告拦截日志(最近${this.logs.length}条):\n\n${logEntries || '暂无日志'}\n\n` +
                `添加内嵌外联脚本白名单方式:\n` +
                `1. 输入序号(如 1-3, 1,3,5)\n` +
                `2. 输入关键词(如 aaa, bbb)\n` +
                `3. 输入 0 清空当前域名所有白名单\n\n` +
                `请输入:`;
            let input = prompt(promptMessage, "");
            if (input === null) return;
            input = input.trim();

            if (input === "0") {
                if (confirm(`清空 ${currentDomain} 的所有白名单?`)) {
                    Whitelisting.clearDomainWhitelist(currentDomain);
                    StorageManager.saveConfig();
                    alert("白名单已清空,页面将刷新。");
                    location.reload();
                }
            } else {
                const indicesToWhitelist = new Set();
                const keywordsToWhitelist = new Set();
                const parts = input.replace(/,/g, ',').split(/[\s,]+/);

                parts.forEach(part => {
                    if (part.includes('-')) {
                        const range = part.split('-').map(Number);
                        if (range.length === 2 && !isNaN(range[0]) && !isNaN(range[1])) {
                            const start = Math.min(range[0], range[1]);
                            const end = Math.max(range[0], range[1]);
                            for (let i = start; i <= end; i++) {
                                indicesToWhitelist.add(i);
                            }
                        }
                    } else {
                        const num = parseInt(part, 10);
                        if (!isNaN(num)) {
                            indicesToWhitelist.add(num);
                        } else if (part.length > 0) {
          keywordsToWhitelist.add(part.toLowerCase());
                        }
                    }
                });

                let addedCount = 0;
                let whitelistedIdentifiers = new Set();

                indicesToWhitelist.forEach(index => {
                    const logEntryInfo = this.logEntryData.get(index);
                    if (logEntryInfo && logEntryInfo.contentIdentifier) {
                        const { contentIdentifier } = logEntryInfo;
                        if (!Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                            whitelistedIdentifiers.add(contentIdentifier);
                        }
                    }
                });

                keywordsToWhitelist.forEach(keyword => {
                    for (const [key, entry] of this.logEntryData.cache) {
                        const logEntryInfo = entry.value;
                        if (logEntryInfo.contentIdentifier && logEntryInfo.contentIdentifier.toLowerCase().includes(keyword)) {
                            if (!Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), logEntryInfo.contentIdentifier)) {
                                whitelistedIdentifiers.add(logEntryInfo.contentIdentifier);
                            }
                        }
                    }
                });

                whitelistedIdentifiers.forEach(identifier => {
                    Whitelisting.add(Utils.getCurrentHostname(), identifier);
                    addedCount++;
                });

                if (addedCount > 0) {
                    StorageManager.saveConfig();
                    alert(`${addedCount} 项已添加到白名单,页面将刷新。`);
                    location.reload();
                } else if (input.length > 0) {
                    alert("未找到匹配项,或已在白名单中。");
                }
            }
        }
    };

    const Whitelisting = {
        isElementWhitelisted(element) {
            if (!element || !Utils.isElement(element)) return false;
            const currentDomain = Utils.getCurrentHostname();
            const contentIdentifier = Utils.getContentIdentifier(element);
            return !!(contentIdentifier && currentDomain && currentConfig.whitelist[currentDomain] && currentConfig.whitelist[currentDomain].has(contentIdentifier));
        },
        isReasonWhitelisted(reason) {
            if (!reason || typeof reason.detail !== 'string') return false;
            const currentDomain = Utils.getCurrentHostname();
            const contentIdentifier = Utils.getContentIdentifier(null, reason);
            return !!(contentIdentifier && currentDomain && currentConfig.whitelist[currentDomain] && currentConfig.whitelist[currentDomain].has(contentIdentifier));
        },
        isContentWhitelisted(domain, contentIdentifier) {
            if (!domain || !contentIdentifier) return false;
            return !!(currentConfig.whitelist[domain] && currentConfig.whitelist[domain].has(contentIdentifier));
        },
        add(domain, contentIdentifier) {
            if (!domain || !contentIdentifier || contentIdentifier.trim() === '') return;
            if (!currentConfig.whitelist[domain]) {
                currentConfig.whitelist[domain] = new Set();
            }
            currentConfig.whitelist[domain].add(contentIdentifier);
        },
        clearDomainWhitelist(domain) {
            if (currentConfig.whitelist[domain]) {
                currentConfig.whitelist[domain].clear();
            }
        },
        clearAllWhitelists() {
            currentConfig.whitelist = {};
        }
    };

    const StorageManager = {
        getConfigKey(hostname) {
            return `${CONFIG_STORAGE_KEY_PREFIX}${hostname}`;
        },
        loadConfig() {
            const hostname = Utils.getCurrentHostname();
            const key = this.getConfigKey(hostname);
            try {
                const savedConfig = JSON.parse(GM_getValue(key, '{}'));
                if (savedConfig) {
                    if (savedConfig.modules) {
                        Object.assign(currentConfig.modules, savedConfig.modules);
                    }
                    if (savedConfig.cspRules) {
                        currentConfig.cspRules = savedConfig.cspRules.map(rule => ({ ...rule }));
                    }
                    if (savedConfig.whitelist) {
                        currentConfig.whitelist = {};
                        for (const domain in savedConfig.whitelist) {
                            if (Array.isArray(savedConfig.whitelist[domain])) {
                                currentConfig.whitelist[domain] = new Set(savedConfig.whitelist[domain]);
                            }
                        }
                    }
                }
            } catch (e) {
                Object.assign(currentConfig.modules, DEFAULT_MODULE_STATE);
                currentConfig.cspRules = DEFAULT_CSP_RULES_TEMPLATE.map(rule => ({ ...rule }));
                currentConfig.whitelist = {};
            }
            Object.keys(DEFAULT_MODULE_STATE).forEach(key => {
                if (currentConfig.modules[key] === undefined) {
                    currentConfig.modules[key] = DEFAULT_MODULE_STATE[key];
                }
            });
            if (currentConfig.modules.manageCSP === undefined) currentConfig.modules.manageCSP = false;
            if (currentConfig.modules.interceptSubdomains === undefined) currentConfig.modules.interceptSubdomains = false;
            if (currentConfig.modules.smartInterception === undefined) currentConfig.modules.smartInterception = false;
        },
        saveConfig() {
            const hostname = Utils.getCurrentHostname();
            const key = this.getConfigKey(hostname);
            try {
                const whitelistForStorage = {};
                for (const domain in currentConfig.whitelist) {
                    whitelistForStorage[domain] = Array.from(currentConfig.whitelist[domain]);
                }
                GM_setValue(key, JSON.stringify({
                    modules: currentConfig.modules,
                    cspRules: currentConfig.cspRules,
                    whitelist: whitelistForStorage
                }));
            } catch (e) {}
        }
    };

    const ProcessedElementsCache = {
        _processedElements: new WeakSet(),

        isProcessed(element) {
            if (!Utils.isElement(element)) return false;
            return this._processedElements.has(element) || element.dataset.adblockProcessed === 'true';
        },

        markAsProcessed(element) {
            if (!Utils.isElement(element)) return;
            this._processedElements.add(element);
            element.dataset.adblockProcessed = 'true';
        },

        clear() {
            this._processedElements = new WeakSet();
        }
    };

    const ResourceCanceller = {
        cancelResourceLoading(element) {
            if (!Utils.isElement(element) || ProcessedElementsCache.isProcessed(element)) return;
            
            const tagName = element.tagName;
            
            if (['IMG', 'VIDEO', 'AUDIO', 'SOURCE'].includes(tagName) && element.src) {
                element.src = '';
                element.srcset = '';
                element.removeAttribute('srcset');
                if (element.load) element.load();
            } else if (tagName === 'IFRAME' && element.src) {
                element.src = 'about:blank';
            } else if (tagName === 'SCRIPT' && element.src) {
                element.src = '';
            } else if (tagName === 'LINK' && element.rel === 'stylesheet' && element.href) {
                element.href = '';
            } else if (tagName === 'STYLE') {
                element.textContent = '';
            }
            
            if (element.parentNode) {
                element.parentNode.removeChild(element);
            }
        }
    };

    const SmartInterceptionModule = {
        originalSetTimeout: null,
        originalSetInterval: null,
        originalClearTimeout: null,
        originalClearInterval: null,
        processedTimers: new WeakSet(),
        stylePatterns: [
            /position\s*:\s*(fixed|sticky|absolute|relative)\s*(!?\s*important)?/i,
            /z-index\s*:\s*([1-9]\d{3,}|[2-9]\d{4,}|[1-9]\d{5,}|auto|inherit|static|relative|absolute|fixed|sticky|relative)\s*(!?\s*important)?/i,
            /(display|visibility|opacity)\s*:\s*(none|hidden|0)\s*(!?\s*important)?/i,
            /(width|height)\s*:\s*(\d{1,4}px|auto|inherit|%|vw|vh|em|rem|vmin|vmax)\s*(!?\s*important)?/i,
            /(top|bottom|left|right)\s*:\s*(0|auto|inherit|px|%|em|rem|vw|vh)\s*(!?\s*important)?/i,
            /background(?:\s*-\s*image)?\s*:\s*url\s*\(\s*['"]?(?!(data:|blob:))[^)'"]+['"]?\s*\)/i,
            /border\s*:\s*\d{1,2}px\s*(solid|dashed|dotted)\s*\S+/i,
            /overflow\s*:\s*(hidden|scroll|auto|visible)\s*(!?\s*important)?/i,
            /(margin|padding)\s*:\s*(\d+(\.\d+)?(px|%|em|rem)?|\s*auto|inherit)\s*(!?\s*important)?/i,
            /text-align\s*:\s*(center|right|justify)\s*(!?\s*important)?/i,
            /(font-size|line-height)\s*:\s*(\d+(\.\d+)?(px|%|em|rem)|normal)\s*(!?\s*important)?/i,
            /([\w\s\.\#\[\]\-\:]*?)\s*{.*(position\s*:\s*(fixed|sticky|absolute|relative)|z-index\s*:\s*([1-9]\d{3,}|[2-9]\d{4,}|[1-9]\d{5,})|display\s*:\s*(block|flex|grid|table|inline-block)|visibility\s*:\s*(visible)|width\s*:\s*(\d{1,4}px)|height\s*:\s*(\d{1,4}px)|top\s*:\s*(0|auto)|bottom\s*:\s*(0|auto)|left\s*:\s*(0|auto)|right\s*:\s*(0|auto)|overflow\s*:\s*(hidden|scroll|auto)).*\s*!\s*important/i
        ],
        init() {
            if (currentConfig.modules.smartInterception) {
                this.enable();
            }
        },
        enable() {
            this.setupTimerInterception();
            this.setupFastStyleChecker();
        },
        disable() {
            this.disableTimerInterception();
        },
        setupTimerInterception() {
            this.originalSetTimeout = window.setTimeout;
            this.originalSetInterval = window.setInterval;
            this.originalClearTimeout = window.clearTimeout;
            this.originalClearInterval = window.clearInterval;
            
            const self = this;
            
            window.setTimeout = function(callback, delay, ...args) {
                if (typeof callback === 'function') {
                    const callbackStr = callback.toString();
                    if (self.isAdTimerCallback(callbackStr)) {
                        const contentIdentifier = Utils.getContentIdentifier(null, { type: 'SETTIMEOUT', detail: `代码: ${Utils.truncateString(callbackStr, 100)}` });
                        if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                            LogManager.add('smartInterception', null, { type: 'SETTIMEOUT', detail: `广告定时器: ${Utils.truncateString(callbackStr, 100)}` });
                            const timerId = self.originalSetTimeout(() => {}, delay);
                            self.processedTimers.add(timerId);
                            return timerId;
                        }
                    }
                }
                return self.originalSetTimeout.call(this, callback, delay, ...args);
            };
            
            window.setInterval = function(callback, delay, ...args) {
                if (typeof callback === 'function') {
                    const callbackStr = callback.toString();
                    if (self.isAdTimerCallback(callbackStr)) {
                        const contentIdentifier = Utils.getContentIdentifier(null, { type: 'SETINTERVAL', detail: `代码: ${Utils.truncateString(callbackStr, 100)}` });
                        if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                            LogManager.add('smartInterception', null, { type: 'SETINTERVAL', detail: `广告定时器: ${Utils.truncateString(callbackStr, 100)}` });
                            const timerId = self.originalSetInterval(() => {}, delay);
                            self.processedTimers.add(timerId);
                            return timerId;
                        }
                    }
                }
                return self.originalSetInterval.call(this, callback, delay, ...args);
            };
            
            window.clearTimeout = function(timerId) {
                if (self.processedTimers.has(timerId)) {
                    self.processedTimers.delete(timerId);
                    return;
                }
                self.originalClearTimeout.call(this, timerId);
            };
            
            window.clearInterval = function(timerId) {
                if (self.processedTimers.has(timerId)) {
                    self.processedTimers.delete(timerId);
                    return;
                }
                self.originalClearInterval.call(this, timerId);
            };
        },
        disableTimerInterception() {
            if (this.originalSetTimeout) window.setTimeout = this.originalSetTimeout;
            if (this.originalSetInterval) window.setInterval = this.originalSetInterval;
            if (this.originalClearTimeout) window.clearTimeout = this.originalClearTimeout;
            if (this.originalClearInterval) window.clearInterval = this.originalClearInterval;
        },
        isAdTimerCallback(callbackStr) {
            const generalAdPatterns = [
                /\b(ad|ads|banner|popup|promo|sponsor|native|interstitial|rewarded|adslot|adbox|feed)\b/i,
                /ad\.(js|css|html)/i,
                /ads\.(js|css|html)/i,
                /banner\.(js|css|html)/i,
                /popup\.(js|css|html)/i,
                /\.(ad|ads|banner|popup|guanggao)[\w-]*\(/i,
                /showAd|displayAd|loadAd|renderAd/i,
                /\b(google_ad|youdao_ad|baidu_ads|toutiao_ads|xigua_ads|kuaishou_ads|weibo_ads|iqiyi_ad|qq_ad|tencent_ad|unionad|duomeng|guanggao)\b/i,
                /\b(doubleclick|googlesyndication|googleadservices|adsystem|adsense|admob|adx|taboola|outbrain|revcontent|contentad)\b/i,
                /['"](ad|ads|banner|popup|guanggao)['"]/i,
                /['"]\s*\+\s*['"](ad|ads|banner)['"]/i,
                /\w\s*=\s*\w\s*\+\s*['"](ad|ads|banner)['"]/i,
                /\w\s*\+\s*=\s*['"](ad|ads|banner)['"]/i,
                /\w\s*\.\s*\w\s*\(\s*['"](ad|ads|banner)['"]/i,
                /\w\s*\[\s*['"](ad|ads|banner)['"]\s*\]/i,
                /(adserver|adservice|advert|advertising|adtech|admanager)\b/i,
                /\/(ad|ads|banner|popup|guanggao)\//i,
                /function\s+\w*[Aa]d\w*\s*\(|function\s+\w*[Gg]uanggao\w*\s*\(/i,
                /var\s+\w*[Aa]d\w*\s*=|const\s+\w*[Aa]d\w*\s*=|let\s+\w*[Aa]d\w*\s*=/i,
                /var\s+\w*[Gg]uanggao\w*\s*=|const\s+\w*[Gg]uanggao\w*\s*=|let\s+\w*[Gg]uanggao\w*\s*=/i,
                /addEventListener.*(load|show|play).*(ad|ads|banner|guanggao)/i,
                /createElement.*(div|iframe|script).*(ad|ads|banner|guanggao)/i,
                /\.src\s*=\s*['"][^'"]*(ad|ads|banner|guanggao)[^'"]*['"]/i,
                /(amazon-adsystem|taboola|outbrain|adcolony|unityads|ironSource|applovin|chartboost|vungle|propellerads|adcash|adsterra|monumetric|ezoic|mediavine|zyncmedia|playwire)/i,
                /creative|campaign|impression|click|tracking|measurement|analytics/i,
                /\b(dynamic|config|init|setup|run|start|launch|module|service|api|ajax|request|get|post)\b.*\b(ad|ads|banner|popup|guanggao)\b/i,
                /common|utils|helpers|core|lib|manager|controller|provider|handler|loader|builder|generator|factory|observer|watcher|router|gateway|middleware|interceptor|plugin|extension|module/i,
                /\b(ads?|banner|popup|promo|native|interstitial|rewarded|adslot|adbox|feed)\b\.?\w*/i,
                /\b(guanggao)\b\.?\w*/i,
                /track|data|stat|event/i
            ];
            
            const isMinified = callbackStr.length > 50 && 
                              (callbackStr.includes(';') && 
                               callbackStr.split(';').length > 10 &&
                               callbackStr.replace(/\s+/g, '').length / callbackStr.length > 0.9);
            
            if (isMinified) {
                const compressedAdPatterns = [
                    /a\s*d\s*s/i,
                    /b\s*a\s*n\s*n\s*e\s*r/i,
                    /p\s*o\s*p\s*u\s*p/i,
                    /g\s*u\s*a\s*n\s*g\s*g\s*a\s*o/i,
                    /[\w\.]+ad[\w\.]*/i,
                    /ad[\w]*\s*=/i,
                    /guanggao[\w]*\s*=/i,
                    /track|data|event/i,
                    /init|setup|run|start|launch|module|service|api|ajax|request|get|post/i,
                    /common|utils|helpers|core|lib|manager|controller|provider|handler|loader|builder|generator|factory|observer|watcher|router|gateway|middleware|interceptor|plugin|extension/i
                ];
                
                if (compressedAdPatterns.some(pattern => pattern.test(callbackStr))) {
                    return true;
                }
            }
            
            return generalAdPatterns.some(pattern => pattern.test(callbackStr));
        },
        setupFastStyleChecker() {
            const observer = new MutationObserver(Utils.throttle((mutations) => {
                for (const mutation of mutations) {
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType !== Node.ELEMENT_NODE) continue;
                        if (ProcessedElementsCache.isProcessed(node) || Utils.isParentProcessed(node)) continue;
                        
                        this.fastCheckElement(node);
                    }
                }
            }, 200));
            
            observer.observe(document.documentElement, {
                childList: true,
                subtree: true
            });
        },
        fastCheckElement(element) {
            const tagName = element.tagName;
            
            if (tagName === 'STYLE') {
                this.checkStyleElement(element);
            }
        },
        checkStyleElement(styleElement) {
            const styleContent = styleElement.textContent;
            if (this.stylePatterns.some(pattern => pattern.test(styleContent))) {
                const contentIdentifier = Utils.getContentIdentifier(styleElement);
                if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                    LogManager.add('smartInterception', styleElement, { type: 'STYLE_ADS', detail: `广告样式: ${Utils.truncateString(styleContent, 100)}` });
                    ResourceCanceller.cancelResourceLoading(styleElement);
                    ProcessedElementsCache.markAsProcessed(styleElement);
                }
            }
        },
        check(element) {
            if (!currentConfig.modules.smartInterception || ProcessedElementsCache.isProcessed(element) || Utils.isParentProcessed(element)) return false;
            
            const tagName = element.tagName;
            
            if (tagName === 'STYLE') {
                this.checkStyleElement(element);
                return ProcessedElementsCache.isProcessed(element);
            }
            
            return false;
        }
    };

    const RemoveInlineScriptsModule = {
        mutationObserver: null,
        init() {
            if (currentConfig.modules.removeInlineScripts) {
                this.enable();
            }
        },
        enable() {
            this.mutationObserver = new MutationObserver(mutations => {
                for (const mutation of mutations) {
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'SCRIPT' && !node.src && !ProcessedElementsCache.isProcessed(node) && !Utils.isParentProcessed(node)) {
                            const contentIdentifier = Utils.getContentIdentifier(node);
                            if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                                LogManager.add('removeInlineScripts', node, { type: '内嵌脚本移除', detail: `内容: ${Utils.getScriptContentPreview(node)}` });
                                ProcessedElementsCache.markAsProcessed(node);
                                node.remove();
                            }
                        }
                    }
                }
            });
            this.mutationObserver.observe(document.documentElement, { childList: true, subtree: true });
            document.querySelectorAll('script:not([src])').forEach(script => {
                if (ProcessedElementsCache.isProcessed(script) || Utils.isParentProcessed(script)) return;
                const contentIdentifier = Utils.getContentIdentifier(script);
                if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                    LogManager.add('removeInlineScripts', script, { type: '内嵌脚本移除', detail: `内容: ${Utils.getScriptContentPreview(script)}` });
                    ProcessedElementsCache.markAsProcessed(script);
                    script.remove();
                }
            });
        },
        disable() {
            if (this.mutationObserver) {
                this.mutationObserver.disconnect();
                this.mutationObserver = null;
            }
        },
        check(element) {
            if (!currentConfig.modules.removeInlineScripts || ProcessedElementsCache.isProcessed(element) || Utils.isParentProcessed(element)) return false;
            if (element.tagName === 'SCRIPT' && !element.src) {
                const contentIdentifier = Utils.getContentIdentifier(element);
                if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                    LogManager.add('removeInlineScripts', element, { type: '内嵌脚本移除', detail: `内容: ${Utils.getScriptContentPreview(element)}` });
                    ProcessedElementsCache.markAsProcessed(element);
                    return true;
                }
            }
            return false;
        }
    };

    const RemoveExternalScriptsModule = {
        mutationObserver: null,
        init() {
            if (currentConfig.modules.removeExternalScripts) {
                this.enable();
            }
        },
        enable() {
            this.mutationObserver = new MutationObserver(mutations => {
                for (const mutation of mutations) {
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'SCRIPT' && node.src && !ProcessedElementsCache.isProcessed(node) && !Utils.isParentProcessed(node)) {
                            const contentIdentifier = Utils.getContentIdentifier(node);
                            if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                                LogManager.add('removeExternalScripts', node, { type: '外联脚本移除', detail: `SRC: ${Utils.truncateString(node.src, 100)}` });
                                ResourceCanceller.cancelResourceLoading(node);
                                ProcessedElementsCache.markAsProcessed(node);
                            }
                        }
                    }
                }
            });
            this.mutationObserver.observe(document.documentElement, { childList: true, subtree: true });
            document.querySelectorAll('script[src]').forEach(script => {
                if (ProcessedElementsCache.isProcessed(script) || Utils.isParentProcessed(script)) return;
                const contentIdentifier = Utils.getContentIdentifier(script);
                if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                    LogManager.add('removeExternalScripts', script, { type: '外联脚本移除', detail: `SRC: ${Utils.truncateString(script.src, 100)}` });
                    ResourceCanceller.cancelResourceLoading(script);
                    ProcessedElementsCache.markAsProcessed(script);
                }
            });
        },
        disable() {
            if (this.mutationObserver) {
                this.mutationObserver.disconnect();
                this.mutationObserver = null;
            }
        },
        check(element) {
            if (!currentConfig.modules.removeExternalScripts || ProcessedElementsCache.isProcessed(element) || Utils.isParentProcessed(element)) return false;
            if (element.tagName === 'SCRIPT' && element.src) {
                const contentIdentifier = Utils.getContentIdentifier(element);
                if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                    LogManager.add('removeExternalScripts', element, { type: '外联脚本移除', detail: `SRC: ${Utils.truncateString(element.src, 100)}` });
                    ResourceCanceller.cancelResourceLoading(element);
                    ProcessedElementsCache.markAsProcessed(element);
                    return true;
                }
            }
            return false;
        }
    };

    const ThirdPartyModule = {
        originalFetch: null,
        originalXhrOpen: null,
        originalXhrSend: null,
        originalCreateElement: null,
        originalAppendChild: null,
        originalDocumentWrite: null,
        originalEval: null,
        originalFunction: null,
        init() {
            if (currentConfig.modules.interceptThirdPartyResources) {
                this.enable();
            }
        },
        enable() {
            const cspBlockEvalRule = currentConfig.cspRules.find(rule => rule.id === 3 && rule.enabled);
            if (!cspBlockEvalRule) {
                this.originalEval = window.eval;
                window.eval = (code) => {
                    const contentIdentifier = Utils.getContentIdentifier(null, { type: 'EVAL', detail: code });
                    if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                        LogManager.add('interceptThirdPartyResources', null, { type: 'EVAL拦截', detail: `代码: ${Utils.truncateString(code, 100)}` });
                        return undefined;
                    }
                    return this.originalEval.call(unsafeWindow, code);
                };
            }

            const cspBlockFunctionRule = currentConfig.cspRules.find(rule => rule.id === 3 && rule.enabled);
            if (!cspBlockFunctionRule) {
                this.originalFunction = window.Function;
                window.Function = function(...args) {
                    const code = args.length > 0 ? args[args.length - 1] : '';
                    const contentIdentifier = Utils.getContentIdentifier(null, { type: 'FUNCTION_CONSTRUCTOR', detail: code });
                    if (contentIdentifier && !Whitelisting.isContentWhitelisted(Utils.getCurrentHostname(), contentIdentifier)) {
                        LogManager.add('interceptThirdPartyResources', null, { type: 'Function构造拦截', detail: `代码: ${Utils.truncateString(code, 100)}` });
                        return () => {};
                    }
                    return this.originalFunction.apply(unsafeWindow, args);
                };
            }

            this.originalFetch = window.fetch;
            window.fetch = (input, init) => {
                if (!currentConfig.modules.interceptThirdPartyResources) {
                    return this.originalFetch.call(this, input, init);
                }
                const url = typeof input === 'string' ? input : input.url;
                const resourceURL = Utils.getAbsoluteURL(url);
                const resourceHostname = Utils.getResourceHostname(resourceURL);
                const currentHost = Utils.getCurrentHostname();
                const contentIdentifier = Utils.getContentIdentifier(null, { type: 'FETCH', detail: `URL: ${Utils.truncateString(resourceURL, 100)}` });

                if (resourceHostname && Utils.isThirdPartyHost(resourceHostname, currentHost)) {
                    if (contentIdentifier && !Whitelisting.isContentWhitelisted(currentHost, contentIdentifier)) {
                        LogManager.add('interceptThirdPartyResources', null, { type: '第三方请求拦截', detail: `URL: ${Utils.truncateString(resourceURL, 100)}` });
                        return Promise.reject(new Error('Third-party resource blocked by AdBlocker.'));
                    }
                }
                return this.originalFetch.call(this, input, init);
            };

            this.originalXhrOpen = XMLHttpRequest.prototype.open;
            XMLHttpRequest.prototype.open = function(method, url) {
                if (!currentConfig.modules.interceptThirdPartyResources) {
                    return this.originalXhrOpen.apply(this, arguments);
                }
                const resourceURL = Utils.getAbsoluteURL(url);
                const resourceHostname = Utils.getResourceHostname(resourceURL);
                const currentHost = Utils.getCurrentHostname();
                const contentIdentifier = Utils.getContentIdentifier(null, { type: 'XHR', detail: `URL: ${Utils.truncateString(resourceURL, 100)}` });

                if (resourceHostname && Utils.isThirdPartyHost(resourceHostname, currentHost)) {
                    if (contentIdentifier && !Whitelisting.isContentWhitelisted(currentHost, contentIdentifier)) {
                        LogManager.add('interceptThirdPartyResources', null, { type: '第三方请求拦截', detail: `URL: ${Utils.truncateString(resourceURL, 100)}` });
                        this._adblockBlocked = true;
                        return;
                    }
                }
                return this.originalXhrOpen.apply(this, arguments);
            };
            this.originalXhrSend = XMLHttpRequest.prototype.send;
            XMLHttpRequest.prototype.send = function() {
                if (this._adblockBlocked) {
                    return;
                }
                this.originalXhrSend.apply(this, arguments);
            };

            this.originalCreateElement = document.createElement;
            document.createElement = (tagName, options) => {
                const element = this.originalCreateElement.call(document, tagName, options);
                if (!currentConfig.modules.interceptThirdPartyResources || ProcessedElementsCache.isProcessed(element)) {
                    return element;
                }
                const resourceURL = Utils.getAbsoluteURL(element.src || element.getAttribute('data-src') || element.href || element.action);
                if (resourceURL) {
                    const resourceHostname = Utils.getResourceHostname(resourceURL);
                    const currentHost = Utils.getCurrentHostname();
                    const contentIdentifier = Utils.getContentIdentifier(element);

                    if (resourceHostname && Utils.isThirdPartyHost(resourceHostname, currentHost)) {
                        if (contentIdentifier && !Whitelisting.isContentWhitelisted(currentHost, contentIdentifier)) {
                            LogManager.add('interceptThirdPartyResources', element, { type: '第三方资源拦截', detail: `SRC: ${Utils.truncateString(resourceURL, 100)}` });
                            ResourceCanceller.cancelResourceLoading(element);
                            ProcessedElementsCache.markAsProcessed(element);
                            return element;
                        }
                    }
                }
                return element;
            };

            this.originalAppendChild = Node.prototype.appendChild;
            Node.prototype.appendChild = function(node) {
                if (!currentConfig.modules.interceptThirdPartyResources || !Utils.isElement(node) || ProcessedElementsCache.isProcessed(node) || Utils.isParentProcessed(node)) {
                    return this.originalAppendChild.call(this, node);
                }
                const resourceURL = Utils.getAbsoluteURL(node.src || node.getAttribute('data-src') || node.href || node.action);
                if (resourceURL) {
                    const resourceHostname = Utils.getResourceHostname(resourceURL);
                    const currentHost = Utils.getCurrentHostname();
                    const contentIdentifier = Utils.getContentIdentifier(node);

                    if (resourceHostname && Utils.isThirdPartyHost(resourceHostname, currentHost)) {
                        if (contentIdentifier && !Whitelisting.isContentWhitelisted(currentHost, contentIdentifier)) {
                            LogManager.add('interceptThirdPartyResources', node, { type: '第三方资源拦截', detail: `SRC: ${Utils.truncateString(resourceURL, 100)}` });
                            ResourceCanceller.cancelResourceLoading(node);
                            ProcessedElementsCache.markAsProcessed(node);
                            return node;
                        }
                    }
                }
                return this.originalAppendChild.call(this, node);
            };

            this.originalDocumentWrite = document.write;
            document.write = function(content) {
                if (!currentConfig.modules.interceptThirdPartyResources) {
                    return this.originalDocumentWrite.call(document, content);
                }
                const tempDiv = document.createElement('div');
                tempDiv.innerHTML = content;
                const scripts = tempDiv.querySelectorAll('script[src]');
                let modifiedContent = content;

                for (const script of scripts) {
                    const src = script.src;
                    if (src) {
                        const resourceURL = Utils.getAbsoluteURL(src);
                        const resourceHostname = Utils.getResourceHostname(resourceURL);
                        const currentHost = Utils.getCurrentHostname();
                        const contentIdentifier = Utils.getContentIdentifier(script);

                        if (resourceHostname && Utils.isThirdPartyHost(resourceHostname, currentHost)) {
                            if (contentIdentifier && !Whitelisting.isContentWhitelisted(currentHost, contentIdentifier)) {
                                LogManager.add('interceptThirdPartyResources', script, { type: '第三方脚本通过document.write拦截', detail: `SRC: ${Utils.truncateString(resourceURL, 100)}` });
                                ResourceCanceller.cancelResourceLoading(script);
                                ProcessedElementsCache.markAsProcessed(script);
                            }
                        }
                    }
                }
                modifiedContent = tempDiv.innerHTML;
                this.originalDocumentWrite.call(document, modifiedContent);
            }.bind(this);
        },
        disable() {
            if (this.originalFetch) window.fetch = this.originalFetch;
            if (this.originalXhrOpen) XMLHttpRequest.prototype.open = this.originalXhrOpen;
            if (this.originalXhrSend) XMLHttpRequest.prototype.send = this.originalXhrSend;
            if (this.originalCreateElement) document.createElement = this.originalCreateElement;
            if (this.originalAppendChild) Node.prototype.appendChild = this.originalAppendChild;
            if (this.originalDocumentWrite) document.write = this.originalDocumentWrite;
            if (this.originalEval) unsafeWindow.eval = this.originalEval;
            if (this.originalFunction) unsafeWindow.Function = this.originalFunction;
        },
        check(element) {
            if (!currentConfig.modules.interceptThirdPartyResources || !Utils.isElement(element) || ProcessedElementsCache.isProcessed(element) || Utils.isParentProcessed(element)) return false;

            const resourceURL = Utils.getAbsoluteURL(element.src || element.getAttribute('data-src') || element.href || element.action);
            if (resourceURL) {
                const resourceHostname = Utils.getResourceHostname(resourceURL);
                const currentHost = Utils.getCurrentHostname();
                const contentIdentifier = Utils.getContentIdentifier(element);

                if (resourceHostname && Utils.isThirdPartyHost(resourceHostname, currentHost)) {
                    if (contentIdentifier && !Whitelisting.isContentWhitelisted(currentHost, contentIdentifier)) {
                        LogManager.add('interceptThirdPartyResources', element, { type: '第三方资源拦截', detail: `SRC: ${Utils.truncateString(resourceURL, 100)}` });
                        ResourceCanceller.cancelResourceLoading(element);
                        ProcessedElementsCache.markAsProcessed(element);
                        return true;
                    }
                }
            }
            return false;
        }
    };

    const CSPModule = {
        init() {},
        applyCSP() {
            if (!currentConfig.modules.manageCSP) return;
            const existingMeta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
            if (existingMeta) {
                existingMeta.remove();
            }
            
            const enabledRules = currentConfig.cspRules.filter(rule => rule.enabled);
            if (enabledRules.length === 0) {
                return;
            }

            const directives = {};
            enabledRules.forEach(rule => {
                const [directive, ...values] = rule.rule.split(' ');
                if (!directives[directive]) {
                    directives[directive] = new Set();
                }
                values.forEach(value => directives[directive].add(value));
            });

            let policyString = '';
            for (const directive in directives) {
                if (directives.hasOwnProperty(directive)) {
                    const values = Array.from(directives[directive]).join(' ');
                    policyString += `${directive} ${values}; `;
                }
            }
            policyString = policyString.trim();

            if (policyString) {
                const meta = document.createElement('meta');
                meta.httpEquiv = "Content-Security-Policy";
                meta.content = policyString;
                if (document.head) {
                    document.head.appendChild(meta);
                } else {
                    document.documentElement.prepend(meta);
                }
            }
        },
        removeCSP() {
            const existingMeta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
            if (existingMeta) {
                existingMeta.remove();
            }
        },
        updateRule(ruleId, enabled) {
            const rule = currentConfig.cspRules.find(r => r.id === ruleId);
            if (rule) {
                rule.enabled = enabled;
            }
        },
        showManagementPanel() {
            const ruleDisplayItems = currentConfig.cspRules.map(r =>
                `${r.id}. ${r.name} (${r.enabled ? '✅启用' : '❌禁用'})`
            ).join('\n');

            const promptMessage = `CSP策略管理:\n` +
                `当前状态: ${currentConfig.modules.manageCSP ? '已启用' : '已禁用'}\n\n` +
                `可用规则:\n${ruleDisplayItems}\n\n` +
                `操作指令:\n` +
                `enable - 启用CSP策略\n` +
                `disable - 禁用CSP策略\n` +
                `1on - 启用规则1\n` +
                `2off - 禁用规则2\n` +
                `1-2on - 启用规则1和2\n` +
                `1,3off - 禁用规则1和3\n` +
                `allon - 启用所有规则\n` +
                `alloff - 禁用所有规则\n\n` +
                `请输入指令:`;

            let input = prompt(promptMessage, "");
            if (input === null) return;
            input = input.trim().toLowerCase();
            let needsReload = false;

            if (input === 'enable') {
                currentConfig.modules.manageCSP = true;
                this.applyCSP();
                needsReload = true;
            } else if (input === 'disable') {
                currentConfig.modules.manageCSP = false;
                this.removeCSP();
                needsReload = true;
            } else if (input === 'allon') {
                currentConfig.cspRules.forEach(rule => rule.enabled = true);
                if (currentConfig.modules.manageCSP) this.applyCSP();
                needsReload = true;
            } else if (input === 'alloff') {
                currentConfig.cspRules.forEach(rule => rule.enabled = false);
                if (currentConfig.modules.manageCSP) this.removeCSP();
                needsReload = true;
            } else {
                const ruleActionMatch = input.match(/^([1-9,-]+)(on|off)$/);
                if (ruleActionMatch) {
                    const ruleSpecs = ruleActionMatch[1];
                    const action = ruleActionMatch[2];
                    const enable = action === 'on';
                    
                    let ruleIdsToModify = new Set();
                    ruleSpecs.split(',').forEach(spec => {
                        if (spec.includes('-')) {
                            const range = spec.split('-').map(Number);
                            if (range.length === 2 && !isNaN(range[0]) && !isNaN(range[1])) {
                                const start = Math.min(range[0], range[1]);
                                const end = Math.max(range[0], range[1]);
                                for (let i = start; i <= end; i++) {
                                    if (i >= 1 && i <= 9) ruleIdsToModify.add(i);
                                }
                            }
                        } else {
                            const id = parseInt(spec, 10);
                            if (!isNaN(id) && id >= 1 && id <= 9) {
                                ruleIdsToModify.add(id);
                            }
                        }
                    });

                    let modified = false;
                    ruleIdsToModify.forEach(id => {
                        const rule = currentConfig.cspRules.find(r => r.id === id);
                        if (rule && rule.enabled !== enable) {
                            rule.enabled = enable;
                            modified = true;
                        }
                    });
                    
                    if (modified) {
                        if (currentConfig.modules.manageCSP) this.applyCSP();
                        needsReload = true;
                    } else {
                        alert("未找到指定规则或规则状态已符合要求。");
                    }
                } else {
                    alert("无效指令。");
                }
            }

            if (needsReload) {
                StorageManager.saveConfig();
                location.reload();
            }
        }
    };

    const UIController = {
        mutationObserver: null,
        batchProcessingQueue: [],
        batchSize: 15,
        isProcessingBatch: false,
        lastProcessTime: 0,
        init() {
            StorageManager.loadConfig();
            this.applyInitialModuleStates();
            this.registerMenuCommands();
            this.applyModuleSettings();
            this.setupObservers();
        },
        applyInitialModuleStates() {
            Object.keys(DEFAULT_MODULE_STATE).forEach(key => {
                if (currentConfig.modules[key] === undefined) {
                    currentConfig.modules[key] = DEFAULT_MODULE_STATE[key];
                }
            });
            if (currentConfig.modules.manageCSP === undefined) {
                currentConfig.modules.manageCSP = false;
            }
            if (currentConfig.modules.interceptSubdomains === undefined) {
                currentConfig.modules.interceptSubdomains = false;
            }
            if (currentConfig.modules.smartInterception === undefined) {
                currentConfig.modules.smartInterception = false;
            }
        },
        registerMenuCommands() {
            GM_registerMenuCommand(`🔘 广告拦截 [${this.isAnyModuleEnabled() ? '✅' : '❌'}]`, () => this.toggleAllModules());
            const moduleOrder = ['smartInterception', 'removeInlineScripts', 'removeExternalScripts', 'interceptThirdPartyResources', 'interceptSubdomains', 'manageCSP'];
            moduleOrder.forEach(key => {
                GM_registerMenuCommand(
                    `${MODULE_NAMES[key]} [${currentConfig.modules[key] ? '✅' : '❌'}]`,
                    () => this.toggleModule(key)
                );
            });
            GM_registerMenuCommand('📜 查看拦截日志', () => LogManager.showInAlert());
            GM_registerMenuCommand('🚫 清空当前域名白名单', () => {
                const currentDomain = Utils.getCurrentHostname();
                if (confirm(`确定清空当前域名 (${currentDomain}) 的白名单吗?`)) {
                    Whitelisting.clearDomainWhitelist(currentDomain);
                    StorageManager.saveConfig();
                    alert("当前域名的白名单已清空。页面将刷新。");
                    location.reload();
                }
            });
            GM_registerMenuCommand('🛡️ CSP策略管理', () => CSPModule.showManagementPanel());
            GM_registerMenuCommand('🔄 重置所有设置', () => this.resetSettings());
        },
        isAnyModuleEnabled() {
            return Object.keys(MODULE_NAMES).some(key => currentConfig.modules[key]);
        },
        toggleAllModules() {
            const newState = !this.isAnyModuleEnabled();
            Object.keys(MODULE_NAMES).forEach(key => {
                currentConfig.modules[key] = newState;
            });
            this.applyModuleSettings();
            StorageManager.saveConfig();
            location.reload();
        },
        toggleModule(key) {
            if (key === 'interceptSubdomains') {
                if (!currentConfig.modules.interceptThirdPartyResources && !currentConfig.modules.interceptSubdomains) {
                    if (confirm('开启子域名拦截需要同时开启第三方资源拦截,是否同时开启?')) {
                        currentConfig.modules.interceptThirdPartyResources = true;
                        currentConfig.modules.interceptSubdomains = true;
                    } else {
                        return;
                    }
                } else {
                    currentConfig.modules[key] = !currentConfig.modules[key];
                }
            } else if (key === 'interceptThirdPartyResources') {
                const newState = !currentConfig.modules.interceptThirdPartyResources;
                currentConfig.modules.interceptThirdPartyResources = newState;
                if (!newState && currentConfig.modules.interceptSubdomains) {
                    currentConfig.modules.interceptSubdomains = false;
                }
            } else if (key === 'smartInterception') {
                currentConfig.modules[key] = !currentConfig.modules[key];
            } else {
                currentConfig.modules[key] = !currentConfig.modules[key];
            }
            
            this.applyModuleSettings();
            StorageManager.saveConfig();
            location.reload();
        },
        applyModuleSettings() {
            SmartInterceptionModule.init();
            RemoveInlineScriptsModule.init();
            RemoveExternalScriptsModule.init();
            ThirdPartyModule.init();
            CSPModule.init();
        },
        setupObservers() {
            const relevantModulesEnabled = Object.keys(MODULE_NAMES).some(key =>
                currentConfig.modules[key] && (
                    key === 'removeInlineScripts' ||
                    key === 'removeExternalScripts' ||
                    key === 'interceptThirdPartyResources' ||
                    key === 'smartInterception'
                )
            );
            if (!relevantModulesEnabled) return;

            this.mutationObserver = new MutationObserver(Utils.throttle((mutations) => {
                for (const mutation of mutations) {
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === Node.ELEMENT_NODE && !ProcessedElementsCache.isProcessed(node) && !Utils.isParentProcessed(node)) {
                            this.addToBatchProcessingQueue(node);
                        }
                    }
                }
            }, 100));
            
            this.mutationObserver.observe(document.documentElement, {
                childList: true,
                subtree: true,
            });

            this.processExistingElementsBatch();
        },
        addToBatchProcessingQueue(element) {
            this.batchProcessingQueue.push(element);
            if (!this.isProcessingBatch) {
                this.processBatch();
            }
        },
        processBatch() {
            this.isProcessingBatch = true;
            
            const processChunk = () => {
                const now = Date.now();
                if (now - this.lastProcessTime < 16) {
                    requestAnimationFrame(processChunk);
                    return;
                }
                
                const chunk = this.batchProcessingQueue.splice(0, this.batchSize);
                this.lastProcessTime = now;
                
                chunk.forEach(node => {
                    if (ProcessedElementsCache.isProcessed(node) || Utils.isParentProcessed(node)) return;
                    
                    if (node.tagName === 'SCRIPT') {
                        if (currentConfig.modules.removeInlineScripts && !node.src) {
                            if (RemoveInlineScriptsModule.check(node)) node.remove();
                        } else if (currentConfig.modules.removeExternalScripts && node.src) {
                            if (RemoveExternalScriptsModule.check(node)) ResourceCanceller.cancelResourceLoading(node);
                        } else if (currentConfig.modules.interceptThirdPartyResources) {
                            if (ThirdPartyModule.check(node)) ResourceCanceller.cancelResourceLoading(node);
                        }
                    } else if (currentConfig.modules.interceptThirdPartyResources) {
                        if (ThirdPartyModule.check(node)) ResourceCanceller.cancelResourceLoading(node);
                    }
                    
                    if (currentConfig.modules.smartInterception) {
                        SmartInterceptionModule.check(node);
                    }
                });
                
                if (this.batchProcessingQueue.length > 0) {
                    requestAnimationFrame(processChunk);
                } else {
                    this.isProcessingBatch = false;
                }
            };
            
            requestAnimationFrame(processChunk);
        },
        processExistingElementsBatch() {
            const selector = 'script, iframe, img, a[href], link[rel="stylesheet"], form, video, audio, source, img[data-src], style, link[rel="preload"], link[rel="prefetch"]';
            const elementsToProcess = Array.from(document.querySelectorAll(selector));
            
            const processInChunks = () => {
                const chunk = elementsToProcess.splice(0, this.batchSize * 2);
                
                chunk.forEach(element => {
                    if (!ProcessedElementsCache.isProcessed(element) && !Utils.isParentProcessed(element)) {
                        this.addToBatchProcessingQueue(element);
                    }
                });
                
                if (elementsToProcess.length > 0) {
                    setTimeout(processInChunks, 0);
                }
            };
            
            processInChunks();
        },
        resetSettings() {
            if (confirm("确定要重置所有设置吗?这将清除所有配置和白名单。")) {
                Object.assign(currentConfig.modules, DEFAULT_MODULE_STATE);
                currentConfig.cspRules = DEFAULT_CSP_RULES_TEMPLATE.map(rule => ({ ...rule }));
                Whitelisting.clearAllWhitelists();
                ProcessedElementsCache.clear();
                CSPModule.removeCSP();
                StorageManager.saveConfig();
                location.reload();
            }
        }
    };

    function initializeAdBlocker() {
        UIController.init();
        if (currentConfig.modules.manageCSP) {
            CSPModule.applyCSP();
        }
    }

    if (document.readyState === 'loading') {
        initializeAdBlocker();
    } else {
        setTimeout(initializeAdBlocker, 0);
    }

})();