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})();