| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| (function() {
|
| 'use strict';
|
|
|
|
|
|
|
|
|
|
|
|
|
| const AD_JSON_KEYS = new Set([
|
| 'adPlacements', 'playerAds', 'adSlots', 'adBreaks', 'adBreakServiceRenderer',
|
| 'promotedSparklesWebRenderer', 'promotedVideoRenderer', 'adRenderer',
|
| 'displayAdRenderer', 'promoted', 'sponsoredAd', 'sponsoredContent',
|
| 'ad_placements', 'player_ads', 'ad_slots', 'ad_breaks',
|
| 'vastUrl', 'vastXml', 'vpaidUrl',
|
| 'adTagUrl', 'adUnit', 'adSource',
|
| ]);
|
|
|
| const AD_JSON_NESTED = [
|
| 'auxiliaryUi.messageRenderers.enforcementMessageViewModel',
|
| 'overlay.playerBarActionRenderer',
|
| ];
|
|
|
| function deepPruneAdKeys(obj, depth) {
|
| if (!obj || typeof obj !== 'object' || depth > 8) return;
|
| if (Array.isArray(obj)) {
|
| obj.forEach(item => deepPruneAdKeys(item, depth + 1));
|
| return;
|
| }
|
| for (const key of Object.keys(obj)) {
|
| if (AD_JSON_KEYS.has(key)) {
|
| delete obj[key];
|
| } else if (typeof obj[key] === 'object') {
|
| deepPruneAdKeys(obj[key], depth + 1);
|
| }
|
| }
|
| }
|
|
|
| function pruneNested(obj, path) {
|
| const parts = path.split('.');
|
| let target = obj;
|
| for (let i = 0; i < parts.length - 1; i++) {
|
| if (!target || typeof target !== 'object') return;
|
| target = target[parts[i]];
|
| }
|
| if (target && typeof target === 'object') {
|
| delete target[parts[parts.length - 1]];
|
| }
|
| }
|
|
|
|
|
| const _JSONParse = JSON.parse;
|
| JSON.parse = function() {
|
| const result = _JSONParse.apply(this, arguments);
|
| if (result && typeof result === 'object') {
|
| deepPruneAdKeys(result, 0);
|
| for (const path of AD_JSON_NESTED) {
|
| pruneNested(result, path);
|
| }
|
| }
|
| return result;
|
| };
|
|
|
|
|
| const _responseJson = Response.prototype.json;
|
| Response.prototype.json = function() {
|
| return _responseJson.apply(this, arguments).then(data => {
|
| if (data && typeof data === 'object') {
|
| deepPruneAdKeys(data, 0);
|
| for (const path of AD_JSON_NESTED) {
|
| pruneNested(data, path);
|
| }
|
| }
|
| return data;
|
| });
|
| };
|
|
|
|
|
|
|
|
|
|
|
| const AD_URL_PATTERNS = [
|
| '/pagead/', '/ptracking', '/api/stats/ads', '/ad_break',
|
| 'doubleclick.net', 'googlesyndication.com', 'googleadservices.com',
|
| 'imasdk.googleapis.com', 'securepubads.g.doubleclick.net',
|
| 'amazon-adsystem.com', 'twitchsvc.net',
|
| '/ads/bid', '/ads/log', '/ads/event',
|
| 'ad.doubleclick.net', 'pagead2.googlesyndication.com',
|
| 'stats.g.doubleclick.net', '2mdn.net',
|
| '/api/stats/qoe?adformat', 'play.google.com/log',
|
| 'video-ad-stats', '/adunit', '/vast/',
|
| ];
|
|
|
| function isAdUrl(url) {
|
| if (!url) return false;
|
| return AD_URL_PATTERNS.some(p => url.includes(p));
|
| }
|
|
|
| const _fetch = window.fetch;
|
| window.fetch = function(input, init) {
|
| const url = typeof input === 'string' ? input : (input instanceof Request ? input.url : '');
|
| if (isAdUrl(url)) {
|
| return Promise.resolve(new Response('{}', { status: 200, headers: { 'Content-Type': 'application/json' } }));
|
| }
|
| return _fetch.apply(this, arguments);
|
| };
|
|
|
| const _xhrOpen = XMLHttpRequest.prototype.open;
|
| XMLHttpRequest.prototype.open = function(method, url) {
|
| this.__muse_blocked = isAdUrl(url);
|
| return _xhrOpen.apply(this, arguments);
|
| };
|
| const _xhrSend = XMLHttpRequest.prototype.send;
|
| XMLHttpRequest.prototype.send = function() {
|
| if (this.__muse_blocked) {
|
| Object.defineProperty(this, 'readyState', { get: () => 4, configurable: true });
|
| Object.defineProperty(this, 'status', { get: () => 200, configurable: true });
|
| Object.defineProperty(this, 'responseText', { get: () => '{}', configurable: true });
|
| Object.defineProperty(this, 'response', { get: () => '{}', configurable: true });
|
| setTimeout(() => { if (typeof this.onload === 'function') this.onload(new Event('load')); }, 0);
|
| return;
|
| }
|
| return _xhrSend.apply(this, arguments);
|
| };
|
|
|
|
|
|
|
|
|
|
|
| const AD_SCRIPT_PATTERNS = [
|
| 'imasdk.googleapis.com', 'securepubads', 'pagead2.googlesyndication',
|
| 'adsbygoogle', 'googletag', 'gpt.js', 'pubads',
|
| 'amazon-adsystem.com/aax', 'moat', 'doubleclick.net/tag',
|
| ];
|
|
|
| const _createElement = document.createElement.bind(document);
|
| document.createElement = function(tag) {
|
| const el = _createElement(tag);
|
| if (tag.toLowerCase() === 'script') {
|
| const _setSrc = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, 'src')?.set;
|
| if (_setSrc) {
|
| Object.defineProperty(el, 'src', {
|
| set(value) {
|
| if (typeof value === 'string' && AD_SCRIPT_PATTERNS.some(p => value.includes(p))) {
|
| return;
|
| }
|
| _setSrc.call(this, value);
|
| },
|
| get() { return el.getAttribute('src') || ''; },
|
| configurable: true,
|
| });
|
| }
|
| }
|
| return el;
|
| };
|
|
|
|
|
|
|
|
|
|
|
| function setupVideoAdSkipper() {
|
| const skipSelectors = [
|
| '.ytp-ad-skip-button', '.ytp-ad-skip-button-modern', '.ytp-skip-ad-button',
|
| '[class*="skip-button"]', '[class*="skipButton"]', '[class*="ad-skip"]',
|
| 'button[class*="skip"]',
|
| ];
|
|
|
| const adContainerSelectors = [
|
| '.ytp-ad-module', '.ytp-ad-overlay-container', '.ytp-ad-text-overlay',
|
| '#player-ads', '#masthead-ad', '.ytd-promoted-sparkles-web-renderer',
|
| '.ytd-display-ad-renderer', '.ytd-promoted-video-renderer',
|
| '.ytd-ad-slot-renderer', '.ytd-in-feed-ad-layout-renderer',
|
| '[class*="ad-container"]', '[class*="ad-banner"]', '[class*="ad-slot"]',
|
| '.video-ads', '.ad-container', '#ad-display',
|
| ];
|
|
|
| const observer = new MutationObserver(() => {
|
|
|
| for (const sel of skipSelectors) {
|
| const btn = document.querySelector(sel);
|
| if (btn && btn.offsetParent !== null) {
|
| btn.click();
|
| }
|
| }
|
|
|
|
|
| for (const sel of adContainerSelectors) {
|
| document.querySelectorAll(sel).forEach(el => {
|
| if (el.offsetHeight > 0) {
|
| el.style.display = 'none';
|
| el.style.height = '0';
|
| el.style.overflow = 'hidden';
|
| el.style.margin = '0';
|
| el.style.padding = '0';
|
| }
|
| });
|
| }
|
|
|
|
|
| const player = document.querySelector('.html5-video-player');
|
| if (player && player.classList.contains('ad-showing')) {
|
| player.classList.remove('ad-showing');
|
| const video = player.querySelector('video');
|
| if (video && video.duration && isFinite(video.duration) && video.duration < 120) {
|
| video.currentTime = video.duration;
|
| video.playbackRate = 16;
|
| }
|
| }
|
| });
|
|
|
| function startObserving() {
|
| if (document.body) {
|
| observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] });
|
| } else {
|
| document.addEventListener('DOMContentLoaded', () => {
|
| observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] });
|
| });
|
| }
|
| }
|
|
|
| startObserving();
|
|
|
|
|
| setInterval(() => {
|
| for (const sel of adContainerSelectors) {
|
| document.querySelectorAll(sel).forEach(el => {
|
| el.style.display = 'none';
|
| });
|
| }
|
|
|
| const player = document.querySelector('.html5-video-player.ad-showing');
|
| if (player) {
|
| const video = player.querySelector('video');
|
| if (video && video.duration && isFinite(video.duration)) {
|
| video.currentTime = video.duration;
|
| }
|
| }
|
| }, 1000);
|
| }
|
|
|
| setupVideoAdSkipper();
|
|
|
|
|
|
|
|
|
|
|
| if (location.hostname.includes('twitch.tv')) {
|
| const origFetch = window.fetch;
|
| window.fetch = function(input, init) {
|
| const url = typeof input === 'string' ? input : (input instanceof Request ? input.url : '');
|
|
|
| if (url.includes('.m3u8')) {
|
| return origFetch.apply(this, arguments).then(response => {
|
| const clone = response.clone();
|
| return clone.text().then(text => {
|
| if (text.includes('stitched-ad') || text.includes('advertisement')) {
|
| const cleaned = text.split('\n').filter(line => {
|
| if (line.includes('#EXT-X-DATERANGE') && (line.includes('stitched-ad') || line.includes('advertisement'))) return false;
|
| if (line.includes('#EXT-X-SCTE35-OUT')) return false;
|
| return true;
|
| }).join('\n');
|
| return new Response(cleaned, { status: response.status, statusText: response.statusText, headers: response.headers });
|
| }
|
| return response;
|
| });
|
| });
|
| }
|
| return origFetch.apply(this, arguments);
|
| };
|
| }
|
|
|
|
|
|
|
|
|
|
|
| const adCss = `
|
| .ytp-ad-module, .ytp-ad-overlay-container, .ytp-ad-text-overlay,
|
| #player-ads, #masthead-ad, .ytd-promoted-sparkles-web-renderer,
|
| .ytd-display-ad-renderer, .ytd-promoted-video-renderer,
|
| .ytd-ad-slot-renderer, .ytd-in-feed-ad-layout-renderer,
|
| .ytd-banner-promo-renderer, ytd-rich-item-renderer:has(.ytd-ad-slot-renderer),
|
| [class*="ad-container"], [class*="ad-banner"],
|
| .video-ads, .ad-container, #ad-display,
|
| .ad-showing .ytp-ad-player-overlay,
|
| .ytp-ad-action-interstitial {
|
| display: none !important;
|
| height: 0 !important;
|
| max-height: 0 !important;
|
| overflow: hidden !important;
|
| margin: 0 !important;
|
| padding: 0 !important;
|
| opacity: 0 !important;
|
| pointer-events: none !important;
|
| }
|
| `;
|
|
|
| const style = document.createElement('style');
|
| style.id = '__muse_ad_collapse';
|
| style.textContent = adCss;
|
| (document.head || document.documentElement).appendChild(style);
|
|
|
| })();
|
|
|