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); | |
| })(); |
评论
?
参与讨论