Greasy Fork

Greasy Fork is available in English.

智能全站广告拦截器 (安全兼容版)

精准广告拦截,保护搜索引擎核心元素,支持现代Web框架

目前为 2025-03-11 提交的版本。查看 最新版本

// ==UserScript==
// @name        智能全站广告拦截器 (安全兼容版)
// @version     2.0
// @description 精准广告拦截,保护搜索引擎核心元素,支持现代Web框架
// @author      little fool
// @match       *://*/*
// @grant       unsafeWindow
// @run-at      document-start
// @namespace   https://yournamespace.com
// @license     MIT
// ==/UserScript==

(function() {
    'use strict';

    // 安全配置中心
    const SecurityConfig = {
        // 关键域名白名单
        protectedDomains: {
            'baidu.com': {
                selectors: [
                    '#kw', '#form', '.s_ipt', 
                    '.s_btn', '.bdsug', '.s_form_wrapper',
                    '.bdlayer', '[name="wd"]'
                ],
                containers: ['#form', '.s_form_wrapper']
            },
            'google.com': {
                selectors: [
                    'input[name="q"]', 
                    '.gLFyf', 
                    '[aria-label="搜索"]',
                    '.UUbT9'  // 搜索建议框
                ],
                containers: ['#searchform']
            }
        },

        // 通用广告特征
        adPatterns: {
            selectors: [
                // 通用广告选择器 (带精确排除)
                'div[data-ad]:not([data-adtype="content"])',
                'iframe[src*="/ad/"]:not([src*="/adapter/"])',
                '[class*="ad-"]:not(.admin):not(.adaptive)',
                '[id^="ad-"]:not([id^="admin-"])',
                
                // YouTube专用
                'ytd-display-ad-renderer',
                '#player-ads',
                '.ytp-ad-module',
                'ytd-promoted-sparkles-web-renderer'
            ],
            urlPatterns: [
                /\/ad[s]?\//i,
                /doubleclick\.net/i,
                /adservice\.google/i,
                /adsystem\.com/i,
                /adserver\.+/i
            ]
        }
    };

    // 智能防护系统
    class AdBlocker {
        constructor() {
            this.currentDomain = window.location.hostname;
            this.protectedRules = this.getDomainProtection();
            this.scanThrottle = this.createThrottle(500);
            this.init();
        }

        // 初始化核心模块
        init() {
            this.setupNetworkInterceptor();
            this.setupDOMObserver();
            this.setupSPAWatch();
            this.safeScan();
            this.antiDetection();
        }

        // 获取当前域名保护规则
        getDomainProtection() {
            for (const domain in SecurityConfig.protectedDomains) {
                if (this.currentDomain.includes(domain)) {
                    return SecurityConfig.protectedDomains[domain];
                }
            }
            return null;
        }

        // 创建节流函数
        createThrottle(delay) {
            let lastExec = 0;
            return (fn) => {
                const now = Date.now();
                if (now - lastExec >= delay) {
                    fn();
                    lastExec = now;
                }
            };
        }

        // DOM安全扫描
        safeScan(root = document) {
            try {
                // 步骤1:扫描可见广告
                this.scanElements(root);

                // 步骤2:处理Shadow DOM
                this.scanShadowDOM(root);

                // 步骤3:处理iframe内容
                this.scanIframes(root);

                // 步骤4:特殊域名保护
                if (this.protectedRules) {
                    this.protectElements(root);
                }
            } catch (e) {
                console.warn('[AdBlocker] 扫描异常:', e);
            }
        }

        // 元素扫描核心
        scanElements(root) {
            const adSelectors = SecurityConfig.adPatterns.selectors.join(', ');
            root.querySelectorAll(adSelectors).forEach(el => {
                if (!this.isProtected(el)) {
                    this.removeElement(el);
                }
            });
        }

        // Shadow DOM处理
        scanShadowDOM(root) {
            const scanNode = (node) => {
                if (node.shadowRoot) {
                    this.safeScan(node.shadowRoot);
                    node.shadowRoot.querySelectorAll('*').forEach(scanNode);
                }
            };
            root.querySelectorAll('*').forEach(scanNode);
        }

        // iframe处理
        scanIframes(root) {
            root.querySelectorAll('iframe').forEach(frame => {
                try {
                    const frameDoc = frame.contentDocument || frame.contentWindow?.document;
                    if (frameDoc) this.safeScan(frameDoc);
                } catch (e) {
                    // 跨域安全限制
                }
            });
        }

        // 保护关键元素
        protectElements(root) {
            this.protectedRules.selectors.forEach(selector => {
                root.querySelectorAll(selector).forEach(el => {
                    el.style.cssText += 'important;';
                });
            });
        }

        // 元素移除安全验证
        removeElement(el) {
            try {
                if (el && el.parentNode && !this.isProtected(el)) {
                    el.parentNode.removeChild(el);
                }
            } catch (e) {
                console.warn('[AdBlocker] 元素移除失败:', e);
            }
        }

        // 保护元素检测
        isProtected(el) {
            if (!this.protectedRules) return false;
            return (
                this.protectedRules.selectors.some(s => el.matches(s)) ||
                this.protectedRules.containers.some(c => el.closest(c))
            );
        }

        // 网络请求拦截
        setupNetworkInterceptor() {
            // Fetch拦截
            const originalFetch = window.fetch;
            window.fetch = async (input, init) => {
                const url = typeof input === 'string' ? input : input.url;
                if (this.isAdRequest(url)) {
                    console.log('[AdBlocker] 拦截请求:', url);
                    return new Response(null, { status: 403 });
                }
                return originalFetch(input, init);
            };

            // XHR拦截
            const originalOpen = XMLHttpRequest.prototype.open;
            XMLHttpRequest.prototype.open = function(method, url) {
                this._url = url;
                return originalOpen.apply(this, arguments);
            };

            XMLHttpRequest.prototype.send = function(...args) {
                if (this._url && this.isAdRequest(this._url)) {
                    console.log('[AdBlocker] 拦截XHR:', this._url);
                    this.abort();
                    return;
                }
                return XMLHttpRequest.prototype.send.apply(this, args);
            };
        }

        // 广告请求检测
        isAdRequest(url) {
            return SecurityConfig.adPatterns.urlPatterns.some(p => p.test(url));
        }

        // DOM动态监控
        setupDOMObserver() {
            new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === 1) this.scanThrottle(() => this.safeScan(node));
                    });
                });
                this.scanThrottle(() => this.safeScan());
            }).observe(document, {
                childList: true,
                subtree: true,
                attributes: false
            });
        }

        // SPA路由监控
        setupSPAWatch() {
            let lastURL = location.href;
            new MutationObserver(() => {
                if (location.href !== lastURL) {
                    lastURL = location.href;
                    setTimeout(() => this.safeScan(), 800);
                }
            }).observe(document, { 
                subtree: true,
                childList: true 
            });
        }

        // 反检测机制
        antiDetection() {
            Object.defineProperties(window, {
                fetch: { configurable: false, writable: false },
                XMLHttpRequest: { configurable: false }
            });
        }
    }

    // 启动广告拦截
    new AdBlocker();

})();