Yes BlockTheAds

Kiss the annoying youtube ads goodbye!

// ==UserScript==
// @name         Yes BlockTheAds
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  Kiss the annoying youtube ads goodbye!
// @author       elliottophellia
// @license      GPL-3.0
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @homepageURL  https://github.com/elliottophellia/yesblocktheads
// @supportURL   https://github.com/elliottophellia/yesblocktheads/issues
// @match        *://*.youtube.com/*
// @exclude      *://accounts.youtube.com/*
// @exclude      *://www.youtube.com/live_chat_replay*
// @exclude      *://www.youtube.com/persist_identity*
// @run-at       document-idle
// @compatible   chrome
// @compatible   firefox
// @compatible   opera
// @compatible   edge
// ==/UserScript==

(async () => {
    'use strict';

    const tag = '[Yes BlockTheAds]';
    const adSelectors = [
        '#masthead-ad', '.video-ads.ytp-ad-module', 'ytd-ad-slot-renderer',
        'ytd-rich-item-renderer.style-scope.ytd-rich-grid-row #content:has(.ytd-display-ad-renderer)',
        'tp-yt-paper-dialog:has(yt-mealbar-promo-renderer)', 'yt-mealbar-promo-renderer',
        'ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]',
        '#related #player-ads', '#related ytd-ad-slot-renderer',
        'ytd-popup-container:has(a[href="/premium"])', 'ad-slot-renderer',
        'ytm-companion-ad-renderer'
    ];

    const log = (message) => console.log(`${tag}[${getTimestamp()}] ${message}`);
    const debug = (message) => console.debug(`${tag}[${getTimestamp()}] ${message}`);

    const asDoubleDigit = value => value < 10 ? `0${value}` : value;
    
    const getTimestamp = () => {
        const dt = new Date();
        return `${asDoubleDigit(dt.getHours())}:${asDoubleDigit(dt.getMinutes())}:${asDoubleDigit(dt.getSeconds())}`;
    };

    const setFlag = (flagName) => {
        if (!document.getElementById(flagName)) {
            const flag = document.createElement('style');
            flag.id = flagName;
            document.head.appendChild(flag);
            return false;
        }
        return true;
    };

    const injectAdBlockStyles = () => {
        if (setFlag('yesBlockTheAdsStyles')) {
            debug('Ad-blocking styles already present');
            return;
        }

        const style = document.createElement('style');
        style.textContent = adSelectors.map(selector => `${selector}{display:none!important}`).join('');
        document.head.appendChild(style);
        log('Ad-blocking styles successfully injected');
    };

    const simulateInteraction = (element) => {
        const events = ['mousedown', 'mouseup', 'click'];
        events.forEach(eventType => {
            const event = new MouseEvent(eventType, {
                view: window,
                bubbles: true,
                cancelable: true
            });
            element.dispatchEvent(event);
        });
    };

    const getVideoPlayer = () => document.querySelector('.ad-showing video, video');

    const ensureVideoPlayback = (video) => {
        if (video.paused && video.currentTime < 0.5) {
            video.play().catch(() => debug('Auto-play prevented'));
            debug('Attempting to auto-play video');
        }
    };

    const clearOverlays = () => {
        const premiumPrompts = document.querySelectorAll('ytd-popup-container');
        premiumPrompts.forEach(prompt => {
            if (prompt.querySelector('a[href="/premium"]')) {
                prompt.remove();
                debug('Removed a YouTube Premium prompt');
            }
        });

        const overlay = document.querySelector('tp-yt-iron-overlay-backdrop[style*="z-index: 2201"]');
        if (overlay) {
            overlay.style.display = 'none';
            debug('Hidden an overlay backdrop');
        }
    };

    const bypassAd = (video) => {
        const skipBtn = document.querySelector('.ytp-ad-skip-button, .ytp-skip-ad-button, .ytp-ad-skip-button-modern');
        const adIndicator = document.querySelector('.video-ads.ytp-ad-module .ytp-ad-player-overlay, .ytp-ad-button-icon');

        if ((skipBtn || adIndicator) && !window.location.href.includes('https://m.youtube.com/')) {
            video.muted = true;
        }

        if (skipBtn) {
            setTimeout(() => {
                if (video.currentTime > 0.5) {
                    video.currentTime = video.duration;
                    debug('Skipped ad for special case');
                    return;
                }
                simulateInteraction(skipBtn);
                debug('Bypassed ad using skip button');
            }, 250);
        } else if (adIndicator) {
            video.currentTime = video.duration;
            debug('Forcefully ended the current ad');
        }
    };

    const enhanceYouTubeExperience = () => {
        if (setFlag('yesBlockTheAdsEnhanced')) {
            debug('Yes BlockTheAds enhancement already active');
            return;
        }

        new MutationObserver(() => {
            const video = getVideoPlayer();
            if (video) {
                clearOverlays();
                bypassAd(video);
                ensureVideoPlayback(video);
            }
        }).observe(document.body, { childList: true, subtree: true });

        log('Yes BlockTheAds enhancement activated');
    };

    const waitForYouTubeApp = () => {
        return new Promise(resolve => {
            const checkForApp = () => {
                if (document.querySelector('ytd-app')) {
                    resolve();
                } else {
                    setTimeout(checkForApp, 100);
                }
            };
            checkForApp();
        });
    };

    await waitForYouTubeApp();
    injectAdBlockStyles();
    enhanceYouTubeExperience();
    log('Monitoring YouTube for ads...');
})();