2025 YouTube及全站广告屏蔽脚本

根据2025年油管及其他网站广告更新的屏蔽脚本,屏蔽YouTube广告及全站广告。请谨慎使用,风险自负。

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

// ==UserScript==
// @name         2025 YouTube及全站广告屏蔽脚本
// @version      1.0
// @description  根据2025年油管及其他网站广告更新的屏蔽脚本,屏蔽YouTube广告及全站广告。请谨慎使用,风险自负。
// @author       YourName
// @match        *://*/*
// @grant        none
// @run-at       document-end
// @namespace https://greasyfork.org/users/1443996
// ==/UserScript==

(function() {
    'use strict';

    // 定义广告元素选择器
    const adSelectors = [
        // YouTube 专用选择器(优先级高)
        'ytd-display-ad-renderer',
        '.video-ads',
        '.ytp-ad-module',
        '.ytp-ad-overlay-container',
        'ytd-promoted-sparkles-web-renderer',
        // 通用广告选择器
        '[id*="ad_"]',
        '[class*="ad-"]',
        '[class*="ads-"]',
        '[class*="advert"]',
        'iframe[src*="ad"]',
        'iframe[src*="adservice"]'
    ];

    // 防抖函数:确保在短时间内多次调用时仅执行一次
    function debounce(func, delay) {
        let timeoutId;
        return (...args) => {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => func.apply(this, args), delay);
        };
    }

    // 处理单个元素及其 Shadow DOM 内的广告
    function removeAdsInElement(element) {
        // 检查元素本身是否匹配广告选择器
        adSelectors.forEach(selector => {
            if (element.matches(selector)) {
                element.remove();
                console.log('[AdBlocker] 移除元素:', element);
            }
        });
        // 检查并处理 Shadow DOM
        if (element.shadowRoot) {
            adSelectors.forEach(selector => {
                const shadowElements = element.shadowRoot.querySelectorAll(selector);
                shadowElements.forEach(el => {
                    el.remove();
                    console.log('[AdBlocker] 移除 Shadow DOM 内元素:', el);
                });
            });
        }
        // 处理子元素
        adSelectors.forEach(selector => {
            const elements = element.querySelectorAll(selector);
            elements.forEach(el => {
                el.remove();
                console.log('[AdBlocker] 移除子元素:', el);
            });
        });
    }

    // 优化后的广告移除逻辑:全局扫描
    const removeAds = debounce(() => {
        adSelectors.forEach(selector => {
            document.querySelectorAll(selector).forEach(el => {
                el.remove();
                console.log('[AdBlocker] 全文档移除:', el);
            });
        });
    }, 100);

    // MutationObserver:仅处理新增节点
    const observer = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    removeAdsInElement(node);
                }
            });
        });
        // 防抖处理可能遗漏的情况
        removeAds();
    });

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

    // 页面加载完成后执行广告移除
    window.addEventListener('load', () => {
        removeAds();
        // 针对延迟加载的内容(如 SPA)
        setTimeout(removeAds, 2000);
    });

    // 处理单页应用(SPA)的 URL 变化
    let lastUrl = location.href;
    const urlObserver = new MutationObserver(() => {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            console.log('[AdBlocker] URL 变化检测:', lastUrl);
            // 延时执行以确保新内容加载完毕
            setTimeout(removeAds, 1500);
        }
    });
    urlObserver.observe(document, { subtree: true, childList: true });

    // 保守的定时器作为备用方案
    setInterval(removeAds, 10000);
})();