Greasy Fork

Greasy Fork is available in English.

硬核YouTube广告拦截器Pro

无API依赖的极简高效广告拦截方案

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

// ==UserScript==
// @name        硬核YouTube广告拦截器Pro
// @version     3.2.0
// @icon        https://www.youtube.com/favicon.ico
// @author      little fool
// @match       *://*.youtube.com/*
// @grant       none
// @run-at      document-start
// @namespace   https://direct.blocker
// @description 无API依赖的极简高效广告拦截方案
// ==/UserScript==

(function() {
    'use strict';

    // 增强版广告特征库
    const AD_SIGNATURES = {
        dom: [
            'ytd-ad-', 'ytm-ad-', 
            '[id*="-ad-"]', '[class*="-ad-"]',
            '#player-ads', '.ytp-ad-',
            '[aria-label*="广告"i]', // 不区分大小写
            'ytd-promoted-', 'ytd-companion-ad',
            'div[data-ad-target]', 'ytd-rich-section-renderer' // 新版信息流广告
        ],
        network: [
            /\/ad(s|server|vert)/i,
            /(doubleclick|googleads|googlesyndication)\./i,
            /\/pagead\//i,
            /\/log_event\?.*\bad_/i,
            /\/get_(midroll|preroll)_/i,
            /\/ptracking\?/i, // 广告追踪参数
            /\/get_video_ad/i
        ]
    };

    // 高效DOM清理系统
    const domHunter = {
        observer: null,
        scan() {
            // 初始化立即清理
            this.clean(document.documentElement);
            
            // 智能扫描间隔(动态调整)
            let scanInterval = 3000;
            const scanner = setInterval(() => {
                this.clean(document.documentElement);
                scanInterval = Math.min(10000, scanInterval + 500);
            }, scanInterval);

            // 优化版MutationObserver
            this.observer = new MutationObserver(muts => {
                scanInterval = 1500; // 检测到变动时加快扫描
                muts.forEach(mut => {
                    [...mut.addedNodes].forEach(node => {
                        if(node.nodeType === 1) this.clean(node);
                    });
                });
            });

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

        clean(root) {
            // 批量选择器查询
            const selector = AD_SIGNATURES.dom.join(',');
            root.querySelectorAll(selector).forEach(ad => {
                // 彻底移除元素及关联数据
                ad.remove();
                this.cleanAdResidue(ad);
            });
            this.fixLayout();
        },

        cleanAdResidue(ad) {
            // 处理广告占位元素
            const parent = ad.parentElement;
            if(parent && parent.childElementCount === 0) {
                parent.remove();
            }
        },

        fixLayout() {
            // 视频播放器修复(节流版)
            const now = Date.now();
            if(now - this.lastFix > 1000) {
                const player = document.querySelector('#movie_player, .html5-video-player');
                if(player) {
                    player.style.cssText = 'height:100vh !important; width:100% !important;';
                }
                this.lastFix = now;
            }
        },
        lastFix: 0
    };

    // 增强版网络拦截
    const networkInterceptor = {
        init() {
            this.hijackFetch();
            this.hijackXHR();
            this.hijackWebSocket();
        },

        hijackFetch() {
            const nativeFetch = window.fetch;
            window.fetch = (input, init) => {
                const url = input.url || input.toString();
                return this.isAdRequest(url) 
                    ? this.blockResponse() 
                    : nativeFetch(input, init);
            };
        },

        hijackXHR() {
            const nativeOpen = XMLHttpRequest.prototype.open;
            XMLHttpRequest.prototype.open = function(_, url) {
                this._url = url;
                nativeOpen.apply(this, arguments);
            };

            const nativeSend = XMLHttpRequest.prototype.send;
            XMLHttpRequest.prototype.send = function() {
                this.isAdRequest() ? this.abort() : nativeSend.apply(this, arguments);
            };

            XMLHttpRequest.prototype.isAdRequest = function() {
                return networkInterceptor.isAdRequest(this._url);
            };
        },

        hijackWebSocket() {
            const nativeWS = WebSocket;
            WebSocket = class extends nativeWS {
                constructor(url) {
                    networkInterceptor.isAdRequest(url) 
                        ? super('ws://localhost') // 重定向到无效地址
                        : super(url);
                }
            };
        },

        isAdRequest(url) {
            return AD_SIGNATURES.network.some(regex => regex.test(url));
        },

        blockResponse() {
            return new Response(null, { 
                status: 403, 
                headers: { 'Blocked-By': 'AdBlockerPro' }
            });
        }
    };

    // 即时样式注入
    const style = document.createElement('style');
    style.textContent = `
        ${AD_SIGNATURES.dom.join(',')} {
            display: none !important;
            height: 0 !important;
            opacity: 0 !important;
            pointer-events: none !important;
            margin: 0 !important;
            padding: 0 !important;
        }
        #movie_player, .html5-video-player {
            height: 100vh !important;
            width: 100% !important;
        }
        .ytp-ad-progress,
        .ytp-ad-skip-button {
            display: none !important;
        }
        ytd-rich-section-renderer {
            min-height: 0 !important;
        }
    `;
    document.head.appendChild(style);

    // 初始化
    domHunter.scan();
    networkInterceptor.init();

})();