YouTube Premium Experience - Ad Blocker & Enhancer

Block all YouTube ads (video, banner, overlay) and add premium features: custom speed controls, theater mode, screenshot tool, auto-skip intro, and more

Size

16.9 KB

Version

1.0.1

Created

Dec 2, 2025

Updated

15 days ago

1// ==UserScript==
2// @name		YouTube Premium Experience - Ad Blocker & Enhancer
3// @description		Block all YouTube ads (video, banner, overlay) and add premium features: custom speed controls, theater mode, screenshot tool, auto-skip intro, and more
4// @version		1.0.1
5// @match		https://*.youtube.com/*
6// @icon		https://www.youtube.com/s/desktop/76a077af/img/favicon_32x32.png
7// @grant		GM.getValue
8// @grant		GM.setValue
9// @grant		GM.xmlhttpRequest
10// ==/UserScript==
11(function() {
12    'use strict';
13
14    console.log('YouTube Premium Experience - Extension loaded');
15
16    // ==================== CONFIGURATION ====================
17    const CONFIG = {
18        adBlockingEnabled: true,
19        autoSkipAds: true,
20        removeAnnotations: true,
21        customSpeedControls: true,
22        theaterModeByDefault: false,
23        autoSkipIntro: true,
24        removeRecommendations: false,
25        hideComments: false,
26        screenshotTool: true
27    };
28
29    // ==================== AD BLOCKING ====================
30    
31    // Block video ads
32    function blockVideoAds() {
33        const video = document.querySelector('video.html5-main-video');
34        if (!video) return;
35
36        // Skip ads automatically
37        const skipButton = document.querySelector('button.ytp-ad-skip-button, button.ytp-ad-skip-button-modern');
38        if (skipButton) {
39            console.log('Skipping ad...');
40            skipButton.click();
41        }
42
43        // Remove ad overlay
44        const adOverlay = document.querySelector('.ytp-ad-player-overlay, .ytp-ad-overlay-container');
45        if (adOverlay) {
46            adOverlay.remove();
47            console.log('Removed ad overlay');
48        }
49
50        // Speed up ads if they can't be skipped
51        const adModule = document.querySelector('.video-ads.ytp-ad-module');
52        if (adModule && video) {
53            video.playbackRate = 16;
54            video.muted = true;
55            console.log('Speeding up unskippable ad');
56        }
57    }
58
59    // Remove banner ads and promotional content
60    function removeBannerAds() {
61        const adSelectors = [
62            'ytd-display-ad-renderer',
63            'ytd-promoted-sparkles-web-renderer',
64            'ytd-ad-slot-renderer',
65            'ytd-banner-promo-renderer',
66            'ytd-statement-banner-renderer',
67            'ytd-in-feed-ad-layout-renderer',
68            'ytd-player-legacy-desktop-watch-ads-renderer',
69            '.ytd-merch-shelf-renderer',
70            'ytd-compact-promoted-item-renderer',
71            'ytd-promoted-video-renderer',
72            '#masthead-ad',
73            '.ytd-action-companion-ad-renderer'
74        ];
75
76        adSelectors.forEach(selector => {
77            document.querySelectorAll(selector).forEach(ad => {
78                ad.remove();
79                console.log(`Removed ad: ${selector}`);
80            });
81        });
82    }
83
84    // Remove video annotations and cards
85    function removeAnnotations() {
86        const annotations = document.querySelectorAll('.ytp-ce-element, .annotation, .ytp-cards-teaser');
87        annotations.forEach(annotation => annotation.remove());
88    }
89
90    // ==================== CUSTOM SPEED CONTROLS ====================
91    
92    function addCustomSpeedControls() {
93        if (document.getElementById('yt-custom-speed-panel')) return;
94
95        const video = document.querySelector('video.html5-main-video');
96        if (!video) return;
97
98        const speedPanel = document.createElement('div');
99        speedPanel.id = 'yt-custom-speed-panel';
100        speedPanel.innerHTML = `
101            <div style="position: fixed; bottom: 100px; right: 20px; background: rgba(0, 0, 0, 0.9); 
102                        padding: 15px; border-radius: 12px; z-index: 9999; color: white; 
103                        font-family: 'Roboto', Arial, sans-serif; box-shadow: 0 4px 20px rgba(0,0,0,0.5);
104                        min-width: 200px;">
105                <div style="font-weight: bold; margin-bottom: 10px; font-size: 14px; color: #3ea6ff;">
106                    ⚡ Speed Control
107                </div>
108                <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 10px;">
109                    <button class="speed-btn" data-speed="0.5">0.5x</button>
110                    <button class="speed-btn" data-speed="0.75">0.75x</button>
111                    <button class="speed-btn" data-speed="1">1x</button>
112                    <button class="speed-btn" data-speed="1.25">1.25x</button>
113                    <button class="speed-btn" data-speed="1.5">1.5x</button>
114                    <button class="speed-btn" data-speed="1.75">1.75x</button>
115                    <button class="speed-btn" data-speed="2">2x</button>
116                    <button class="speed-btn" data-speed="2.5">2.5x</button>
117                    <button class="speed-btn" data-speed="3">3x</button>
118                </div>
119                <div style="margin-top: 10px;">
120                    <input type="range" id="custom-speed-slider" min="0.25" max="3" step="0.25" value="1" 
121                           style="width: 100%; cursor: pointer;">
122                    <div style="text-align: center; margin-top: 5px; font-size: 12px; color: #aaa;">
123                        Current: <span id="current-speed-display">1.0x</span>
124                    </div>
125                </div>
126                <button id="toggle-speed-panel" style="margin-top: 10px; width: 100%; padding: 8px; 
127                        background: #3ea6ff; border: none; border-radius: 6px; color: white; 
128                        cursor: pointer; font-weight: bold;">
129                    Minimize
130                </button>
131            </div>
132        `;
133
134        document.body.appendChild(speedPanel);
135
136        // Add styles for speed buttons
137        const style = document.createElement('style');
138        style.textContent = `
139            .speed-btn {
140                padding: 8px;
141                background: #272727;
142                border: 2px solid #3ea6ff;
143                border-radius: 6px;
144                color: white;
145                cursor: pointer;
146                font-size: 12px;
147                font-weight: bold;
148                transition: all 0.2s;
149            }
150            .speed-btn:hover {
151                background: #3ea6ff;
152                transform: scale(1.05);
153            }
154            .speed-btn.active {
155                background: #3ea6ff;
156                box-shadow: 0 0 10px #3ea6ff;
157            }
158        `;
159        document.head.appendChild(style);
160
161        // Speed button handlers
162        document.querySelectorAll('.speed-btn').forEach(btn => {
163            btn.addEventListener('click', () => {
164                const speed = parseFloat(btn.dataset.speed);
165                video.playbackRate = speed;
166                document.getElementById('custom-speed-slider').value = speed;
167                document.getElementById('current-speed-display').textContent = speed + 'x';
168                document.querySelectorAll('.speed-btn').forEach(b => b.classList.remove('active'));
169                btn.classList.add('active');
170                console.log(`Speed changed to ${speed}x`);
171            });
172        });
173
174        // Slider handler
175        document.getElementById('custom-speed-slider').addEventListener('input', (e) => {
176            const speed = parseFloat(e.target.value);
177            video.playbackRate = speed;
178            document.getElementById('current-speed-display').textContent = speed.toFixed(2) + 'x';
179        });
180
181        // Toggle minimize
182        let isMinimized = false;
183        document.getElementById('toggle-speed-panel').addEventListener('click', () => {
184            const panel = speedPanel.querySelector('div');
185            if (isMinimized) {
186                panel.style.height = 'auto';
187                panel.style.overflow = 'visible';
188                document.getElementById('toggle-speed-panel').textContent = 'Minimize';
189            } else {
190                panel.style.height = '40px';
191                panel.style.overflow = 'hidden';
192                document.getElementById('toggle-speed-panel').textContent = 'Expand';
193            }
194            isMinimized = !isMinimized;
195        });
196    }
197
198    // ==================== SCREENSHOT TOOL ====================
199    
200    function addScreenshotTool() {
201        if (document.getElementById('yt-screenshot-btn')) return;
202
203        const screenshotBtn = document.createElement('button');
204        screenshotBtn.id = 'yt-screenshot-btn';
205        screenshotBtn.innerHTML = '📸';
206        screenshotBtn.title = 'Take Screenshot (S key)';
207        screenshotBtn.style.cssText = `
208            position: fixed;
209            bottom: 180px;
210            right: 20px;
211            width: 50px;
212            height: 50px;
213            background: rgba(0, 0, 0, 0.9);
214            border: 2px solid #3ea6ff;
215            border-radius: 50%;
216            color: white;
217            font-size: 24px;
218            cursor: pointer;
219            z-index: 9999;
220            display: flex;
221            align-items: center;
222            justify-content: center;
223            transition: all 0.3s;
224            box-shadow: 0 4px 15px rgba(0,0,0,0.5);
225        `;
226
227        screenshotBtn.addEventListener('mouseenter', () => {
228            screenshotBtn.style.transform = 'scale(1.1)';
229            screenshotBtn.style.boxShadow = '0 6px 20px rgba(62, 166, 255, 0.6)';
230        });
231
232        screenshotBtn.addEventListener('mouseleave', () => {
233            screenshotBtn.style.transform = 'scale(1)';
234            screenshotBtn.style.boxShadow = '0 4px 15px rgba(0,0,0,0.5)';
235        });
236
237        screenshotBtn.addEventListener('click', takeScreenshot);
238        document.body.appendChild(screenshotBtn);
239
240        // Keyboard shortcut
241        document.addEventListener('keydown', (e) => {
242            if (e.key === 's' || e.key === 'S') {
243                const activeElement = document.activeElement;
244                if (activeElement.tagName !== 'INPUT' && activeElement.tagName !== 'TEXTAREA') {
245                    e.preventDefault();
246                    takeScreenshot();
247                }
248            }
249        });
250    }
251
252    function takeScreenshot() {
253        const video = document.querySelector('video.html5-main-video');
254        if (!video) {
255            console.error('Video element not found');
256            return;
257        }
258
259        const canvas = document.createElement('canvas');
260        canvas.width = video.videoWidth;
261        canvas.height = video.videoHeight;
262        const ctx = canvas.getContext('2d');
263        ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
264
265        canvas.toBlob((blob) => {
266            const url = URL.createObjectURL(blob);
267            const a = document.createElement('a');
268            a.href = url;
269            a.download = `youtube-screenshot-${Date.now()}.png`;
270            a.click();
271            URL.revokeObjectURL(url);
272            
273            showNotification('Screenshot saved! 📸');
274            console.log('Screenshot taken successfully');
275        });
276    }
277
278    // ==================== AUTO-SKIP INTRO ====================
279    
280    function autoSkipIntro() {
281        const skipIntroButton = document.querySelector('button.ytp-skip-ad-button, .ytp-skip-intro-button, button[aria-label*="Skip"]');
282        if (skipIntroButton && skipIntroButton.textContent.includes('Skip')) {
283            skipIntroButton.click();
284            console.log('Auto-skipped intro');
285        }
286    }
287
288    // ==================== THEATER MODE ====================
289    
290    async function enableTheaterMode() {
291        const theaterButton = document.querySelector('button.ytp-size-button');
292        const isTheaterMode = document.querySelector('ytd-watch-flexy[theater]');
293        
294        if (theaterButton && !isTheaterMode && CONFIG.theaterModeByDefault) {
295            theaterButton.click();
296            console.log('Theater mode enabled');
297        }
298    }
299
300    // ==================== REMOVE DISTRACTIONS ====================
301    
302    function removeDistractions() {
303        if (CONFIG.removeRecommendations) {
304            const recommendations = document.querySelector('#related');
305            if (recommendations) recommendations.style.display = 'none';
306        }
307
308        if (CONFIG.hideComments) {
309            const comments = document.querySelector('#comments');
310            if (comments) comments.style.display = 'none';
311        }
312    }
313
314    // ==================== NOTIFICATION SYSTEM ====================
315    
316    function showNotification(message) {
317        const notification = document.createElement('div');
318        notification.textContent = message;
319        notification.style.cssText = `
320            position: fixed;
321            top: 80px;
322            right: 20px;
323            background: rgba(0, 0, 0, 0.9);
324            color: white;
325            padding: 15px 20px;
326            border-radius: 8px;
327            z-index: 10000;
328            font-family: 'Roboto', Arial, sans-serif;
329            font-size: 14px;
330            box-shadow: 0 4px 15px rgba(0,0,0,0.5);
331            border-left: 4px solid #3ea6ff;
332            animation: slideIn 0.3s ease-out;
333        `;
334
335        const style = document.createElement('style');
336        style.textContent = `
337            @keyframes slideIn {
338                from { transform: translateX(400px); opacity: 0; }
339                to { transform: translateX(0); opacity: 1; }
340            }
341        `;
342        document.head.appendChild(style);
343
344        document.body.appendChild(notification);
345        setTimeout(() => notification.remove(), 3000);
346    }
347
348    // ==================== SETTINGS PANEL ====================
349    
350    function createSettingsPanel() {
351        if (document.getElementById('yt-premium-settings')) return;
352
353        const settingsBtn = document.createElement('button');
354        settingsBtn.innerHTML = '⚙️';
355        settingsBtn.title = 'YouTube Premium Experience Settings';
356        settingsBtn.style.cssText = `
357            position: fixed;
358            bottom: 250px;
359            right: 20px;
360            width: 50px;
361            height: 50px;
362            background: rgba(0, 0, 0, 0.9);
363            border: 2px solid #3ea6ff;
364            border-radius: 50%;
365            color: white;
366            font-size: 24px;
367            cursor: pointer;
368            z-index: 9999;
369            display: flex;
370            align-items: center;
371            justify-content: center;
372            transition: all 0.3s;
373            box-shadow: 0 4px 15px rgba(0,0,0,0.5);
374        `;
375
376        settingsBtn.addEventListener('click', () => {
377            showNotification('Settings panel - Coming soon! 🎉');
378        });
379
380        document.body.appendChild(settingsBtn);
381    }
382
383    // ==================== DEBOUNCE UTILITY ====================
384    
385    function debounce(func, wait) {
386        let timeout;
387        return function executedFunction(...args) {
388            const later = () => {
389                clearTimeout(timeout);
390                func(...args);
391            };
392            clearTimeout(timeout);
393            timeout = setTimeout(later, wait);
394        };
395    }
396
397    // ==================== MAIN OBSERVER ====================
398    
399    function observePageChanges() {
400        const debouncedAdBlock = debounce(() => {
401            if (CONFIG.adBlockingEnabled) {
402                blockVideoAds();
403                removeBannerAds();
404            }
405            if (CONFIG.removeAnnotations) {
406                removeAnnotations();
407            }
408            if (CONFIG.autoSkipIntro) {
409                autoSkipIntro();
410            }
411        }, 500);
412
413        const observer = new MutationObserver(debouncedAdBlock);
414        
415        observer.observe(document.body, {
416            childList: true,
417            subtree: true
418        });
419
420        console.log('Page observer initialized');
421    }
422
423    // ==================== INITIALIZATION ====================
424    
425    function init() {
426        console.log('Initializing YouTube Premium Experience...');
427
428        // Wait for page to be ready
429        if (document.readyState === 'loading') {
430            document.addEventListener('DOMContentLoaded', init);
431            return;
432        }
433
434        // Initial cleanup
435        setTimeout(() => {
436            if (CONFIG.adBlockingEnabled) {
437                blockVideoAds();
438                removeBannerAds();
439            }
440            if (CONFIG.removeAnnotations) {
441                removeAnnotations();
442            }
443            removeDistractions();
444        }, 1000);
445
446        // Add features
447        setTimeout(() => {
448            if (CONFIG.customSpeedControls) {
449                addCustomSpeedControls();
450            }
451            if (CONFIG.screenshotTool) {
452                addScreenshotTool();
453            }
454            createSettingsPanel();
455            enableTheaterMode();
456        }, 2000);
457
458        // Start observing
459        observePageChanges();
460
461        // Periodic checks for ads
462        setInterval(() => {
463            if (CONFIG.adBlockingEnabled) {
464                blockVideoAds();
465                removeBannerAds();
466            }
467            if (CONFIG.autoSkipAds) {
468                autoSkipIntro();
469            }
470        }, 1000);
471
472        showNotification('YouTube Premium Experience Active! 🚀');
473        console.log('YouTube Premium Experience initialized successfully');
474    }
475
476    // Start the extension
477    init();
478
479})();
YouTube Premium Experience - Ad Blocker & Enhancer | Robomonkey