Greasy Fork

Greasy Fork is available in English.

RafBlocker

Attempts to block various YouTube ads (pre-roll, mid-roll, banners) and automatically skip segments, while trying to prevent playlist skipping errors.

当前为 2025-10-23 提交的版本,查看 最新版本

// ==UserScript==
// @name         RafBlocker
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Attempts to block various YouTube ads (pre-roll, mid-roll, banners) and automatically skip segments, while trying to prevent playlist skipping errors.
// @author       Raf
// @match        *://www.youtube.com/*
// @grant        none
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

/*
 * MIT License
 *
 * Copyright (c) 2025 Raf (or your chosen name)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

(function() {
    'use strict';

    // --- Configuration ---
    // The key selectors for ad elements on YouTube often change.
    // These are common selectors, but may become outdated.
    const AD_CONTAINER_SELECTOR = '.ad-container'; // Common pre/mid-roll ad container
    const VIDEO_AD_SELECTOR = '.video-ads, .ytp-ad-module'; // Video ad elements
    const SKIP_BUTTON_SELECTOR = '.ytp-ad-skip-button, .ytp-skip-ad-button'; // The skip ad button
    const AD_OVERLAY_SELECTOR = '.ytp-player-content-container .ytp-ce-element, .ytp-ad-overlay-container, .ytp-ad-image-overlay'; // Overlays and banners

    // Function to remove elements from the DOM
    function removeElement(selector) {
        document.querySelectorAll(selector).forEach(element => {
            if (element) {
                element.remove();
                // console.log(`RafBlocker: Removed ad element: ${selector}`);
            }
        });
    }

    // Function to skip the video ad
    function skipVideoAd() {
        const skipButton = document.querySelector(SKIP_BUTTON_SELECTOR);
        if (skipButton) {
            skipButton.click();
            // console.log('RafBlocker: Clicked skip button.');
            return true;
        }

        const videoPlayer = document.querySelector('video');
        if (videoPlayer && document.querySelector('.ad-showing')) {
            // Attempt to force the video to the end if an ad is showing and no skip button is present
            // This is a common method for non-skippable ads.
            videoPlayer.currentTime = videoPlayer.duration;
            // console.log('RafBlocker: Forced video to end to skip non-skippable ad.');
            return true;
        }

        return false;
    }

    // Main blocking logic
    function blockAds() {
        // 1. Remove video ad and banner containers
        removeElement(AD_CONTAINER_SELECTOR);
        removeElement(VIDEO_AD_SELECTOR);
        removeElement(AD_OVERLAY_SELECTOR);

        // 2. Try to click the skip ad button
        skipVideoAd();

        // 3. (EXPERIMENTAL) Hide any remaining potential ad/sponsor elements using CSS
        // This is a fallback and can sometimes break the layout.
        const style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = `
            ${AD_CONTAINER_SELECTOR}, ${VIDEO_AD_SELECTOR}, ${AD_OVERLAY_SELECTOR},
            ytd-promoted-sparkles-text-search-renderer, ytd-promoted-video-renderer, ytd-ad-slot-renderer,
            .ytp-ad-progress-bar-container, .ytp-ad-text {
                display: none !important;
                visibility: hidden !important;
            }
        `;
        document.head.appendChild(style);
    }

    // Use a MutationObserver to watch for changes in the DOM, like ads being loaded dynamically.
    const observer = new MutationObserver((mutations, obs) => {
        // Only run the blocking logic if YouTube is open and we're on a video page (optional optimization)
        if (window.location.pathname.startsWith('/watch')) {
            blockAds();
        }
    });

    // Start observing the body for configuration changes and subtree modifications
    observer.observe(document.body, { childList: true, subtree: true });

    // Also run blockAds on an interval for a quick check, especially useful for initial load and overlays
    setInterval(blockAds, 500); // Check every 500 milliseconds

})();