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