Greasy Fork

Greasy Fork is available in English.

YouTube广告拦截器

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

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

// ==UserScript==
// @name        YouTube广告拦截器
// @namespace   safe-adblock
// @version    4.1
// @match       *://*.youtube.com/*
// @grant       none
// @run-at      document-start
// @description 无API依赖的极简高效广告拦截方案
// ==/UserScript==

(function() {
    'use strict';

    // 安全元素选择器(排除播放器相关元素)
    const AD_SELECTORS = [
        'ytd-ad-slot-renderer',
        'div.ytd-promoted-sparkles-web-renderer',
        '[data-ad-metadata]',
        'div#player-ads.ytd-watch:not(#movie_player)',
        'ytd-rich-section-renderer:has(ytd-ad-)',
        'div[class*="-ad-"]:not([data-legitimate])',
        'div.ytp-ad-module'
    ];

    // 智能CSS注入系统
    const initLayout = () => {
        const style = document.createElement('style');
        style.textContent = `
            /* 广告隐藏规则 */
            ${AD_SELECTORS.join(',')} {
                transform: scale(0) !important;
                height: 0 !important;
                width: 0 !important;
                opacity: 0 !important;
                pointer-events: none !important;
                position: absolute !important;
                z-index: -1 !important;
            }

            /* 播放器核心保护规则 */
            #movie_player, .html5-video-player {
                position: static !important;
                width: 100% !important;
                height: 0 !important;
                padding-bottom: 56.25% !important; /* 16:9比例 */
                min-height: auto !important;
                overflow: visible !important;
            }

            /* 视频自适应容器 */
            .html5-video-container {
                position: absolute !important;
                top: 0 !important;
                left: 0 !important;
                width: 100% !important;
                height: 100% !important;
            }

            /* 修复全屏显示 */
            .ytp-fullscreen #movie_player {
                padding-bottom: 0 !important;
                height: 100vh !important;
            }

            /* 防止推荐栏重叠 */
            ytd-watch-flexy[theater] #secondary.ytd-watch-flexy {
                margin-top: 60px !important;
                z-index: 500 !important;
            }
        `;
        document.head.appendChild(style);
    };

    // 播放器守护系统
    const playerProtector = {
        lastHeight: 0,
        observer: null,

        init() {
            this.setupSizeWatcher();
            this.patchFullscreenAPI();
        },

        setupSizeWatcher() {
            this.observer = new ResizeObserver(entries => {
                entries.forEach(entry => {
                    const video = entry.target.querySelector('video');
                    if (video) {
                        this.adjustVideoSize(video);
                    }
                });
            });

            const checkPlayer = () => {
                const player = document.getElementById('movie_player');
                if (player) {
                    this.observer.observe(player);
                    this.adjustVideoSize(player.querySelector('video'));
                }
            };
            checkPlayer();
            setInterval(checkPlayer, 3000);
        },

        adjustVideoSize(video) {
            if (!video) return;
            const container = video.closest('.html5-video-container');
            if (container) {
                container.style.cssText = `
                    width: 100% !important;
                    height: 100% !important;
                    overflow: hidden !important;
                `;
            }
            video.style.cssText = `
                width: 100% !important;
                height: 100% !important;
                object-fit: contain !important;
            `;
        },

        patchFullscreenAPI() {
            const originalRequest = Element.prototype.requestFullscreen;
            Element.prototype.requestFullscreen = function() {
                const player = document.getElementById('movie_player');
                if (player && player.contains(this)) {
                    player.style.paddingBottom = '0';
                    player.style.height = '100vh';
                }
                return originalRequest.apply(this, arguments);
            };
        }
    };

    // 初始化系统
    initLayout();
    playerProtector.init();

    // 安全广告清理系统(原有功能保持)
    const adCleaner = {
        observer: new MutationObserver(muts => {
            muts.forEach(mut => {
                mut.addedNodes.forEach(node => {
                    if (node.nodeType === 1) this.cleanAds(node);
                });
            });
        }),
        cleanAds(root) {
            AD_SELECTORS.forEach(selector => {
                root.querySelectorAll(selector).forEach(ad => {
                    ad.replaceChildren();
                    ad.style.cssText = 'display:none!important';
                });
            });
        }
    };
    adCleaner.observer.observe(document, {
        childList: true,
        subtree: true
    });

})();