// ==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.5 // @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 // @require https://update.greasyfork.icu/scripts/519877/1497523/UserScript%20Compatibility%20Library.js // @run-at document-start // @downloadURL none // ==/UserScript== (function () { 'use strict'; const CONFIG = { skipAds: GM_getValue('skipAds', true), hideAds: GM_getValue('hideAds', true), muteAds: GM_getValue('muteAds', true), bypassAdBlock: GM_getValue('bypassAdBlock', true), }; const saveConfig = () => { Object.keys(CONFIG).forEach(key => { GM_setValue(key, CONFIG[key]); }); }; 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', 'tp-yt-paper-dialog[role="dialog"]'], adBlockDetection: ['ytd-enforcement-message-view-model', '#error-page', '#dialog.ytd-popup-container'], }, isAdPlaying(video) { return document.querySelector('.ad-showing') !== null || (video?.src && video.src.includes('/ads/')) || document.querySelector('.ytp-ad-player-overlay') !== null; }, }; class AdSkipper { constructor() { this.originalVolume = null; this.observer = null; this.retryCount = 0; this.maxRetries = 5; this.lastVideoState = null; } initialize() { this.setupObservers(); this.checkForAds(); this.bypassAdBlockDetection(); this.setupVideoStateTracking(); document.addEventListener('DOMContentLoaded', () => { this.applyCriticalStyles(); }); setInterval(() => { this.checkForAds(); this.bypassAdBlockDetection(); }, 1000); } setupVideoStateTracking() { document.addEventListener('visibilitychange', () => { const video = document.querySelector('video'); if (video) { if (document.hidden) { this.lastVideoState = video.paused; } else if (this.lastVideoState !== null) { if (this.lastVideoState) { video.pause(); } else { video.play().catch(() => {}); } } } }); } applyCriticalStyles() { const styles = ` .ad-showing video { display: none !important; } .video-ads { display: none !important; } .ytp-ad-overlay-container { display: none !important; } .ytp-ad-message-container { display: none !important; } ytd-promoted-sparkles-web-renderer { display: none !important; } ytd-promoted-video-renderer { display: none !important; } tp-yt-paper-dialog[role="dialog"] { display: none !important; } ytd-enforcement-message-view-model { display: none !important; } #error-page { display: none !important; } #dialog.ytd-popup-container { display: none !important; } `; GM_addStyle(styles); } bypassAdBlockDetection() { if (!CONFIG.bypassAdBlock) return; AdDetector.selectors.adBlockDetection.forEach(selector => { const elements = document.querySelectorAll(selector); elements.forEach(element => element?.remove()); }); const video = document.querySelector('video'); if (video?.paused && !document.hidden && this.lastVideoState === false) { video.play().catch(() => {}); } } 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; video.style.display = 'block'; video.style.visibility = 'visible'; // Khôi phục trạng thái video sau khi bỏ qua quảng cáo if (this.lastVideoState) { video.pause(); } } else if (this.retryCount < this.maxRetries) { this.retryCount++; setTimeout(() => this.skipAd(), 500); } } catch { // Bỏ qua lỗi nếu có } } async clickSkipButton() { for (const selector of AdDetector.selectors.skippable) { const buttons = document.querySelectorAll(selector); for (const button of buttons) { if (button?.offsetParent !== null) { try { button.click(); return true; } catch { continue; } } } } return false; } async skipVideoAd(video) { if (AdDetector.isAdPlaying(video)) { try { video.currentTime = video.duration || 0; video.playbackRate = 16; if (video.paused && !document.hidden && this.lastVideoState === false) { await video.play().catch(() => {}); } return true; } catch { return false; } } 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 { // Bỏ qua lỗi nếu có } } setupObservers() { this.observer?.disconnect(); this.observer = new MutationObserver(() => { requestAnimationFrame(() => { this.checkForAds(); this.bypassAdBlockDetection(); }); }); 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 { el?.parentNode && el.remove(); } catch { // Bỏ qua lỗi nếu có } }); }); } destroy() { if (this.observer) { this.observer.disconnect(); this.observer = null; } saveConfig(); } } const init = () => { try { const adSkipper = new AdSkipper(); adSkipper.initialize(); window.addEventListener('unload', () => { adSkipper.destroy(); }); } catch { setTimeout(init, 1000); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();