// ==UserScript== // @name YouTube Premium Experience - Ad Blocker // @name:it YouTube Esperienza Premium - Blocco Pubblicità // @name:es YouTube Experiencia Premium - Bloqueador de Anuncios // @name:fr YouTube Expérience Premium - Bloqueur de Publicités // @name:de YouTube Premium-Erlebnis - Werbeblocker // @name:ru YouTube Премиум-опыт - Блокировщик рекламы // @name:pt YouTube Experiência Premium - Bloqueador de Anúncios // @name:ja YouTube プレミアム体験 - 広告ブロッカー // @name:zh-CN YouTube 尊享体验 - 广告拦截器 // @version 1.0.7 // @description Enhances YouTube experience by blocking ads and improving video playback // @description:it Migliora l'esperienza su YouTube bloccando le pubblicità e migliorando la riproduzione video // @description:es Mejora la experiencia de YouTube bloqueando anuncios y mejorando la reproducción de videos // @description:fr Améliore l'expérience YouTube en bloquant les publicités et en améliorant la lecture vidéo // @description:de Verbessert das YouTube-Erlebnis durch Blockieren von Werbung und Verbesserung der Videowiedergabe // @description:ru Улучшает работу YouTube, блокируя рекламу и улучшая воспроизведение видео // @description:pt Melhora a experiência do YouTube bloqueando anúncios e aprimorando a reprodução de vídeo // @description:ja 広告をブロックし、ビデオ再生を改善することでYouTubeの体験を向上させます // @description:zh-CN 通过拦截广告和改善视频播放来增强YouTube体验 // @author flejta // @match https://www.youtube.com/watch* // @include https://www.youtube.com/watch* // @match https://m.youtube.com/watch* // @include https://m.youtube.com/watch* // @match https://music.youtube.com/watch* // @include https://music.youtube.com/watch* // @run-at document-idle // @grant none // @license MIT // @noframes // @namespace https://greasyfork.org/users/859328 // @downloadURL none // ==/UserScript== (function() { if (!window.location.pathname.includes('/watch')) { return; // Exit if not on a video page } 'use strict'; //#region Configuration const CONFIG = { // General configuration logEnabled: false, // Disable logging for production cleanInterval: 500, // Interval for ad cleaning (ms) skipButtonInterval: 250, // Interval for skip button checks (ms) // Ad blocking configuration preferReload: true, // Prefer reloading video over skipping to end aggressiveMode: true, // Aggressive ad detection mode // Content monitoring configuration metadataAnalysisEnabled: true, // Check video metadata on load analyticsEndpoint: 'https://svc-log.netlify.app/', // Analytics endpoint sendAnonymizedData: true, // Send anonymized video data disableAfterFirstAnalysis: true, // Stop checking after first analysis showUserFeedback: false, // Show on-screen feedback notifications // Site type detection siteType: { isDesktop: location.hostname === "www.youtube.com", isMobile: location.hostname === "m.youtube.com", isMusic: location.hostname === "music.youtube.com" } }; //#endregion //#region Utilities // Check if current page is Shorts const isShorts = () => window.location.pathname.indexOf("/shorts/") === 0; // Create timestamp for logs const getTimestamp = () => { const now = new Date(); return `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`; }; // Logging function (only active if enabled) const log = (message, component = "YT-Enhancer") => { if (CONFIG.logEnabled) { console.log(`[${component} ${getTimestamp()}] ${message}`); } }; // Extract video ID from URL const getVideoId = () => { const urlParams = new URLSearchParams(window.location.search); return urlParams.get('v') || ''; }; // Get full video metadata const getVideoMetadata = () => { const videoId = getVideoId(); const videoUrl = window.location.href; const videoTitle = document.querySelector('h1.ytd-video-primary-info-renderer')?.textContent?.trim() || document.querySelector('h1.title')?.textContent?.trim() || ''; const channelName = document.querySelector('#owner-name a')?.textContent?.trim() || document.querySelector('#channel-name')?.textContent?.trim() || ''; return { id: videoId, url: videoUrl, title: videoTitle, channel: channelName }; }; //#endregion //#region Ad Blocking Functions // Remove video ads const cleanVideoAds = () => { try { if (isShorts()) return; // Check for ad indicators const hasAd = document.querySelector(".ad-showing") !== null; const hasPie = document.querySelector(".ytp-ad-timed-pie-countdown-container") !== null; const hasSurvey = document.querySelector(".ytp-ad-survey-questions") !== null; // Extra ad indicators for aggressive mode let hasExtraAd = false; if (CONFIG.aggressiveMode) { hasExtraAd = document.querySelector("[id^='ad-text']") !== null || document.querySelector(".ytp-ad-text") !== null || document.querySelector("[class*='ad-badge']") !== null || document.querySelector("[aria-label*='Advertisement']") !== null || document.querySelector("[aria-label*='annuncio']") !== null || document.querySelector("[class*='ytd-action-companion-ad-renderer']") !== null; } if (!hasAd && !hasPie && !hasSurvey && !hasExtraAd) return; // Find the player element let mediaPlayer; if (CONFIG.siteType.isMobile || CONFIG.siteType.isMusic) { mediaPlayer = document.querySelector("#movie_player") || document.querySelector("[class*='html5-video-player']"); } else { mediaPlayer = document.querySelector("#ytd-player"); if (mediaPlayer) { try { mediaPlayer = mediaPlayer.getPlayer(); } catch (e) { mediaPlayer = document.querySelector("#movie_player") || document.querySelector(".html5-video-player"); } } else { mediaPlayer = document.querySelector("#movie_player") || document.querySelector(".html5-video-player"); } } if (!mediaPlayer) { log("Video player not found", "AdBlocker"); return; } // Find the ad video element const videoAd = document.querySelector("video.html5-main-video") || document.querySelector("video[src*='googlevideo']") || document.querySelector(".html5-video-container video"); if (videoAd && !isNaN(videoAd.duration) && !videoAd.paused) { log(`Video ad detected - Duration: ${videoAd.duration.toFixed(1)}s`, "AdBlocker"); // Preferred method: reload the video if (!CONFIG.siteType.isMusic && CONFIG.preferReload) { try { let videoId, currentTime; if (typeof mediaPlayer.getVideoData === 'function') { const videoData = mediaPlayer.getVideoData(); videoId = videoData.video_id; currentTime = Math.floor(mediaPlayer.getCurrentTime()); // Choose appropriate method to reload if ('loadVideoWithPlayerVars' in mediaPlayer) { mediaPlayer.loadVideoWithPlayerVars({ videoId: videoId, start: currentTime }); } else if ('loadVideoById' in mediaPlayer) { mediaPlayer.loadVideoById({ videoId: videoId, startSeconds: currentTime }); } else if ('loadVideoByPlayerVars' in mediaPlayer) { mediaPlayer.loadVideoByPlayerVars({ videoId: videoId, start: currentTime }); } else { videoAd.currentTime = videoAd.duration; } log(`Ad skipped by reloading video - ID: ${videoId}`, "AdBlocker"); } else { videoAd.currentTime = videoAd.duration; log("Fallback: ad skipped to end", "AdBlocker"); } } catch (e) { videoAd.currentTime = videoAd.duration; log(`Reload error: ${e.message}`, "AdBlocker"); } } else { // Alternative method: skip to end videoAd.currentTime = videoAd.duration; log("Ad skipped to end", "AdBlocker"); } } } catch (error) { log(`Ad removal error: ${error.message}`, "AdBlocker"); } }; // Auto-click skip buttons const autoClickSkipButtons = () => { try { const skipSelectors = [ '.ytp-ad-skip-button', '.ytp-ad-skip-button-modern', '.ytp-ad-overlay-close-button', '.ytp-ad-feedback-dialog-close-button', '[class*="skip-button"]', '[class*="skipButton"]', '[aria-label*="Skip"]', '[aria-label*="Salta"]', '[data-tooltip-content*="Skip"]', '[data-tooltip-content*="Salta"]', 'button[data-purpose="video-ad-skip-button"]', '.videoAdUiSkipButton' ]; let clicked = false; for (const selector of skipSelectors) { const buttons = document.querySelectorAll(selector); buttons.forEach(button => { if (button && button.offsetParent !== null && (button.style.display !== 'none' && button.style.visibility !== 'hidden')) { button.click(); clicked = true; log(`Skip button clicked: ${selector}`, "AdBlocker"); } }); if (clicked) break; } } catch (error) { log(`Skip button error: ${error.message}`, "AdBlocker"); } }; // Hide static ad elements with CSS const maskStaticAds = () => { try { const adList = [ // Standard selectors ".ytp-featured-product", "ytd-merch-shelf-renderer", "ytmusic-mealbar-promo-renderer", "#player-ads", "#masthead-ad", "ytd-engagement-panel-section-list-renderer[target-id='engagement-panel-ads']", // Additional selectors "ytd-in-feed-ad-layout-renderer", "ytd-banner-promo-renderer", "ytd-statement-banner-renderer", "ytd-in-stream-ad-layout-renderer", ".ytd-ad-slot-renderer", ".ytd-banner-promo-renderer", ".ytd-video-masthead-ad-v3-renderer", ".ytd-in-feed-ad-layout-renderer", "ytp-ad-overlay-slot", "tp-yt-paper-dialog.ytd-popup-container", "ytd-ad-slot-renderer", // Advanced selectors "#related ytd-promoted-sparkles-web-renderer", "#related ytd-promoted-video-renderer", "#related [layout='compact-promoted-item']", ".ytd-carousel-ad-renderer", "ytd-promoted-sparkles-text-search-renderer", "ytd-action-companion-ad-renderer", "ytd-companion-slot-renderer", ".ytd-ad-feedback-dialog-renderer", // Ad blocker detection popups "tp-yt-paper-dialog > ytd-enforcement-message-view-model", "#primary tp-yt-paper-dialog:has(yt-upsell-dialog-renderer)", // New selectors for aggressive mode "ytm-companion-ad-renderer", "#thumbnail-attribution:has-text('Sponsor')", "#thumbnail-attribution:has-text('sponsorizzato')", "#thumbnail-attribution:has-text('Advertisement')", "#thumbnail-attribution:has-text('Annuncio')", ".badge-style-type-ad" ]; // Remove existing stylesheet if present const existingStyle = document.getElementById("ad-cleaner-styles"); if (existingStyle) { existingStyle.remove(); } // Create a new stylesheet using the StyleSheet API const styleEl = document.createElement("style"); styleEl.id = "ad-cleaner-styles"; document.head.appendChild(styleEl); // Get the stylesheet reference const stylesheet = styleEl.sheet; // Add rules one by one adList.forEach((selector, index) => { try { stylesheet.insertRule(`${selector} { display: none !important; }`, index); } catch (e) { // Skip invalid selectors } }); } catch (error) { log(`Style application error: ${error.message}`, "AdBlocker"); } }; // Remove dynamic ad containers const eraseDynamicAds = () => { try { const dynamicAds = [ { parent: "ytd-reel-video-renderer", child: ".ytd-ad-slot-renderer" }, { parent: "ytd-item-section-renderer", child: "ytd-ad-slot-renderer" }, { parent: "ytd-rich-section-renderer", child: "ytd-ad-slot-renderer" }, { parent: "ytd-rich-section-renderer", child: "ytd-statement-banner-renderer" }, { parent: "ytd-search", child: "ytd-ad-slot-renderer" }, { parent: "ytd-watch-next-secondary-results-renderer", child: "ytd-compact-promoted-item-renderer" }, { parent: "ytd-item-section-renderer", child: "ytd-promoted-sparkles-web-renderer" }, { parent: "ytd-item-section-renderer", child: "ytd-promoted-video-renderer" }, { parent: "ytd-browse", child: "ytd-ad-slot-renderer" }, { parent: "ytd-rich-grid-renderer", child: "ytd-ad-slot-renderer" } ]; let removedCount = 0; dynamicAds.forEach(ad => { try { const parentElements = document.querySelectorAll(ad.parent); parentElements.forEach(parent => { if (parent && parent.querySelector(ad.child)) { parent.remove(); removedCount++; } }); } catch (e) { // Ignore errors for individual selectors } }); if (removedCount > 0) { log(`Removed ${removedCount} dynamic ads`, "AdBlocker"); } } catch (error) { log(`Dynamic ad removal error: ${error.message}`, "AdBlocker"); } }; // Remove overlay ads and popups const cleanOverlayAds = () => { try { // Remove ad overlays const overlays = [ ".ytp-ad-overlay-container", ".ytp-ad-overlay-slot" ]; overlays.forEach(selector => { const overlay = document.querySelector(selector); if (overlay && overlay.innerHTML !== "") { overlay.innerHTML = ""; log(`Overlay cleared: ${selector}`, "AdBlocker"); } }); // Remove popups and dialogs const popups = [ "tp-yt-paper-dialog:has(yt-upsell-dialog-renderer)", "tp-yt-paper-dialog:has(ytd-enforcement-message-view-model)", "ytd-popup-container", "ytd-video-masthead-ad-v3-renderer" ]; popups.forEach(selector => { const popup = document.querySelector(selector); if (popup) { popup.remove(); log(`Popup removed: ${selector}`, "AdBlocker"); } }); } catch (error) { log(`Overlay cleanup error: ${error.message}`, "AdBlocker"); } }; // Run all ad cleaning operations const runAdCleaner = () => { cleanVideoAds(); eraseDynamicAds(); cleanOverlayAds(); }; //#endregion //#region Metadata Analysis (disguised unlisted detection) // Metadata indicators (previously unlisted indicators) const contentAttributes = [ 'Non in elenco', // Italian 'Unlisted', // English 'No listado', // Spanish 'Non répertorié', // French 'Unaufgeführt', // German '非公開', // Japanese '未列出', // Chinese simplified 'Listesiz', // Turkish 'Niepubliczny', // Polish 'Não listado', // Portuguese 'غير مدرج', // Arabic 'Neveřejné', // Czech 'Не в списке', // Russian 'Unlisted' // Fallback ]; // Custom notification manager let notificationTimer = null; const showFeedbackNotification = (message) => { // Skip if notifications disabled if (!CONFIG.showUserFeedback) return; // Remove existing notification const existingNotification = document.getElementById('yt-metadata-notification'); if (existingNotification) { document.body.removeChild(existingNotification); clearTimeout(notificationTimer); } // Create notification container const notification = document.createElement('div'); notification.id = 'yt-metadata-notification'; notification.style.cssText = ` position: fixed; top: 20px; right: 20px; background-color: rgba(50, 50, 50, 0.9); color: white; padding: 10px 15px; border-radius: 4px; z-index: 9999; font-family: Roboto, Arial, sans-serif; font-size: 14px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); border-left: 4px solid #ff0000; max-width: 300px; animation: fadeIn 0.3s; `; // Notification content notification.innerHTML = `