// ==UserScript== // @name 视频网站去广告 + YouTube API播放器 // @namespace https://greasyfork.org/users/你的用户名 // @version 1.3 // @description 去除爱奇艺、优酷、腾讯视频、咪咕、PPTV、1905、芒果、哔哩、西瓜、YouTube等视频网站的广告 | YouTube官方API播放器支持 // @author WorkBuddy // @match *://*.iqiyi.com/* // @match *://*.youku.com/* // @match *://v.qq.com/* // @match *://*.migu.cn/* // @match *://*.pptv.com/* // @match *://*.1905.com/* // @match *://*.mgtv.com/* // @match *://*.bilibili.com/* // @match *://*.ixigua.com/* // @match *://www.youtube.com/* // @match *://youtube.com/* // @match *://*.youtube.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=iqiyi.com // @grant GM_registerMenuCommand // @grant GM_addStyle // @run-at document-start // @license MIT // ==/UserScript== (function() { 'use strict'; // 配置 const CONFIG = { debug: false, checkInterval: 500, // 检测间隔(ms) enableSkipButton: true, // 自动点击跳过按钮 enableRemoveAd: true, // 移除广告元素 enableSpeedUp: false, // 广告加速播放 }; // 广告元素选择器列表 const AD_SELECTORS = { // 爱奇艺 'iqiyi.com': [ '.episode-feed-back', '.episode-tips', '[class*="ad-"]', '[class*="player-ad"]', '.qy-player-ad', '.ads-container', '.commercial-popup', '.popup-ad', ], // 优酷 'youku.com': [ '.oplayer-ad', '.vp-ad-container', '[class*="ad-"]', '.youku-ad-wrapper', '.advertisement', '.commercial-box', ], // 腾讯视频 'qq.com': [ '.txp_ad', '.txp-drawer-ad', '[class*="ad-"]', '.txp_ad_container', '.video_ad', '.mod_ad', '.ad-mark', ], // 咪咕视频 'migu.cn': [ '.player-ad', '.ad-container', '[class*="ad-"]', '.advertisement', ], // PPTV 'pptv.com': [ '.ad-player', '.player-ad', '[class*="ad-"]', '.advertising', ], // 1905电影网 '1905.com': [ '.ad-wrap', '.player-ad', '[class*="ad-"]', ], // 芒果TV 'mgtv.com': [ '.player-ad', '.ad-container', '[class*="ad-"]', '.mgtv-ad', '.ad-cover', ], // 哔哩哔哩 'bilibili.com': [ '.video-ad-card', '.bilibili-live-ad', '.ad-container', '[class*="advert"]', '.bili-ad', '.popover', '.bp-popup', ], // 西瓜视频 'ixigua.com': [ '.ad-container', '.player-ad', '[class*="ad-"]', '.xg-ad', ], // YouTube 'youtube.com': [ '.ytp-ad-module', '.video-ads', 'ytd-ad-slot-renderer', 'ytd-promoted-sparkles-web-renderer', 'ytd-display-ad-renderer', '.ytp-ad-overlay-slot', '.ytp-ad-text-overlay', '#player-ads', ], }; // 跳过按钮选择器 const SKIP_BUTTON_SELECTORS = [ '.skip-btn', '.ad-skip', '.txp-ad-skip', '.youku-ad-skip', '.btn-skip-ad', '.ad-skip-button', '[class*="skip"]', '.ytp-ad-skip-button', '.ytp-ad-skip-button-modern', '.videoAdUiSkipButton', '.skip-button', '#skip_button', 'button[class*="skip"]', ]; // 调试日志 function log(message) { if (CONFIG.debug) { console.log('[VideoAdBlocker]', message); } } // 获取当前网站的选择器 function getCurrentSiteSelectors() { const hostname = window.location.hostname; for (const [domain, selectors] of Object.entries(AD_SELECTORS)) { if (hostname.includes(domain)) { return selectors; } } return []; } // 移除广告元素 function removeAdElements() { if (!CONFIG.enableRemoveAd) return; const selectors = getCurrentSiteSelectors(); if (selectors.length === 0) return; selectors.forEach(selector => { try { document.querySelectorAll(selector).forEach(el => { // YouTube 广告特殊处理 if (hostname.includes('youtube.com')) { if (el.tagName === 'YTD-AD-SLOT-RENDERER' || el.tagName === 'YTD-PROMOTED-SPARKLES-WEB-RENDERER') { el.remove(); log('Removed YouTube ad:', el.tagName); } } else { el.style.display = 'none'; el.style.visibility = 'hidden'; el.style.height = '0'; el.style.overflow = 'hidden'; } }); } catch (e) { // 忽略无效选择器 } }); } // 点击跳过按钮 function clickSkipButtons() { if (!CONFIG.enableSkipButton) return; SKIP_BUTTON_SELECTORS.forEach(selector => { try { document.querySelectorAll(selector).forEach(btn => { if (btn && btn.offsetParent !== null) { // 元素可见 btn.click(); log('Clicked skip button:', selector); } }); } catch (e) { // 忽略无效选择器 } }); // YouTube 专用跳过 if (hostname.includes('youtube.com')) { // 等待广告跳过按钮 const skipButton = document.querySelector('.ytp-ad-skip-button, .ytp-ad-skip-button-modern'); if (skipButton) { skipButton.click(); log('YouTube skip button clicked'); } // 尝试加速广告 if (CONFIG.enableSpeedUp) { const adVideo = document.querySelector('.ad-showing video'); if (adVideo) { adVideo.playbackRate = 10; adVideo.muted = true; } } } } // 移除 YouTube 广告覆盖层 function removeYouTubeOverlays() { if (!hostname.includes('youtube.com')) return; // 移除广告覆盖层 document.querySelectorAll('.ytp-ad-overlay-container, .ytp-ad-text-overlay').forEach(el => { el.style.display = 'none'; }); // 移除推广内容 document.querySelectorAll('ytd-promoted-sparkles-web-renderer, ytd-display-ad-renderer').forEach(el => { el.remove(); }); } // 处理爱奇艺特定广告 function handleIQiyiAds() { if (!hostname.includes('iqiyi.com')) return; // 移除暂停广告 document.querySelectorAll('.pause-ad-container, .pop-ad-container').forEach(el => { el.style.display = 'none'; }); // 移除贴片广告 document.querySelectorAll('.qc-comp-anim, .video-juji-ad').forEach(el => { el.style.display = 'none'; }); } // 处理优酷特定广告 function handleYoukuAds() { if (!hostname.includes('youku.com')) return; // 移除播放器广告 document.querySelectorAll('.youku-ad-player, .player-ads').forEach(el => { el.style.display = 'none'; }); } // 处理腾讯视频特定广告 function handleQQAds() { if (!hostname.includes('qq.com')) return; // 移除视频贴片广告 document.querySelectorAll('.txp_vid_ads, .video_ad_container').forEach(el => { el.style.display = 'none'; }); } // 处理B站特定广告 function handleBilibiliAds() { if (!hostname.includes('bilibili.com')) return; // 移除首页推广 document.querySelectorAll('.bili-banner, .bili-popover').forEach(el => { el.style.display = 'none'; }); // 移除大会员促销 document.querySelectorAll('.bili-dyn-up-composition, .bp-home-rcmd').forEach(el => { el.style.display = 'none'; }); } // 主处理函数 function processAds() { const hostname = window.location.hostname; removeAdElements(); clickSkipButtons(); // 特定网站处理 if (hostname.includes('youtube.com')) { removeYouTubeOverlays(); } if (hostname.includes('iqiyi.com')) { handleIQiyiAds(); } if (hostname.includes('youku.com')) { handleYoukuAds(); } if (hostname.includes('qq.com')) { handleQQAds(); } if (hostname.includes('bilibili.com')) { handleBilibiliAds(); } } // 监听 DOM 变化 function observeDOM() { const observer = new MutationObserver((mutations) => { processAds(); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style'], }); log('DOM observer started'); } // 定时检测 function startInterval() { setInterval(processAds, CONFIG.checkInterval); log('Interval checker started'); } //======================================== // YouTube 官方API播放器模块 //======================================== const YouTubeAPI = { player: null, videoId: null, isCustomPlayer: false, // 从URL中提取视频ID extractVideoId: function(url) { const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/shorts\/)([a-zA-Z0-9_-]{11})/, /^([a-zA-Z0-9_-]{11})$/ ]; for (const pattern of patterns) { const match = url.match(pattern); if (match) return match[1]; } return null; }, // 加载YouTube IFrame API loadIFrameAPI: function(callback) { if (window.YT && window.YT.Player) { callback(); return; } const tag = document.createElement('script'); tag.src = 'https://www.youtube.com/iframe_api'; const firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); window.onYouTubeIframeAPIReady = callback; }, // 创建自定义播放器 createPlayer: function(videoId, containerId) { this.videoId = videoId; const container = document.getElementById(containerId); if (!container) { log('Container not found: ' + containerId); return; } this.loadIFrameAPI(() => { this.player = new YT.Player(containerId, { height: '100%', width: '100%', videoId: videoId, playerVars: { 'autoplay': 0, 'controls': 1, 'rel': 0, 'showinfo': 0, 'modestbranding': 1, 'playsinline': 1, 'iv_load_policy': 3, 'enablejsapi': 1, 'origin': window.location.origin }, events: { 'onReady': this.onPlayerReady.bind(this), 'onStateChange': this.onPlayerStateChange.bind(this), 'onError': this.onPlayerError.bind(this) } }); this.isCustomPlayer = true; log('YouTube player created for video: ' + videoId); }); }, // 播放器就绪 onPlayerReady: function(event) { log('YouTube player ready'); document.dispatchEvent(new CustomEvent('YouTubePlayerReady', { detail: event.target })); }, // 播放状态变化 onPlayerStateChange: function(event) { const state = event.data; switch(state) { case YT.PlayerState.BUFFERING: log('Player buffering'); break; case YT.PlayerState.CUED: log('Player cued'); break; case YT.PlayerState.ENDED: log('Player ended'); document.dispatchEvent(new CustomEvent('YouTubePlayerEnded')); break; case YT.PlayerState.PAUSED: log('Player paused'); break; case YT.PlayerState.PLAYING: log('Player playing'); break; case YT.PlayerState.UNSTARTED: log('Player unstarted'); break; } }, // 播放器错误 onPlayerError: function(event) { log('Player error: ' + event.data); }, // 播放视频 play: function() { if (this.player && this.player.playVideo) { this.player.playVideo(); } }, // 暂停视频 pause: function() { if (this.player && this.player.pauseVideo) { this.player.pauseVideo(); } }, // 停止视频 stop: function() { if (this.player && this.player.stopVideo) { this.player.stopVideo(); } }, // 跳转播放 seekTo: function(seconds) { if (this.player && this.player.seekTo) { this.player.seekTo(seconds, true); } }, // 设置音量 (0-100) setVolume: function(volume) { if (this.player && this.player.setVolume) { this.player.setVolume(volume); } }, // 获取当前播放时间 getCurrentTime: function() { if (this.player && this.player.getCurrentTime) { return this.player.getCurrentTime(); } return 0; }, // 获取视频时长 getDuration: function() { if (this.player && this.player.getDuration) { return this.player.getDuration(); } return 0; }, // 加载新视频 loadVideo: function(videoId, startSeconds) { if (this.player && this.player.loadVideoById) { this.videoId = videoId; this.player.loadVideoById({ videoId: videoId, startSeconds: startSeconds || 0 }); } }, // 获取播放状态 getPlayerState: function() { if (this.player && this.player.getPlayerState) { return this.player.getPlayerState(); } return -1; }, // 是否正在播放 isPlaying: function() { return this.getPlayerState() === YT.PlayerState.PLAYING; } }; // 快捷菜单命令 function registerMenuCommands() { if (typeof GM_registerMenuCommand === 'undefined') return; // 切换调试模式 GM_registerMenuCommand('🔍 切换调试模式', function() { CONFIG.debug = !CONFIG.debug; alert('调试模式: ' + (CONFIG.debug ? '开启' : '关闭')); }); // 打开YouTube API播放器 GM_registerMenuCommand('🎬 打开YouTube播放器', function() { const videoId = YouTubeAPI.extractVideoId(window.location.href); if (!videoId) { alert('未检测到YouTube视频URL'); return; } YouTubeAPI.createPlayer(videoId, 'youtube-player-container'); }); // 跳转播放 GM_registerMenuCommand('⏩ 跳转播放', function() { const time = prompt('输入跳转时间(秒):', '0'); if (time && !isNaN(time)) { YouTubeAPI.seekTo(parseInt(time)); } }); // 设置播放速度 GM_registerMenuCommand('⚡ 播放速度', function() { const speed = prompt('输入播放速度 (0.25-2):', '1'); if (speed && !isNaN(speed)) { if (YouTubeAPI.player && YouTubeAPI.player.setPlaybackRate) { YouTubeAPI.player.setPlaybackRate(parseFloat(speed)); } } }); } // 添加样式 function addStyles() { const style = ` /* 自定义YouTube播放器容器 */ #youtube-player-modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); z-index: 999999; } #youtube-player-modal.active { display: flex; align-items: center; justify-content: center; } #youtube-player-modal .player-wrapper { width: 80%; max-width: 1000px; aspect-ratio: 16/9; background: #000; position: relative; } #youtube-player-modal .close-btn { position: absolute; top: -40px; right: 0; color: #fff; font-size: 30px; cursor: pointer; background: none; border: none; } /* 广告元素隐藏 */ .ytp-ad-module, .video-ads, ytd-ad-slot-renderer, ytd-promoted-sparkles-web-renderer, ytd-display-ad-renderer, .ytp-ad-overlay-slot, .ytp-ad-text-overlay, #player-ads { display: none !important; visibility: hidden !important; height: 0 !important; overflow: hidden !important; } `; if (typeof GM_addStyle !== 'undefined') { GM_addStyle(style); } else { const styleEl = document.createElement('style'); styleEl.textContent = style; document.head.appendChild(styleEl); } } // 页面加载完成后启动 function init() { log('Script initialized v1.3'); // 添加样式 addStyles(); // 页面加载完成后立即执行 processAds(); // 启动定时检测 startInterval(); // 启动 DOM 监听 if (document.body) { observeDOM(); } else { document.addEventListener('DOMContentLoaded', observeDOM); } // 注册菜单命令 registerMenuCommands(); // 如果在YouTube页面,尝试创建快捷操作 if (window.location.hostname.includes('youtube.com')) { setupYouTubeShortcuts(); } } // YouTube快捷操作 function setupYouTubeShortcuts() { // 键盘快捷键 document.addEventListener('keydown', function(e) { // 忽略输入框中的快捷键 if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; switch(e.key) { case 'k': // 播放/暂停 case ' ': if (YouTubeAPI.player && YouTubeAPI.player.playVideo) { if (YouTubeAPI.isPlaying()) { YouTubeAPI.pause(); } else { YouTubeAPI.play(); } } break; case 'ArrowLeft': // 后退10秒 YouTubeAPI.seekTo(Math.max(0, YouTubeAPI.getCurrentTime() - 10)); break; case 'ArrowRight': // 前进10秒 YouTubeAPI.seekTo(YouTubeAPI.getCurrentTime() + 10); break; case 'ArrowUp': // 音量增加 if (YouTubeAPI.player && YouTubeAPI.player.getVolume) { YouTubeAPI.setVolume(Math.min(100, YouTubeAPI.player.getVolume() + 10)); } break; case 'ArrowDown': // 音量减少 if (YouTubeAPI.player && YouTubeAPI.player.getVolume) { YouTubeAPI.setVolume(Math.max(0, YouTubeAPI.player.getVolume() - 10)); } break; case 'm': // 静音 if (YouTubeAPI.player && YouTubeAPI.player.mute) { YouTubeAPI.player.unMute(); } break; case 'f': // 全屏 if (YouTubeAPI.player && YouTubeAPI.player.getIframe) { YouTubeAPI.player.getIframe().requestFullscreen(); } break; } }); // 监听视频变化 const urlObserver = new MutationObserver(() => { const videoId = YouTubeAPI.extractVideoId(window.location.href); if (videoId && videoId !== YouTubeAPI.videoId) { log('Video changed to: ' + videoId); YouTubeAPI.videoId = videoId; } }); urlObserver.observe(document.body, { childList: true, subtree: true }); } // 启动脚本 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // 导出到全局 window.YouTubeAPI = YouTubeAPI; })();