Greasy Fork

Greasy Fork is available in English.

广告终结者 v2.0

[13模块完整版] 动态检测、框架过滤、堆叠拦截、第三方拦截四大系统,增强广告拦截

当前为 2025-02-02 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         广告终结者 v2.0
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  [13模块完整版] 动态检测、框架过滤、堆叠拦截、第三方拦截四大系统,增强广告拦截
// @author       TMHhz
// @match        *://*/*
// @license      GPLv3
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_notification
// ==/UserScript==

(function() {
    'use strict';

    // 核心配置
    const CONFIG = {
        maxLogs: 100,
        adKeywords: [
            'ad', 'ads', 'advert', 'banner', 'popup', '推广', '广告', 'gg', 
            'advertisement', 'sponsor', '推荐', 'adv', 'guanggao', 'syad', 
            'bfad', '男男', '女女', '弹窗', '悬浮', '浮动', '浮窗', '葡京', 
            'pop', 'sticky', 'fixed', 'tip', 'tips', 'adbox', 'adsense', 
            'adserver', 'advertmarket', 'advertising', 'cookie-sync', '国产', '偷拍', '黑料', '横幅'
        ],
        checkAttributes: [
            'id', 'class', 'src', 'href', 'data-ad', 'name', 
            'data-src', 'data-url', 'alt', 'title', 'onclick', 'style'
        ],
        protectionRules: {
            minWidth: 50,
            minHeight: 20,
            iframeSizeThreshold: 2,
            zIndexThreshold: 50,
            sizeThresholdRatio: 0.15,
            similarityThreshold: 0.8,
            dynamicIdLength: 10,
            dynamicIdDigits: 5,
            fixedPositionThreshold: 2,
            floatingKeywords: ['float', '悬浮', '弹窗', '浮窗', '浮动','横幅','fixed','sticky','tip','tips','pop'],
            adImagePatterns: ['/*.gif', '/*.webp', '/*.swf'],
            adContainerSelectors: ['[id*="side"]', '[class*="side"]'],
            viewportEdgeThreshold: 10,
            maxFrameDepth: 3,
            textAdKeywords: ['限时优惠', '立即下载', '免费领取', 'vx:', '点击咨询', '低至1折', '加群', '抢购', '微信', 'telegram', '国产', '偷拍', '黑料']
        },
        whitelist: {
            scriptNamespaces: ['pswMgrDialog', 'userscript-'],
            protectedAttributes: [
                {name: 'id', values: ['pswMgrDialog', 'userscript-quickFill']},
                {name: 'class', values: ['userscript-quickFill']}
            ],
            selectors: ['#pswMgrDialog', '.userscript-quickFill', '.userscript-pswmgrDlg'],
            thirdparty: ['cdn.bootcss.com', 'unpkg.com']
        },
        defaultSettings: {
            // 动态检测系统
            dynamicIdDetection: true,
            attributeSimilarity: true,
            sizeAnomaly: true,
            adAttributeDetection: true,
            
            // 框架过滤系统
            iframeAttributeCheck: true,
            parentContainerCheck: true,
            nestedFrameDetection: true,
            
            // 堆叠拦截系统
            highZIndexDetection: true,
            fixedPositionCheck: true,
            overlayDetection: true,
            floatingLayerCheck: true,
            
            // 第三方拦截
            thirdpartyCheck: true,
            cookieSyncDetection: true,
            
            // 增强功能
            floatingAdDetection: true,
            imageAdDetection: true,
            sidebarAdDetection: true,
            textAdDetection: true
        }
    };

    // ======================= 工具类 =======================
    class AdUtils {
        static safeRemove(node, module, reason) {
            if (!node || !node.parentNode || this.isWhitelisted(node)) {
                console.debug('[拦截跳过] 白名单元素:', node);
                return false;
            }

            try {
                Logger.logRemoval({
                    module,
                    element: {
                        tag: node.tagName,
                        id: node.id,
                        class: node.className,
                        html: node.outerHTML.slice(0, 500)
                    },
                    reason
                });

                node.parentNode.removeChild(node);
                this.cleanAncestors(node.parentNode);
                console.log('[成功移除]', module, node);
                return true;
            } catch (e) {
                console.error('元素移除失败:', e);
                return false;
            }
        }

        static cleanAncestors(node) {
            let current = node;
            while (current && current !== document.documentElement) {
                if (current.children.length === 0 && 
                   !current.hasAttribute('data-keep-empty')) {
                    const parent = current.parentNode;
                    parent?.removeChild(current);
                    current = parent;
                } else {
                    break;
                }
            }
        }

        static isWhitelisted(element) {
            let currentElement = element;
            while (currentElement && currentElement !== document.documentElement) {
                const src = currentElement.getAttribute('src');
                if (src && CONFIG.whitelist.thirdparty.some(domain => src.includes(domain))) return true;

                if (CONFIG.whitelist.selectors.some(s => currentElement.matches(s))) return true;
                if (CONFIG.whitelist.protectedAttributes.some(attr => {
                    const attrValue = currentElement.getAttribute(attr.name);
                    return attrValue && attr.values.some(v => 
                        attr.name === 'class' ? 
                        currentElement.classList.contains(v) :
                        attrValue.startsWith(v)
                    );
                })) return true;
                if (CONFIG.whitelist.scriptNamespaces.some(ns => {
                    const id = currentElement.id || '';
                    const className = currentElement.className || '';
                    return id.startsWith(ns) || className.startsWith(ns);
                })) return true;

                currentElement = currentElement.parentElement;
            }
            return false;
        }

        static calculateSimilarity(a, b) {
            const setA = new Set(a.split(''));
            const setB = new Set(b.split(''));
            const intersection = new Set([...setA].filter(x => setB.has(x)));
            return intersection.size / Math.max(setA.size, setB.size);
        }
    }

    // ======================= 第三方拦截模块 =======================
    class ThirdpartyInterceptor {
        constructor() {
            this.baseHost = this.getCurrentBaseHost();
            this.initObserver();
        }

        getCurrentBaseHost() {
            const host = location.hostname;
            return this.isIP(host) ? host : this.getBaseDomain(host);
        }

        isIP(host) {
            return /^(?:\d{1,3}\.){3}\d{1,3}$/.test(host);
        }

        getBaseDomain(url) {
            try {
                const parsed = new URL(url.startsWith('http') ? url : `http://${url}`);
                const parts = parsed.hostname.split('.');
                if (parts.length <= 1) return parsed.hostname;
                return parts.slice(-2).join('.');
            } catch {
                return this.baseHost;
            }
        }

        isThirdparty(src) {
            if (!src || CONFIG.whitelist.thirdparty.some(d => src.includes(d))) return false;
            try {
                return this.getBaseDomain(src) !== this.baseHost;
            } catch {
                return false;
            }
        }

        processNode(node) {
            const tag = node.tagName.toUpperCase();
            if (['SCRIPT', 'IFRAME'].includes(tag)) {
                const src = node.getAttribute('src');
                if (src && this.isThirdparty(src)) {
                    AdUtils.safeRemove(node, 'thirdparty', {
                        type: '第三方资源',
                        detail: `拦截源: ${this.getBaseDomain(src)}`
                    });
                }
            }
        }

        initObserver() {
            const observer = new MutationObserver(mutations => {
                mutations.forEach(m => {
                    m.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            this.processNode(node);
                            node.querySelectorAll('script, iframe').forEach(n => this.processNode(n));
                        }
                    });
                });
            });

            observer.observe(document, {
                childList: true,
                subtree: true
            });

            document.querySelectorAll('script, iframe').forEach(n => this.processNode(n));
        }
    }

    // ======================= 核心拦截系统 =======================
    class CoreCleaner {
        constructor() {
            if (DomainConfig.getConfig('thirdpartyCheck')) {
                this.thirdpartyInterceptor = new ThirdpartyInterceptor();
            }
            
            if (DomainConfig.getConfig('cookieSyncDetection')) {
                this.cookieSyncCheck();
            }
            
            if (this.isAnyModuleEnabled()) {
                this.initEnhancedObserver();
                this.initialCleanup();
            }
        }

        isAnyModuleEnabled() {
            return Object.keys(CONFIG.defaultSettings).some(
                key => DomainConfig.getConfig(key)
            );
        }

        initEnhancedObserver() {
            this.observer = new MutationObserver(mutations => {
                mutations.forEach(m => {
                    m.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            if (node.shadowRoot) {
                                this.observer.observe(node.shadowRoot, {
                                    childList: true,
                                    subtree: true
                                });
                            }
                            
                            this.checkGenericElements(node);
                            if (node.tagName === 'IFRAME') this.checkIframes(node);
                            if (['DIV', 'P', 'SPAN'].includes(node.tagName)) this.checkTextAds(node);
                        }
                    });
                });
            });

            this.observer.observe(document, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ['style', 'class', 'id', 'src', 'href']
            });
        }

        initialCleanup() {
            if (!this.isAnyModuleEnabled()) return;

            this.runDetectionSystems();
            this.checkElements('iframe', this.checkIframes.bind(this));
            this.checkElements('*', this.checkGenericElements.bind(this));
            this.checkElements('img', this.checkImageAds.bind(this));
            this.checkElements('*', this.checkFloatingAds.bind(this));
            this.checkSidebarContainers();
            this.checkElements('div,p,span', this.checkTextAds.bind(this));
        }

        runDetectionSystems() {
            if (DomainConfig.getConfig('highZIndexDetection')) this.checkHighZIndex();
            if (DomainConfig.getConfig('fixedPositionCheck')) this.checkFixedPosition();
            if (DomainConfig.getConfig('overlayDetection')) this.checkOverlay();
            if (DomainConfig.getConfig('floatingLayerCheck')) this.checkFloatingLayers();
        }

        checkElements(selector, checker) {
            if (!this.isAnyModuleEnabled()) return;
            document.querySelectorAll(selector).forEach(node => checker(node));
        }

        // ========== 框架过滤系统 ==========
        checkIframes(iframe) {
            if (DomainConfig.getConfig('iframeAttributeCheck')) {
                this.checkIframeAttributes(iframe);
            }
            if (DomainConfig.getConfig('parentContainerCheck')) {
                this.checkParentContainers(iframe);
            }
            if (DomainConfig.getConfig('nestedFrameDetection')) {
                this.checkNestedFrames(iframe);
            }
        }

        checkParentContainers(iframe) {
            const parents = ['div', 'section', 'article']
                .map(s => iframe.closest(s))
                .filter(Boolean);
            
            parents.forEach(parent => {
                if (!AdUtils.isWhitelisted(parent)) {
                    AdUtils.safeRemove(parent, 'frame-parent', {
                        type: '父容器过滤',
                        detail: '可疑iframe容器'
                    });
                }
            });
        }

        checkIframeAttributes(iframe) {
            const hasAdSrc = CONFIG.adKeywords.some(kw => iframe.src.includes(kw));
            const isHidden = iframe.offsetWidth < CONFIG.protectionRules.iframeSizeThreshold || 
                           iframe.offsetHeight < CONFIG.protectionRules.iframeSizeThreshold;
            
            if (isHidden || hasAdSrc) {
                AdUtils.safeRemove(iframe, 'frame-attr', {
                    type: 'iframe属性',
                    detail: hasAdSrc ? 
                        `广告源: ${iframe.src.slice(0, 50)}` : 
                        `隐藏iframe: ${iframe.offsetWidth}x${iframe.offsetHeight}`
                });
            }
        }

        checkNestedFrames(iframe) {
            try {
                const depth = this.getFrameDepth(iframe);
                if (depth > CONFIG.protectionRules.maxFrameDepth) {
                    AdUtils.safeRemove(iframe, 'nested-frame', {
                        type: '嵌套框架',
                        detail: `嵌套层级: ${depth}层`
                    });
                }
            } catch (e) {
                console.log('框架深度检测异常:', e);
            }
        }

        getFrameDepth(node) {
            let depth = 0;
            let currentNode = node;
            while (currentNode.parentNode) {
                if (currentNode.tagName === 'IFRAME') depth++;
                currentNode = currentNode.parentNode;
            }
            return depth;
        }

        // ========== 动态检测系统 ==========
        checkGenericElements(element) {
            if (DomainConfig.getConfig('dynamicIdDetection')) {
                this.checkDynamicId(element);
            }
            if (DomainConfig.getConfig('attributeSimilarity')) {
                this.checkAttributeSimilarity(element);
            }
            if (DomainConfig.getConfig('sizeAnomaly')) {
                this.checkSizeAnomaly(element);
            }
            if (DomainConfig.getConfig('adAttributeDetection')) {
                this.checkAdAttributes(element);
            }
        }

        checkDynamicId(element) {
            const id = element.id || '';
            if (id.length > CONFIG.protectionRules.dynamicIdLength || 
               /\d{5,}/.test(id)) {
                AdUtils.safeRemove(element, 'dynamic-id', {
                    type: '动态ID检测',
                    detail: `ID特征异常: ${id.slice(0, 50)}`
                });
            }
        }

        checkAttributeSimilarity(element) {
            const id = element.id || '';
            const className = element.className || '';
            if (AdUtils.calculateSimilarity(id, className) > CONFIG.protectionRules.similarityThreshold) {
                AdUtils.safeRemove(element, 'attr-similarity', {
                    type: '属性相似度',
                    detail: `ID与class相似度过高`
                });
            }
        }

        checkSizeAnomaly(element) {
            const rect = element.getBoundingClientRect();
            if (rect.width * rect.height > 
                window.innerWidth * window.innerHeight * CONFIG.protectionRules.sizeThresholdRatio) {
                AdUtils.safeRemove(element, 'size-anomaly', {
                    type: '尺寸异常',
                    detail: `占用面积 ${Math.round(rect.width*rect.height)}px²`
                });
            }
        }

        checkAdAttributes(element) {
            const attrCheck = CONFIG.checkAttributes.find(attr => {
                const value = element.getAttribute(attr) || '';
                return CONFIG.adKeywords.some(kw => value.includes(kw));
            });

            if (attrCheck) {
                AdUtils.safeRemove(element, 'attr-match', {
                    type: '属性匹配',
                    attribute: attrCheck,
                    value: element.getAttribute(attrCheck).slice(0, 100)
                });
            }
        }

        // ========== 堆叠拦截系统 ==========
        checkHighZIndex() {
            document.querySelectorAll('body *').forEach(el => {
                const zIndex = parseInt(getComputedStyle(el).zIndex);
                if (!isNaN(zIndex) && zIndex > CONFIG.protectionRules.zIndexThreshold) {
                    AdUtils.safeRemove(el, 'z-index', {
                        type: '高堆叠',
                        detail: `z-index: ${zIndex}`
                    });
                }
            });
        }

        checkFixedPosition() {
            const fixedElements = [];
            document.querySelectorAll('*').forEach(el => {
                const style = getComputedStyle(el);
                if (style.position === 'fixed' && !AdUtils.isWhitelisted(el)) {
                    fixedElements.push(el);
                }
            });

            if (fixedElements.length > CONFIG.protectionRules.fixedPositionThreshold) {
                fixedElements.forEach(el => {
                    AdUtils.safeRemove(el, 'fixed-pos', {
                        type: '过量固定元素',
                        detail: `发现${fixedElements.length}个固定元素`
                    });
                });
            }
        }

        checkOverlay() {
            document.querySelectorAll('div, section').forEach(el => {
                const style = getComputedStyle(el);
                if (style.backgroundColor !== 'rgba(0, 0, 0, 0)' && 
                   parseFloat(style.opacity) > 0.5 &&
                   el.offsetWidth >= window.innerWidth * 0.8) {
                    AdUtils.safeRemove(el, 'overlay', {
                        type: '遮罩层',
                        detail: `背景色: ${style.backgroundColor}`
                    });
                }
            });
        }

        checkFloatingLayers() {
            document.querySelectorAll('*').forEach(el => {
                const style = getComputedStyle(el);
                if (style.position === 'fixed' && 
                   (el.offsetWidth < 200 || el.offsetHeight < 100)) {
                    AdUtils.safeRemove(el, 'floating-layer', {
                        type: '悬浮层',
                        detail: `小型浮动元素: ${el.offsetWidth}x${el.offsetHeight}`
                    });
                }
            });
        }

        // ========== 增强功能模块 ==========
        checkFloatingAds(element) {
            if (!DomainConfig.getConfig('floatingAdDetection')) return;

            const style = getComputedStyle(element);
            const isFixed = style.position === 'fixed';
            const isSticky = style.position === 'sticky';
            const hasFloatingClass = CONFIG.protectionRules.floatingKeywords.some(kw => 
                element.className.includes(kw) || element.id.includes(kw)
            );

            const rect = element.getBoundingClientRect();
            const edgeDetected = 
                rect.top <= CONFIG.protectionRules.viewportEdgeThreshold ||
                rect.bottom >= window.innerHeight - CONFIG.protectionRules.viewportEdgeThreshold ||
                rect.left <= CONFIG.protectionRules.viewportEdgeThreshold ||
                rect.right >= window.innerWidth - CONFIG.protectionRules.viewportEdgeThreshold;

            if ((isFixed || isSticky || hasFloatingClass) && edgeDetected) {
                AdUtils.safeRemove(element, 'floating-ad', {
                    type: '浮动广告',
                    detail: `定位方式: ${style.position}, 位置: ${Math.round(rect.top)}px`
                });
            }
        }

        checkImageAds(img) {
            if (!DomainConfig.getConfig('imageAdDetection')) return;

            const src = img.src.toLowerCase();
            const isAdImage = CONFIG.protectionRules.adImagePatterns.some(pattern => 
                src.endsWith(pattern) || src.includes('adimg')
            );

            const adDimensions = [
                [728, 90], [300, 250], [336, 280], [250, 250], [120, 600], 
                [160, 600], [468, 60], [900, 100]
            ];
            const isAdSize = adDimensions.some(([w, h]) => 
                Math.abs(img.width - w) < 10 && 
                Math.abs(img.height - h) < 10
            );

            if (isAdImage || isAdSize) {
                AdUtils.safeRemove(img, 'image-ad', {
                    type: '图片广告',
                    detail: `尺寸: ${img.width}x${img.height}, 源: ${src.slice(0, 50)}`
                });
            }
        }

        checkSidebarContainers() {
            if (!DomainConfig.getConfig('sidebarAdDetection')) return;

            document.querySelectorAll(CONFIG.protectionRules.adContainerSelectors.join(',')).forEach(container => {
                const rect = container.getBoundingClientRect();
                const isSidePositioned = 
                    rect.left <= 10 || 
                    rect.right >= window.innerWidth - 10;

                if (isSidePositioned && container.offsetHeight > 200) {
                    AdUtils.safeRemove(container, 'sidebar-ad', {
                        type: '侧边栏容器',
                        detail: `位置: ${Math.round(rect.left)}px, 高度: ${container.offsetHeight}px`
                    });
                }
            });
        }

        checkTextAds(element) {
            if (!DomainConfig.getConfig('textAdDetection')) return;
            
            const text = element.textContent.toLowerCase();
            const isSuspicious = CONFIG.protectionRules.textAdKeywords.some(kw => 
                text.includes(kw.toLowerCase())
            );
            
            if (isSuspicious && element.children.length === 0) {
                AdUtils.safeRemove(element, 'text-ad', {
                    type: '文本广告',
                    detail: `包含关键词: ${text.slice(0,30)}`
                });
            }
        }

        cookieSyncCheck() {
            document.querySelectorAll('script').forEach(script => {
                const src = script.getAttribute('src');
                if (src && src.includes('cookie') && src.includes('sync')) {
                    AdUtils.safeRemove(script, 'cookie-sync', {
                        type: 'Cookie同步',
                        detail: `检测到同步脚本: ${src.slice(0, 50)}`
                    });
                }
            });
        }

        destructor() {
            if (this.observer) this.observer.disconnect();
        }
    }

    // ======================= 配置系统 =======================
    class DomainConfig {
        static get currentDomain() {
            return location.hostname.replace(/^www\./, '');
        }

        static getConfig(key) {
            const allConfigs = GM_getValue('domainConfigs', {});
            const domainConfig = allConfigs[this.currentDomain] || {...CONFIG.defaultSettings};
            return key in domainConfig ? domainConfig[key] : CONFIG.defaultSettings[key];
        }

        static updateConfig(key, value) {
            const allConfigs = GM_getValue('domainConfigs', {});
            if (!allConfigs[this.currentDomain]) {
                allConfigs[this.currentDomain] = {...CONFIG.defaultSettings};
            }
            allConfigs[this.currentDomain][key] = value;
            GM_setValue('domainConfigs', allConfigs);
        }

        static resetConfig() {
            const allConfigs = GM_getValue('domainConfigs', {});
            delete allConfigs[this.currentDomain];
            GM_setValue('domainConfigs', allConfigs);
        }
    }

    // ======================= 用户界面 =======================
    class UIController {
        static init() {
            this.registerDomainControls();
            this.registerGlobalControls();
            this.registerInfoButton();
            this.registerMasterSwitch();
        }

        static registerMasterSwitch() {
            const allEnabled = Object.keys(CONFIG.defaultSettings).every(
                key => DomainConfig.getConfig(key)
            );
            GM_registerMenuCommand(
                `🔘 一键${allEnabled ? '禁用' : '启用'}所有模块`,
                () => this.toggleAllModules()
            );
        }

        static toggleAllModules() {
            const allKeys = Object.keys(CONFIG.defaultSettings);
            const currentState = allKeys.every(key => DomainConfig.getConfig(key));
            
            allKeys.forEach(key => {
                DomainConfig.updateConfig(key, !currentState);
            });

            GM_notification({
                title: '总开关已切换',
                text: `所有模块已${!currentState ? '启用' : '禁用'}`,
                timeout: 2000
            });
            
            window.location.reload();
        }

        static registerInfoButton() {
            GM_registerMenuCommand('📘 13模块说明', () => this.showInstructions());
        }

        static showInstructions() {
            const instructions = `【广告终结者v1.3 - 13大模块说明】

██ 核心拦截系统 ██
1. 第三方资源拦截
   ✔ 拦截规则:
     - 非本站域名的<script>/<iframe>
     - 排除白名单中的CDN资源
     - 自动识别跟踪脚本

2. iframe属性检测
   ✔ 拦截规则:
     - 尺寸<2x2像素的隐藏框架
     - src包含50+广告关键词
     - 移除iframe及父容器

3. 父容器检测
   ✔ 拦截规则:
     - 包裹iframe的div/section
     - 无有效内容的空容器
     - 多层嵌套广告容器

██ 动态检测系统 ██
4. 动态ID检测
   ✔ 拦截规则:
     - ID长度>10字符
     - 包含5+连续数字
     - 示例:ad_12345

5. 属性相似度
   ✔ 拦截规则:
     - ID与class相似度>80%
     - 属性值重复率过高
     - 示例:id="ad" class="ad-box"

6. 尺寸异常
   ✔ 拦截规则:
     - 元素面积>屏幕15%
     - 自动计算视窗占比
     - 响应式布局识别

7. 广告属性检测
   ✔ 拦截规则:
     - 12个属性关键词匹配
     - 50+中英文广告词库
     - 支持data-*属性

██ 堆叠拦截系统 ██
8. 高z-index检测
   ✔ 拦截规则:
     - z-index值>50
     - 排除导航菜单等白名单
     - 动态堆叠上下文分析

9. 固定定位检测
   ✔ 拦截规则:
     - fixed元素>2个
     - 识别"回到顶部"等正常元素
     - 支持sticky定位

10. 遮罩层检测
    ✔ 拦截规则:
      - 半透明背景(rgba)
      - 覆盖80%屏幕宽度
      - 防点击劫持

11. 浮动层检测
    ✔ 拦截规则:
      - 边缘吸附<10px
      - 含float/sticky定位
      - 30+中文特征词

██ 增强功能模块 ██
12. 嵌套框架检测
    ✔ 拦截规则:
      - iframe嵌套>3层
      - 空白嵌套框架
      - 跨域嵌套容器

13. 文本广告检测
    ✔ 拦截规则:
      - 包含20+营销关键词
      - 无子元素的纯文本
      - 微信号/QQ号识别`;

            alert(instructions);
        }

        static registerDomainControls() {
            const SEPARATOR = '───────────────';
            GM_registerMenuCommand(SEPARATOR, () => {});

            this.registerModuleControls([
                'thirdpartyCheck',
                'dynamicIdDetection',
                'attributeSimilarity',
                'sizeAnomaly',
                'adAttributeDetection'
            ]);

            GM_registerMenuCommand(SEPARATOR, () => {});

            this.registerModuleControls([
                'iframeAttributeCheck',
                'parentContainerCheck',
                'nestedFrameDetection'
            ]);

            GM_registerMenuCommand(SEPARATOR, () => {});

            this.registerModuleControls([
                'highZIndexDetection',
                'fixedPositionCheck',
                'overlayDetection',
                'floatingLayerCheck'
            ]);

            GM_registerMenuCommand(SEPARATOR, () => {});
            
            this.registerModuleControls([
                'floatingAdDetection',
                'imageAdDetection',
                'sidebarAdDetection',
                'textAdDetection',
                'cookieSyncDetection'
            ]);

            GM_registerMenuCommand(SEPARATOR, () => {});
            
            GM_registerMenuCommand('🔄 重置当前网站设置', () => {
                DomainConfig.resetConfig();
                GM_notification({
                    title: '配置已重置',
                    text: `${DomainConfig.currentDomain} 设置已恢复默认`,
                    timeout: 2000
                });
                window.location.reload();
            });
        }

        static registerModuleControls(keys) {
            keys.forEach(key => {
                const currentValue = DomainConfig.getConfig(key);
                GM_registerMenuCommand(
                    `   ${this.getKeyName(key)} [${currentValue ? '✅' : '❌'}]`,
                    () => this.toggleConfig(key)
                );
            });
        }

        static registerGlobalControls() {
            GM_registerMenuCommand('📜 查看拦截日志', this.showLogs.bind(this));
            GM_registerMenuCommand('🧹 清除当前日志', this.clearLogs.bind(this));
        }

        static toggleConfig(key) {
            const current = DomainConfig.getConfig(key);
            DomainConfig.updateConfig(key, !current);
            GM_notification({
                title: '配置已更新',
                text: `${this.getKeyName(key)} 已${!current ? '启用' : '禁用'}`,
                timeout: 1500
            });
            window.location.reload();
        }

        static getKeyName(key) {
            const names = {
                thirdpartyCheck: '第三方拦截',
                dynamicIdDetection: '动态ID检测',
                attributeSimilarity: '属性相似度',
                sizeAnomaly: '尺寸异常',
                adAttributeDetection: '广告属性检测',
                iframeAttributeCheck: 'iframe属性',
                parentContainerCheck: '父容器检测',
                nestedFrameDetection: '嵌套框架检测',
                highZIndexDetection: '高z-index',
                fixedPositionCheck: '固定定位',
                overlayDetection: '遮罩层检测',
                floatingLayerCheck: '浮动层检测',
                floatingAdDetection: '浮动广告检测',
                imageAdDetection: '图片广告检测',
                sidebarAdDetection: '侧边栏检测',
                textAdDetection: '文本广告检测',
                cookieSyncDetection: 'Cookie同步检测'
            };
            return names[key] || key;
        }

        static showLogs() {
            const logs = Logger.getDomainLogs();
            alert(logs.length ? 
                `【${DomainConfig.currentDomain}】拦截记录:\n\n${Logger.formatLogs(logs)}` : 
                '当前无拦截记录');
        }

        static clearLogs() {
            Logger.clearDomainLogs();
            GM_notification({title: '日志已清除', timeout: 1500});
        }
    }

    // ======================= 日志系统 =======================
    class Logger {
        static logRemoval(record) {
            const allLogs = GM_getValue('removalLogs', {});
            const domainLogs = allLogs[DomainConfig.currentDomain] || [];
            
            domainLogs.push({
                timestamp: new Date().toLocaleString(),
                ...record
            });

            if (domainLogs.length > CONFIG.maxLogs) domainLogs.shift();
            allLogs[DomainConfig.currentDomain] = domainLogs;
            GM_setValue('removalLogs', allLogs);
        }

        static getDomainLogs() {
            const allLogs = GM_getValue('removalLogs', {});
            return allLogs[DomainConfig.currentDomain] || [];
        }

        static clearDomainLogs() {
            const allLogs = GM_getValue('removalLogs', {});
            delete allLogs[DomainConfig.currentDomain];
            GM_setValue('removalLogs', allLogs);
        }

        static formatLogs(logs) {
            return logs.map((log, index) => 
                `[${index + 1}] ${log.timestamp}\n模块: ${log.module}\n` +
                `类型: ${log.reason.type}\n详情: ${log.reason.detail || ''}`
            ).join('\n\n');
        }
    }

    // ======================= 系统初始化 =======================
    let coreCleaner;

    function initialize() {
        if (coreCleaner) coreCleaner.destructor();
        coreCleaner = new CoreCleaner();
    }

    initialize();
    UIController.init();

    // CSS防护规则
    const antiRevertStyle = document.createElement('style');
    antiRevertStyle.textContent = `
        html::-webkit-scrollbar { width: 0 !important }
        [style*="overflow:hidden"] { overflow: visible !important }
        [data-ad-container] { display: none !important }
    `;
    document.head.appendChild(antiRevertStyle);
})();