您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Tự động bỏ qua quảng cáo trên YouTube
当前为
// ==UserScript== // @name YouTube Bỏ qua quảng cáo video tự động // @name:en YouTube Auto Ad Skipper // @name:vi YouTube Bỏ qua quảng cáo video tự động // @name:zh-cn YouTube 自动跳过广告 // @name:zh-tw YouTube 自動跳過廣告 // @name:ja YouTube 広告自動スキップ // @name:ko YouTube 자동 광고 건너뛰기 // @name:es YouTube Saltar anuncios automáticamente // @name:ru YouTube Автоматический пропуск рекламы // @name:id YouTube Lewati Iklan Otomatis // @name:hi YouTube स्वचालित विज्ञापन स्किपर // @namespace http://tampermonkey.net/ // @version 6.1.3 // @description Tự động bỏ qua quảng cáo trên YouTube // @description:en Automatically skip ads on YouTube videos // @description:vi Tự động bỏ qua quảng cáo trên YouTube // @description:zh-cn 自动跳过 YouTube 视频广告 // @description:zh-tw 自動跳過 YouTube 影片廣告 // @description:ja YouTube動画の広告を自動的にスキップ // @description:ko YouTube 동영상의 광고를 자동으로 건너뛰기 // @description:es Salta automáticamente los anuncios en videos de YouTube // @description:ru Автоматически пропускает рекламу в видео на YouTube // @description:id Otomatis melewati iklan di video YouTube // @description:hi YouTube वीडियो में विज्ञापनों को स्वचालित रूप से छोड़ें // @author RenjiYuusei // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @match https://*.youtube.com/* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @run-at document-start // ==/UserScript== (function() { 'use strict'; // Configuration and storage const CONFIG = { skipAds: GM_getValue('skipAds', true), hideAds: GM_getValue('hideAds', true), muteAds: GM_getValue('muteAds', true) }; // Save configuration const saveConfig = () => { Object.keys(CONFIG).forEach(key => { GM_setValue(key, CONFIG[key]); }); }; // Ad Detection with extended selectors const AdDetector = { selectors: { skippable: [ '.ytp-ad-skip-button', '.ytp-ad-skip-button-modern', '.videoAdUiSkipButton', '.ytp-ad-overlay-close-button', '.ytp-ad-text-overlay-skip-button', '.ytp-ad-skip-button-container', '.ytp-ad-preview-container' ], hideable: [ '.ad-showing', '.ytp-ad-module', 'ytd-ad-slot-renderer', '#masthead-ad', '.video-ads', '.ytp-ad-overlay-container', 'ytd-promoted-sparkles-web-renderer', 'ytd-promoted-video-renderer', '.ytd-watch-next-secondary-results-renderer.ytd-item-section-renderer' ] }, isAdPlaying(video) { return document.querySelector('.ad-showing') !== null || (video?.src && video.src.includes('/ads/')) || document.querySelector('.ytp-ad-player-overlay') !== null; } }; // Ad Skipper with extended features class AdSkipper { constructor() { this.originalVolume = null; this.observer = null; this.retryCount = 0; this.maxRetries = 5; } initialize() { this.setupObservers(); this.checkForAds(); // Wait for DOM to load before applying styles document.addEventListener('DOMContentLoaded', () => { this.applyCriticalStyles(); }); // Add periodic check interval setInterval(() => this.checkForAds(), 1000); } applyCriticalStyles() { const styles = ` .ad-showing video { display: none !important; } .video-ads { visibility: hidden !important; } .ytp-ad-overlay-container { visibility: hidden !important; } .ytp-ad-message-container { visibility: hidden !important; } ytd-promoted-sparkles-web-renderer { visibility: hidden !important; } ytd-promoted-video-renderer { visibility: hidden !important; } `; GM_addStyle(styles); } async skipAd() { const video = document.querySelector('video'); if (!video) return; try { if (await this.clickSkipButton() || await this.skipVideoAd(video)) { if (CONFIG.muteAds) { this.muteAd(video); } this.retryCount = 0; // Restore video player after skipping ads video.style.display = 'block'; video.style.visibility = 'visible'; } else if (this.retryCount < this.maxRetries) { this.retryCount++; setTimeout(() => this.skipAd(), 500); } } catch (err) { console.warn('Error skipping ad:', err); } } async clickSkipButton() { for (const selector of AdDetector.selectors.skippable) { const buttons = document.querySelectorAll(selector); for (const button of buttons) { if (button && button.offsetParent !== null) { try { button.click(); return true; } catch (err) { console.warn('Error clicking skip button:', err); } } } } return false; } async skipVideoAd(video) { if (AdDetector.isAdPlaying(video)) { try { video.currentTime = video.duration || 0; video.playbackRate = 16; if (video.paused) { await video.play().catch(() => {}); } return true; } catch (err) { console.warn('Error skipping video ad:', err); } } return false; } muteAd(video) { if (this.originalVolume === null) { this.originalVolume = video.volume; } try { video.muted = true; video.volume = 0; const muteButton = document.querySelector('.ytp-mute-button'); if (muteButton && !video.muted) { muteButton.click(); } } catch (err) { console.warn('Error muting ad:', err); } } setupObservers() { if (this.observer) { this.observer.disconnect(); } this.observer = new MutationObserver(() => { requestAnimationFrame(() => { this.checkForAds(); }); }); this.observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'src', 'style'] }); } checkForAds() { if (CONFIG.skipAds) { this.skipAd(); } if (CONFIG.hideAds) { this.hideAds(); } } hideAds() { AdDetector.selectors.hideable.forEach(selector => { document.querySelectorAll(selector).forEach(el => { try { if (el.parentNode) { el.style.visibility = 'hidden'; } } catch (err) { console.warn('Error hiding ad element:', err); } }); }); } destroy() { if (this.observer) { this.observer.disconnect(); this.observer = null; } saveConfig(); } } // Initialize with enhanced error handling const init = () => { try { const adSkipper = new AdSkipper(); adSkipper.initialize(); window.addEventListener('unload', () => { adSkipper.destroy(); }); } catch (err) { console.error('Error initializing AdSkipper:', err); setTimeout(init, 1000); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();