YouTube & YouTube Music Adblock Userscript

// ==UserScript==
// @name YouTube & YouTube Music Adblock (API Interceptor)
// @namespace http://tampermonkey.net/
// @version 6.0
// @description Bloqueia anúncios na raiz (nível de API/Rede) no YouTube e YouTube Music, como o uBlock Origin
// @author Anton / Enhanced
// @match *://*.youtube.com/*
// @match *://music.youtube.com/*
// @exclude *://accounts.youtube.com/*
// @exclude *://www.youtube.com/live_chat_replay*
// @exclude *://www.youtube.com/persist_identity*
// @icon https://www.google.com/s2/favicons?sz=64&domain=music.youtube.com
// @grant none
// @run-at document-start
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// 1. Função central que limpa os nós de anúncios dos dados da API
function cleanAds(data) {
if (!data || typeof data !== 'object') return data;
// Remove estruturas de anúncios que disparam propagandas no player
if (data.adPlacements) delete data.adPlacements;
if (data.playerAds) delete data.playerAds;
if (data.adSlots) delete data.adSlots;
if (data.adSafetyReason) delete data.adSafetyReason;
// Se estiver aninhado dentro de playerResponse
if (data.playerResponse && typeof data.playerResponse === 'object') {
cleanAds(data.playerResponse);
}
// Remove banners de promoção do Premium
if (data.auxiliaryUi && data.auxiliaryUi.messageRenderers) {
delete data.auxiliaryUi.messageRenderers.upsellDialogRenderer;
}
return data;
}
// 2. Intercepta Response.prototype.json (usado pelo fetch do YouTube Music)
if (window.Response && Response.prototype.json) {
const originalJson = Response.prototype.json;
Response.prototype.json = async function(...args) {
const data = await originalJson.apply(this, args);
return cleanAds(data);
};
}
// 3. Intercepta JSON.parse (usado caso o YouTube processe payloads como texto)
const originalParse = JSON.parse;
JSON.parse = function(text, reviver) {
const data = originalParse.call(this, text, reviver);
return cleanAds(data);
};
// 4. Intercepta fetch para bloquear requisições a servidores de anúncios do Google
const originalFetch = window.fetch;
window.fetch = function(...args) {
const url = typeof args[0] === 'string' ? args[0] : (args[0] && args[0].url) || '';
// Cancela chamadas de estatísticas, rastreamento de anúncios e doubleclick
if (
url.includes('/api/stats/ads') ||
url.includes('/pagead/') ||
url.includes('doubleclick.net') ||
url.includes('/ad_break')
) {
return Promise.resolve(new Response(JSON.stringify({}), {
status: 200,
headers: { 'Content-Type': 'application/json' }
}));
}
return originalFetch.apply(this, args);
};
// 5. Intercepta variáveis globais de inicialização do player antes do carregamento
let _ytInitialPlayerResponse = window.ytInitialPlayerResponse;
Object.defineProperty(window, 'ytInitialPlayerResponse', {
get() {
return _ytInitialPlayerResponse;
},
set(val) {
_ytInitialPlayerResponse = cleanAds(val);
},
configurable: true
});
let _ytInitialData = window.ytInitialData;
Object.defineProperty(window, 'ytInitialData', {
get() {
return _ytInitialData;
},
set(val) {
_ytInitialData = cleanAds(val);
},
configurable: true
});
// 6. Camada Visual / DOM (remoção de banners e clique em "Continuar ouvindo?")
const cssRules = [
`ytmusic-mealbar-promo-renderer{display:none!important}`,
`ytmusic-ad-slot-renderer{display:none!important}`,
`ytmusic-popup-container:has(a[href*="/premium"]){display:none!important}`,
`tp-yt-paper-dialog:has(ytmusic-mealbar-promo-renderer){display:none!important}`,
`ytd-popup-container:has(a[href*="/premium"]){display:none!important}`,
`#player-ads{display:none!important}`,
`#masthead-ad{display:none!important}`
].join(' ');
const styleEl = document.createElement('style');
styleEl.textContent = cssRules;
(document.head || document.documentElement).appendChild(styleEl);
// Fecha diálogos de inatividade ("Você ainda está ouvindo?") e clica em botões de pular se surgirem
setInterval(() => {
// Confirma diálogo de inatividade
const confirmBtn = document.querySelector('ytmusic-you-there-renderer #confirm-button, yt-confirm-dialog-renderer #confirm-button');
if (confirmBtn && confirmBtn.offsetParent !== null) {
confirmBtn.click();
const video = document.querySelector('video');
if (video && video.paused) video.play();
}
// Botão de pular emergencial
const skipBtn = document.querySelector('.ytp-ad-skip-button, .ytp-skip-ad-button, .ytp-ad-skip-button-modern');
if (skipBtn && !skipBtn.disabled) {
skipBtn.click();
}
}, 500);
})();
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论