YouTube Ad-Bypass

YouTube 広告をスキップして非表示にします (YouTube kōkoku o sukippu shite hihyōji ni shimasu)

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name              YouTube Ad-Bypass
// @namespace         YouTube_Ad-Bypass_Fckoff
// @version           1.22
// @description:en    Skips and hides YouTube and YouTube Music ads
// @description:es    Salta y oculta anuncios de YouTube y YouTube Music
// @description:pt    Pula e oculta anuncios do YouTube & YouTube Music
// @description:fr    Passe et masque las publicités YouTube & YouTube Music
// @description:it    Salta e nasconde gli annunci di YouTube & YouTube Music
// @description:de    Überspringe und verberge YouTube-Werbung
// @description:hi    यूट्यूब विज्ञापनों को छोड़ें और छुपाएं (YouTube vigyapanon ko chhodein aur chhupayein)
// @description:zh-CN 跳过并 column 隐藏 YouTube 广告 (Tiàoguò bìng yǐncáng YouTube guǎnggào)
// @description:ja    YouTube 広告をスキップして非表示にします (YouTube kōkoku o sukippu shite hihyōji ni shimasu)
// @description:ru    Пропускает и скрывает рекламу на YouTube.
// @author            WakeUpNeo
// @match             *://www.youtube.com/*
// @match             *://music.youtube.com/*
// @run-at            document-start
// @grant             none
// @license           MIT
// @description Salta y oculta anuncios de YouTube
// ==/UserScript==

(function() {
    'use strict';

    /**
     * Configuration object containing CSS selectors for different types of ad elements.
     */
    const SELECTORS = {
        // Elements that should be visually hidden from the UI
        toHide: [
            '.ytp-ad-message-container',
            'ytd-player-legacy-desktop-watch-ads-renderer',
            'ytd-ad-slot-renderer',
            '#masthead-ad',
            'tp-yt-paper-dialog:has(#feedback.ytd-enforcement-message-view-model)',
            '.yt-mealbar-promo-renderer',
            '.video-ads',
            '.ytp-ad-module',
            '.ytp-ad-player-overlay',
            '.ad-showing > video',
            '.ad-interrupting > video',
            'div:has(> div#banner)',
            'ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]',
            'ytd-rich-item-renderer:has(ytd-ad-slot-renderer)',
            'ytmusic-mealbar-promo-renderer',
            'ytd-in-feed-ad-layout-renderer',
            '#player-ads',
            '.ytd-video-masthead-ad-v3-renderer',
            'ytd-ad-selection-preview-renderer',
            '.ytp-ad-image-overlay',
            '#root.yt-chips-search-renderer-header-v2'
        ],
        // Selectors for the main YouTube video player container
        player: [
            '#movie_player',
            '.html5-video-player'
        ],
        // Classes added by YouTube when an ad is active
        adsClasses: [
            '.ad-showing',
            '.ad-interrupting',
            '.ytp-ad-player-overlay'
        ],
        // Selectors for the various "Skip Ad" buttons
        skipButtons: [
            '.ytp-ad-skip-button-modern',
            '.ytp-skip-ad-button',
            '.ytp-ad-skip-button',
            '.ytp-ad-skip-button-slot',
            '.ytp-ad-skip-button-container'
        ]
    };

    /**
     * Convert arrays of selectors into single comma-separated strings for querySelectorAll/matches usage.
     */
    const selectors = Object.fromEntries(
       Object.entries(SELECTORS).map(([key, value]) => [key, value.join(', ')])
    );

    let playerObserver = null;
    let video = null;

    /**
     * Injects a global <style> tag to hide ad-related elements using CSS.
     * Uses visibility:hidden and 1px size to avoid breaking layout while making ads invisible.
     */
    const injectStyles = () => {
        const style = document.createElement('style');
        style.textContent = `
            ${selectors.toHide} {
                display: flex !important;
                visibility: hidden !important;
                opacity: 0 !important;
                pointer-events: none !important;
                height: 1px !important;
                width: 1px !important;
                overflow: hidden !important;
            }
        `;
        (document.head || document.documentElement).appendChild(style);
    };

    /**
     * Executes the skipping logic: fast-forwards the video to the end and clicks the skip button.
     */
    const skipAction = () => {
        if (video) {
            if (video.paused) video.play();
            video.muted = true; // Mute to avoid sudden loud ad audio
            video.playbackRate = 16; // Set max speed to fly through the ad
            if (isFinite(video.duration)  && video.duration > 0) {
                // Jump to the very end of the ad segment
                video.currentTime = video.duration - 0.1;
            }
        }
        // Attempt to find and click any available "Skip" button
        const btn = document.querySelector(selectors.skipButtons);
        if (btn) btn.click();
    };

    /**
     * Checks if the player is currently showing an ad.
     * @param {HTMLElement} target - The player element to check for ad-related classes.
     */
    const checkAndSkip = (target) => {
       // Re-fetch the video element if it's missing or disconnected from DOM
       if (!video || !video.isConnected) {
            video = document.querySelector('video');
        }
        if (!video) return;

        // If player has ad-related classes, trigger skip; otherwise, reset playback speed
        if (target.matches(selectors.adsClasses)) {
            skipAction();
        } else {
            // Restore normal speed if the script had previously accelerated it
            if (video.playbackRate > 2) video.playbackRate = 1;
        }
    };

    /**
     * Initializes a MutationObserver to watch for changes in the player's class attribute.
     * This allows the script to react instantly when an ad starts.
     */
    const setupPlayerObserver = () => {
        const player = document.querySelector(selectors.player);

        if (player && !playerObserver) {
            playerObserver = new MutationObserver(() => checkAndSkip(player));
            // Monitor class changes which indicate ad transitions
            playerObserver.observe(player, { attributes: true, attributeFilter: ['class'] });

            // Run initial check
            checkAndSkip(player);
        }
    };

    // Event listeners to handle page loads and YouTube's internal navigation (SPA)
    window.addEventListener('load', setupPlayerObserver);
    window.addEventListener('yt-navigate-finish', setupPlayerObserver);

    // Inject CSS as soon as the DOM structure is available
    window.addEventListener('DOMContentLoaded', (event) => {
        injectStyles();
    });

    /**
     * Fallback mechanism: attempts to initialize the observer every 250ms 
     * in case 'load' events fire before the player is ready.
     */
    let retry = 0;
    const fallback = setInterval(() => {
        setupPlayerObserver();
        // Stop retrying if observer is active or after 10 failed attempts
        if (playerObserver || retry > 10) clearInterval(fallback);
        retry++;
    }, 250);

})();