- // ==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.org/scripts/519877/1497523/UserScript%20Compatibility%20Library.js
- // @run-at document-start
- // ==/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();
- }
- })();