Greasy Fork

Greasy Fork is available in English.

RafBlocker

Aggressively blocks YouTube ads and attempts to suppress the AdBlock warning by forcing the player state and instantly hiding the modal.

// ==UserScript==
// @name         RafBlocker
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Aggressively blocks YouTube ads and attempts to suppress the AdBlock warning by forcing the player state and instantly hiding the modal.
// @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 and Selectors ---
    const AD_CONTAINER_SELECTOR = '.ad-container, .video-ads, .ytp-ad-module';
    const SKIP_BUTTON_SELECTOR = '.ytp-ad-skip-button, .ytp-skip-ad-button';
    const AD_OVERLAY_SELECTOR = '.ytp-player-content-container .ytp-ce-element, .ytp-ad-overlay-container, .ytp-ad-image-overlay';

    // Aggressive selectors for the warning modal and backdrop
    const WARNING_MODAL_SELECTOR = 'ytd-popup-container, #popup, .yt-spec-general-modal, tp-yt-paper-dialog';
    const DISMISS_BUTTON_SELECTOR = 'ytd-button-renderer button.ytd-popup-container, ytd-button-renderer button.yt-spec-general-modal';

    // --- Core Functions ---

    // Function to remove elements from the DOM
    function removeElement(selector) {
        document.querySelectorAll(selector).forEach(element => {
            if (element) {
                element.remove();
            }
        });
    }

    // Function to skip the video ad (works on pre-roll/mid-roll)
    function skipVideoAd() {
        const skipButton = document.querySelector(SKIP_BUTTON_SELECTOR);
        if (skipButton) {
            skipButton.click();
            return true;
        }

        const videoPlayer = document.querySelector('video');
        const adShowing = document.querySelector('.ad-showing');

        // Check if an ad is clearly marked as playing and try to jump to the end
        if (videoPlayer && adShowing) {
            videoPlayer.currentTime = videoPlayer.duration;
            return true;
        }

        return false;
    }

    // --- Ad Block Warning Evasion (The Core Fix) ---
    function evadeAdDetection() {
        // 1. Aggressively Hide the Modal and Backdrop via CSS
        let style = document.getElementById('RafBlockerStyle');
        if (!style) {
            style = document.createElement('style');
            style.id = 'RafBlockerStyle';
            style.type = 'text/css';
            document.head.appendChild(style);
        }

        // Keep the modal hidden and restore scrolling
        style.innerHTML = `
            ${WARNING_MODAL_SELECTOR} {
                display: none !important;
                visibility: hidden !important;
            }
            body {
                overflow: auto !important;
            }
        `;

        // 2. Click any hidden dismiss buttons just in case
        document.querySelectorAll(DISMISS_BUTTON_SELECTOR).forEach(button => {
            if (button.innerText.toUpperCase().includes('DISMISS') || button.innerText.toUpperCase().includes('CLOSE')) {
                button.click();
            }
        });

        // 3. Forcing Player State (Most important part for persistent warnings)
        // This attempts to trick YouTube's internal ad-check functions.
        if (window.ytplayer) {
            // Force the player to believe the ad has timed out or is already skipped
            if (window.ytplayer.config.args) {
                window.ytplayer.config.args.advideo = 0; // Standard ad flag
                window.ytplayer.config.args.is_ad = false; // Is Ad flag
                window.ytplayer.config.args.ad_flags = 0; // Ad flags
            }

            // Also check for the global Player object (if available)
            const player = document.querySelector('#movie_player');
            if (player && player.getPlayerState) {
                // If the player is paused (state 2) due to the warning, try to play it (state 1 is playing)
                if (player.getPlayerState() === 2) {
                    player.playVideo();
                }
            }
        }
    }

    // --- Main Blocking Loop ---
    function blockAdsAndWarning() {
        // Always run evasion first to catch the warning instantly
        evadeAdDetection();

        // Standard ad removal
        removeElement(AD_CONTAINER_SELECTOR);
        removeElement(AD_OVERLAY_SELECTOR);

        // Attempt to skip the video ad
        skipVideoAd();
    }

    // Use a MutationObserver for dynamic content loading
    const observer = new MutationObserver((mutations, obs) => {
        // Only run the logic if we're on a YouTube page
        blockAdsAndWarning();
    });

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

    // Also run blockAdsAndWarning on a rapid interval for aggressive ad/warning removal
    setInterval(blockAdsAndWarning, 100); // Check every 100 milliseconds for maximum speed

})();