Greasy Fork is available in English.
Blocks all YouTube ads (video, banner, preview) and suppresses adblocker warnings without skipping playlist videos.
// ==UserScript==
// @name RafBlocker Enhanced
// @namespace http://tampermonkey.net/
// @version 1.3
// @description Blocks all YouTube ads (video, banner, preview) and suppresses adblocker warnings without skipping playlist videos.
// @author Raf
// @match *://www.youtube.com/*
// @match *://m.youtube.com/*
// @grant none
// @run-at document-idle
// @license MIT
// ==/UserScript==
/*
* MIT License
*
* Copyright (c) 2025 Raf
*
* 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_SELECTORS = [
'.ad-container',
'.video-ads',
'.ytp-ad-module',
'.ytp-ad-image-overlay',
'.ytp-ad-overlay-container',
'.ytp-ce-element',
'.ytp-ad-text',
'.ytp-ad-preview-container',
'.ytp-ad-skip-button-container',
'.ytp-ad-banner-container',
'.sparkles-light-cta', // Promotional banners
'.ytd-companion-slot-renderer',
'.ytd-action-companion-ad-renderer',
'.ytd-in-feed-ad-renderer'
].join(', ');
const SKIP_BUTTON_SELECTOR = '.ytp-ad-skip-button, .ytp-skip-ad-button, .ytp-ad-skip-button-modern';
const WARNING_MODAL_SELECTOR = [
'ytd-popup-container',
'tp-yt-paper-dialog',
'.ytp-adblock-warning',
'.yt-spec-general-modal',
'#dialog',
'.ytd-consent-bump-v2-lightbox'
].join(', ');
const DISMISS_BUTTON_SELECTOR = [
'ytd-button-renderer button',
'.ytp-adblock-warning-dismiss',
'.yt-spec-button-shape-next--call-to-action',
'button[aria-label*="Dismiss"]',
'button[aria-label*="Close"]'
].join(', ');
// --- Utility Functions ---
// Remove elements matching the selector
function removeElements(selector) {
document.querySelectorAll(selector).forEach(element => {
if (element) {
element.remove();
}
});
}
// Check if the current video is an ad
function isAdPlaying() {
return document.querySelector('.ad-showing, .ad-interrupting, .ytp-ad-player-overlay') !== null;
}
// Skip video ads without affecting playlist videos
function skipVideoAd() {
const skipButton = document.querySelector(SKIP_BUTTON_SELECTOR);
if (skipButton) {
skipButton.click();
return true;
}
const videoPlayer = document.querySelector('video');
if (videoPlayer && isAdPlaying()) {
videoPlayer.currentTime = videoPlayer.duration || Number.MAX_SAFE_INTEGER;
return true;
}
return false;
}
// Suppress adblocker warnings
function suppressAdBlockWarning() {
// Inject CSS to hide modals and restore scrolling
let style = document.getElementById('RafBlockerStyle');
if (!style) {
style = document.createElement('style');
style.id = 'RafBlockerStyle';
style.type = 'text/css';
document.head.appendChild(style);
}
style.innerHTML = `
${WARNING_MODAL_SELECTOR}, .ytp-adblock-warning, .ytp-consent-bump {
display: none !important;
visibility: hidden !important;
pointer-events: none !important;
}
body, html {
overflow: auto !important;
}
.ytp-ad-player-overlay, .ytp-ad-overlay-slot {
display: none !important;
}
`;
// Click dismiss buttons
document.querySelectorAll(DISMISS_BUTTON_SELECTOR).forEach(button => {
if (button.innerText.toUpperCase().includes('DISMISS') ||
button.innerText.toUpperCase().includes('CLOSE') ||
button.getAttribute('aria-label')?.toUpperCase().includes('DISMISS') ||
button.getAttribute('aria-label')?.toUpperCase().includes('CLOSE')) {
button.click();
}
});
// Manipulate player state to bypass ad checks
const player = document.querySelector('#movie_player');
if (player && player.getPlayerState) {
const state = player.getPlayerState();
if (state === 2 && isAdPlaying()) { // Paused due to ad
player.playVideo();
}
}
// Override YouTube's ad-related properties
if (window.ytplayer?.config?.args) {
window.ytplayer.config.args.advideo = 0;
window.ytplayer.config.args.is_ad = false;
window.ytplayer.config.args.ad_flags = 0;
window.ytplayer.config.args.ad_module = '';
}
// Mock ad-related functions to return empty or safe values
const originalGet = Object.getOwnPropertyDescriptor;
const originalDefine = Object.defineProperty;
const mockProperties = ['adPlacements', 'adSlots', 'isAdPlaying', 'adsEnabled'];
mockProperties.forEach(prop => {
if (window.ytplayer) {
originalDefine(window.ytplayer, prop, {
get: () => false,
configurable: true
});
}
});
}
// --- Main Blocking Logic ---
function blockAdsAndWarnings() {
// Suppress adblock warnings first
suppressAdBlockWarning();
// Remove all ad-related elements
removeElements(AD_SELECTORS);
// Skip video ads only if an ad is detected
if (isAdPlaying()) {
skipVideoAd();
}
}
// --- Playlist Protection ---
function protectPlaylist() {
const playlist = document.querySelector('ytd-playlist-panel-renderer');
if (playlist) {
// Ensure the player doesn't skip videos due to ad detection
const player = document.querySelector('#movie_player');
if (player && player.getPlaylistId) {
const playlistId = player.getPlaylistId();
if (playlistId && isAdPlaying()) {
// Prevent skipping by ensuring ad checks don't interfere
player.playVideo();
}
}
}
}
// --- Observer and Interval ---
const observer = new MutationObserver(() => {
blockAdsAndWarnings();
protectPlaylist();
});
observer.observe(document.body, { childList: true, subtree: true });
// Run every 100ms for aggressive ad removal
setInterval(() => {
blockAdsAndWarnings();
protectPlaylist();
}, 100);
// Initial run
blockAdsAndWarnings();
protectPlaylist();
})();