广告终结者

广告终结者(移除相关功能)

目前為 2025-02-04 提交的版本,檢視 最新版本

// ==UserScript==
// @name         广告终结者
// @namespace    http://tampermonkey.net/
// @version      2.8
// @description  广告终结者(移除相关功能)
// @author       TMHhz
// @match        *://*/*
// @exclude     *://*.bing.com/*
// @exclude     *://*.iqiyi.com/*
// @exclude     *://*.qq.com/*
// @exclude     *://*.v.qq.com/*
// @exclude     *://*.sohu.com/*
// @exclude     *://*.mgtv.com/*
// @exclude     *://*.ifeng.com/*
// @exclude     *://*.pptv.com/*
// @exclude     *://*.sina.com.cn/*
// @exclude     *://*.56.com/*
// @exclude     *://*.cntv.cn/*
// @exclude     *://*.tudou.com/*
// @exclude     *://*.baofeng.com/*
// @exclude     *://*.le.com/*
// @exclude     *://*.pps.tv/*
// @exclude     *://*.www.fun.tv/*
// @exclude     *://*.baidu.com/*
// @exclude     *://*.ku6.com/*
// @exclude     *://*.tvsou.com/*
// @exclude     *://*.kankan.com/*
// @exclude     *://*.douyu.com/*
// @exclude     *://*.weibo.com/*
// @exclude     *://*.people.com.cn/*
// @exclude     *://*.cctv.com/*
// @exclude     *://*.gdtv.com.cn/*
// @exclude     *://*.ahtv.cn/*
// @exclude     *://*.tvb.com/*
// @exclude     *://*.tvmao.com/*
// @exclude     *://*.douban.com/*
// @exclude     *://*.163.com/*
// @exclude     *://*.bilibili.com/*
// @exclude     *://*.www.gov.cn/*
// @exclude     *://*.thepaper.cn/*
// @exclude     *://*.xinhuanet.com/*
// @exclude     *://*.china.com/*
// @exclude     *://*.guancha.cn/*
// @exclude     *://*.jianshu.com/*
// @exclude     *://*.amazon.cn/*
// @exclude     *://*.cnblogs.com/*
// @exclude     *://*.cnstock.com/*
// @exclude     *://*.baike.com/*
// @exclude     *://*.guokr.com/*
// @exclude     *://*.360doc.com/*
// @exclude     *://*.qiushibaike.com/*
// @exclude     *://*.zol.com.cn/*
// @exclude     *://*.pconline.com.cn/*
// @exclude     *://*.pcpop.com/*
// @exclude     *://*.it168.com/*
// @exclude     *://*.gfan.com/*
// @exclude     *://*.feng.com/*
// @exclude     *://*.xiaomi.cn/*
// @exclude     *://*.10086.cn/*
// @exclude     *://*.10010.com/*
// @license      GPLv3
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_notification
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';

    // ======================= 小说网站UA伪装 =======================
    (function detectNovelSite() {
        const novelKeywords = [
            'novel', 'xiaoshuo', '小说', '阅读', 
            'book', '章节', '文学', '小说网',
            'txt', 'download', '免费小说'
        ];
        
        const isNovelSite = () => {
            const urlCheck = novelKeywords.some(k => 
                window.location.href.toLowerCase().includes(k)
            );
            const titleCheck = novelKeywords.some(k => 
                document.title.toLowerCase().includes(k)
            );
            const metaKeywords = document.querySelector('meta[name="keywords"]')?.content || '';
            const metaDescription = document.querySelector('meta[name="description"]')?.content || '';
            const contentCheck = novelKeywords.some(k => 
                metaKeywords.includes(k) || metaDescription.includes(k)
            );
            return urlCheck || titleCheck || contentCheck;
        };

        if (isNovelSite()) {
            const symbianUA = 'NokiaN8-00/5.0 (Symbian/3; Series60/5.2 Mozilla/5.0; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/533.4 (KHTML, like Gecko) BrowserNG/7.3.1.37';
            Object.defineProperty(window.navigator, 'userAgent', {
                value: symbianUA,
                writable: false,
                configurable: false
            });
        }
    })();

    // ======================= 核心配置 =======================
    const CONFIG = {
        maxLogs: 150,
        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', 
            '偷拍', '黑料', '横幅', '乱伦'
        ],
        protectionRules: {
            dynamicIdLength: 12,
            zIndexThreshold: 50,
            maxFrameDepth: 3,
            textAdKeywords: ['限时优惠', '立即下载', '微信', 'vx:', 'telegram', '偷拍', '黑料']
        },
        defaultSettings: {
            dynamicSystem: true,
            layoutSystem: true,
            frameSystem: true,
            mediaSystem: true,
            textSystem: true,
            thirdPartyBlock: true
        }
    };

    // ======================= 广告工具类 =======================
    class AdUtils {
        static safeRemove(node, module, reason) {
            if (!node?.parentNode || this.isWhitelisted(node)) return false;
            try {
                Logger.logRemoval({
                    module,
                    element: {
                        tag: node.tagName,
                        id: node.id,
                        class: node.className,
                        html: node.outerHTML?.slice(0, 200)
                    },
                    reason
                });
                node.parentNode.removeChild(node);
                return true;
            } catch(e) {
                console.warn('元素移除失败:', e);
                return false;
            }
        }

        static handleScriptContent(script) {
            const content = script.innerHTML.toLowerCase();
            const foundKeywords = CONFIG.adKeywords.filter(k => 
                content.includes(k.toLowerCase().trim())
            );

            if (foundKeywords.length > 0) {
                Logger.logRemoval({
                    module: 'ScriptFilter',
                    element: {
                        tag: script.tagName,
                        id: script.id,
                        class: script.className,
                        html: script.outerHTML.slice(0, 200)
                    },
                    reason: {
                        type: '脚本关键词拦截',
                        detail: `匹配关键词: ${foundKeywords.join(', ')}`
                    }
                });
                script.remove();
                return true;
            }
            return false;
        }

        static isWhitelisted(element) {
            return element.closest('[data-protected]');
        }
    }

    // ======================= 核心拦截系统 =======================
    class CoreSystem {
        constructor() {
            this.observerConfig = {
                childList: true, 
                subtree: true,
                attributeFilter: ['id', 'class', 'style', 'src']
            };
            this.processedElements = new WeakSet();
            this.initObservers();
            this.initialClean();
            this.injectProtectionStyles();
        }

        debounce(func, wait) {
            let timeout;
            return function(...args) {
                clearTimeout(timeout);
                timeout = setTimeout(() => func.apply(this, args), wait);
            };
        }

        initObservers() {
            const processMutations = this.debounce(this.handleMutations.bind(this), 100);
            new MutationObserver(mutations => processMutations(mutations))
                .observe(document, this.observerConfig);
        }

        handleMutations(mutations) {
            const elements = new Set();
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    if (node.nodeType === 1 && !this.processedElements.has(node)) {
                        elements.add(node);
                        this.processedElements.add(node);
                    }
                }
            }
            this.batchProcessElements([...elements]);
        }

        batchProcessElements(elements) {
            if (!elements.length) return;
            
            const BATCH_SIZE = 25;
            for (let i = 0; i < elements.length; i += BATCH_SIZE) {
                const batch = elements.slice(i, i + BATCH_SIZE);
                requestIdleCallback(() => {
                    batch.forEach(el => this.processElement(el));
                }, { timeout: 500 });
            }
        }

        initialClean() {
            this.checkPriorityElements(['script', 'iframe', 'img', 'div']);
            requestIdleCallback(() => this.checkElements('*'), { timeout: 1000 });
        }

        checkPriorityElements(selectors) {
            selectors.forEach(selector => {
                const elements = document.querySelectorAll(selector);
                this.batchProcessElements([...elements]);
            });
        }

        processElement(el) {
            if(Config.get('dynamicSystem')) {
                this.checkDynamicId(el);
                this.checkAdAttributes(el);
            }
            if(Config.get('layoutSystem')) {
                this.checkZIndex(el);
                this.checkFixedPosition(el);
            }
            if(Config.get('mediaSystem')) {
                this.checkImageAds(el);
                this.checkFloatingAds(el);
            }
            if(Config.get('textSystem')) {
                this.checkTextAds(el);
            }
        }

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

        checkAdAttributes(el) {
            ['id', 'class', 'src'].forEach(attr => {
                const val = el.getAttribute(attr) || '';
                if(CONFIG.adKeywords.some(k => val.includes(k))) {
                    AdUtils.safeRemove(el, 'DynamicSystem', {
                        type: '广告属性检测',
                        detail: `${attr}=${val.slice(0, 30)}`
                    });
                }
            });
        }

        checkZIndex(el) {
            const zIndex = parseInt(getComputedStyle(el).zIndex);
            if(zIndex > CONFIG.protectionRules.zIndexThreshold) {
                AdUtils.safeRemove(el, 'LayoutSystem', {
                    type: '高堆叠元素',
                    detail: `z-index=${zIndex}`
                });
            }
        }

        checkFixedPosition(el) {
            const style = getComputedStyle(el);
            if(style.position === 'fixed' && el.offsetWidth < 200) {
                AdUtils.safeRemove(el, 'LayoutSystem', {
                    type: '固定定位元素',
                    detail: `尺寸: ${el.offsetWidth}x${el.offsetHeight}`
                });
            }
        }

        checkImageAds(el) {
            if(el.tagName === 'IMG' && (el.src.includes('ad') || el.src.endsWith('.gif'))) {
                AdUtils.safeRemove(el, 'MediaSystem', {
                    type: '图片广告',
                    detail: `图片源: ${el.src.slice(0, 50)}`
                });
            }
        }

        checkFloatingAds(el) {
            const rect = el.getBoundingClientRect();
            const style = getComputedStyle(el);
            if(['fixed', 'sticky'].includes(style.position) && 
              (rect.top < 10 || rect.bottom > window.innerHeight - 10)) {
                AdUtils.safeRemove(el, 'MediaSystem', {
                    type: '浮动广告',
                    detail: `位置: ${rect.top}px`
                });
            }
        }

        checkTextAds(el) {
            const text = el.textContent?.toLowerCase() || '';
            if (CONFIG.protectionRules.textAdKeywords.some(k => text.includes(k))) {
                AdUtils.safeRemove(el, 'TextSystem', {
                    type: '文本广告',
                    detail: `关键词: ${text.slice(0, 50)}`
                });
            }
        }

        checkIframes() {
            if(!Config.get('frameSystem')) return;
            document.querySelectorAll('iframe').forEach(iframe => {
                let depth = 0, parent = iframe;
                while((parent = parent.parentNode)) {
                    if(parent.tagName === 'IFRAME') depth++;
                }
                if(depth > CONFIG.protectionRules.maxFrameDepth) {
                    AdUtils.safeRemove(iframe, 'FrameSystem', {
                        type: '深层嵌套框架',
                        detail: `嵌套层级: ${depth}`
                    });
                }

                const container = iframe.closest('div, section');
                if(container && !AdUtils.isWhitelisted(container)) {
                    AdUtils.safeRemove(container, 'FrameSystem', {
                        type: '广告容器',
                        detail: 'iframe父容器'
                    });
                }
            });
        }

        checkThirdParty() {
            if(!Config.get('thirdPartyBlock')) return;
            document.querySelectorAll('script, iframe').forEach(el => {
                try {
                    const src = new URL(el.src).hostname;
                    const current = new URL(location.href).hostname;
                    if(!src.endsWith(current)) {
                        AdUtils.safeRemove(el, 'ThirdParty', {
                            type: '第三方资源',
                            detail: `源域: ${src}`
                        });
                    }
                } catch {}
            });
        }

        injectProtectionStyles() {
            GM_addStyle(`
                [style*="fixed"], [style*="sticky"] { 
                    position: static !important;
                    top: auto !important;
                    bottom: auto !important;
                }
                iframe[src*="ad"], .ad-container { 
                    display: none !important;
                    height: 0 !important;
                    width: 0 !important;
                    opacity: 0 !important;
                }
                .ad-shield-protected {
                    border: 2px solid #4CAF50 !important;
                    padding: 5px !important;
                }
            `);
        }

        checkElements(selector, fn) {
            document.querySelectorAll(selector).forEach(fn);
        }
    }

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

        static get allKeys() {
            return Object.keys(CONFIG.defaultSettings);
        }

        static get(key) {
            const data = GM_getValue('config') || {};
            const domainConfig = data[this.currentDomain] || {};
            return domainConfig[key] ?? CONFIG.defaultSettings[key];
        }

        static set(key, value) {
            const data = GM_getValue('config') || {};
            data[this.currentDomain] = {...CONFIG.defaultSettings, ...data[this.currentDomain], [key]: value};
            GM_setValue('config', data);
        }

        static toggleAll(status) {
            const data = GM_getValue('config') || {};
            data[this.currentDomain] = Object.fromEntries(
                Config.allKeys.map(k => [k, status])
            );
            GM_setValue('config', data);
        }
    }

    // ======================= 用户界面控制器 =======================
    class UIController {
        static init() {
            this.registerMainMenu();
            this.registerModuleCommands();
            this.registerUtilityCommands();
        }

        static registerMainMenu() {
            const allEnabled = Config.allKeys.every(k => Config.get(k));
            GM_registerMenuCommand(
                `🔘 主开关 [${allEnabled ? '✅' : '❌'}]`,
                () => this.toggleAllModules(!allEnabled)
            );
        }

        static registerModuleCommands() {
            const modules = [
                ['dynamicSystem', '动态检测系统 (ID/属性)'],
                ['layoutSystem', '布局检测系统 (定位/z-index)'],
                ['frameSystem', '框架过滤系统 (iframe)'],
                ['mediaSystem', '媒体检测系统 (图片/浮动)'],
                ['textSystem', '文本广告检测'],
                ['thirdPartyBlock', '第三方拦截']
            ];

            modules.forEach(([key, name]) => {
                GM_registerMenuCommand(
                    `${name} [${Config.get(key) ? '✅' : '❌'}]`,
                    () => this.toggleModule(key, name)
                );
            });
        }

        static registerUtilityCommands() {
            GM_registerMenuCommand('📜 查看拦截日志', () => this.showLogs());
            GM_registerMenuCommand('🧹 清除当前日志', () => Logger.clear());
            GM_registerMenuCommand('⚙️ 重置所有配置', () => this.resetConfig());
        }

        static toggleModule(key, name) {
            const value = !Config.get(key);
            Config.set(key, value);
            this.showNotification(`${name} ${value ? '✅ 已启用' : '❌ 已禁用'}`);
            setTimeout(() => location.reload(), 500);
        }

        static toggleAllModules(status) {
            Config.toggleAll(status);
            this.showNotification(`所有模块已${status ? '启用' : '禁用'}`);
            setTimeout(() => location.reload(), 500);
        }

        static resetConfig() {
            if (!confirm('确定重置所有配置吗?')) return;
            const data = GM_getValue('config') || {};
            delete data[Config.currentDomain];
            GM_setValue('config', data);
            this.showNotification('配置已重置');
            setTimeout(() => location.reload(), 500);
        }

        static showLogs() {
            const logs = Logger.getLogs();
            alert(logs.length ? 
                `📃 最近${CONFIG.maxLogs}条拦截记录:\n\n${logs.map(l => 
                    `[${l.time}] ${l.module}\n类型: ${l.type}\n元素: ${l.element}`
                ).join('\n\n')}` : 
                '暂无拦截记录'
            );
        }

        static showNotification(text, duration = 2000) {
            GM_notification({
                title: '广告终结者',
                text: text,
                silent: true,
                timeout: duration
            });
        }
    }

    // ======================= 日志系统 =======================
    class Logger {
        static logRemoval(data) {
            const logs = GM_getValue('logs', []);
            logs.push({
                time: new Date().toLocaleTimeString(),
                module: data.module,
                type: data.reason.type,
                detail: data.reason.detail,
                element: `${data.element.tag}#${data.element.id}`
            });
            GM_setValue('logs', logs.slice(-CONFIG.maxLogs));
        }

        static getLogs() {
            return GM_getValue('logs', []);
        }

        static clear() {
            GM_setValue('logs', []);
            UIController.showNotification('日志已清空');
        }
    }

    // ======================= 初始化入口 =======================
    (function init() {
        new CoreSystem();
        UIController.init();
        console.log('✅ 广告拦截系统已激活 - 当前域名:', location.hostname);
    })();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址