// ==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 2024.12.23.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
// @compatible chrome
// @compatible firefox
// @compatible edge
// ==/UserScript==
(function () {
'use strict';
const CONFIG = {
allowedReloadPage: true, // allow reload page
dontReloadWhileBusy: true, // don't reload page while busy
maxScrollThreshold: 200, // max scroll threshold
adSkipDelay: 500, // add delay 500ms to boost speed skip ads
maxPlaybackRate: 16, // max playback rate
maxSkipAttempts: 10, // increase skip ads attempts
autoMuteAds: true, // auto mute ads
hideAllAds: true, // hide all ads
};
class YouTubeAdSkipper {
constructor() {
this.video = null;
this.currentVideoTime = 0;
this.isTabBlurred = false;
this.skipAttempts = 0;
this.maxSkipAttempts = CONFIG.maxSkipAttempts;
this.lastSkipTime = 0;
this.init();
}
init() {
this.setupEventListeners();
this.setupMutationObserver();
if (CONFIG.hideAllAds) {
this.addCSSHideAds();
}
this.skipAd();
// add interval to check ads continuously
setInterval(() => this.skipAd(), 1000);
}
setupEventListeners() {
window.addEventListener('blur', () => (this.isTabBlurred = true));
window.addEventListener('focus', () => {
this.isTabBlurred = false;
this.skipAd(); // check ads when focus again
});
document.addEventListener(
'timeupdate',
e => {
if (e.target.matches('video.html5-main-video')) {
this.currentVideoTime = e.target.currentTime;
}
},
true
);
// add event for load new video
document.addEventListener('yt-navigate-finish', () => this.skipAd());
}
setupMutationObserver() {
const observer = new MutationObserver(() => this.skipAd());
observer.observe(document.body, {
attributes: true,
attributeFilter: ['class', 'src', 'style'],
childList: true,
subtree: true,
});
}
async skipAd() {
if (window.location.pathname.startsWith('/shorts/')) return;
const player = document.querySelector('#movie_player');
if (!player) return;
const hasAd = player.classList.contains('ad-showing');
this.video = player.querySelector('video.html5-main-video');
if (hasAd && this.video) {
await this.handleVideoAd();
}
this.removeAdBlockerWarnings();
this.removeShortVideoAds();
this.removeOverlayAds();
}
async handleVideoAd() {
// avoid processing too many times in a short time
const now = Date.now();
if (now - this.lastSkipTime < 100) return;
this.lastSkipTime = now;
const skipButtons = document.querySelectorAll(`
.ytp-skip-ad-button,
.ytp-ad-skip-button,
.ytp-ad-skip-button-modern,
.ytp-ad-survey-answer-button,
.ytp-ad-skip-button-container button
`);
skipButtons.forEach(button => {
if (button && button.offsetParent !== null) {
button.click();
button.remove();
}
});
if (this.video.src) {
this.video.currentTime = 9999;
this.video.playbackRate = CONFIG.maxPlaybackRate;
}
if (CONFIG.autoMuteAds) {
this.video.muted = true;
this.video.volume = 0;
}
if (this.skipAttempts < this.maxSkipAttempts) {
this.skipAttempts++;
await new Promise(resolve => setTimeout(resolve, CONFIG.adSkipDelay));
this.skipAd();
}
}
removeAdBlockerWarnings() {
const warnings = ['tp-yt-paper-dialog:has(#feedback.ytd-enforcement-message-view-model)', '.yt-playability-error-supported-renderers:has(.ytd-enforcement-message-view-model)', 'ytd-enforcement-message-view-model', '.ytd-popup-container'];
warnings.forEach(selector => {
const warning = document.querySelector(selector);
if (warning) {
if (selector.includes('playability-error') && this.checkCanReloadPage()) {
this.reloadPage();
}
warning.remove();
}
});
}
removeShortVideoAds() {
document
.querySelectorAll(
`
ytd-reel-video-renderer:has(.ytd-ad-slot-renderer),
ytd-in-feed-ad-layout-renderer,
ytd-promoted-video-renderer
`
)
.forEach(ad => ad.remove());
}
removeOverlayAds() {
document
.querySelectorAll(
`
.ytp-ad-overlay-container,
.ytp-ad-overlay-slot,
.ytp-ad-text-overlay
`
)
.forEach(ad => (ad.style.display = 'none'));
}
checkCanReloadPage() {
if (!CONFIG.allowedReloadPage) return false;
if (!CONFIG.dontReloadWhileBusy) return true;
if (document.activeElement?.matches('input, textarea, select')) return false;
if (document.documentElement.scrollTop > CONFIG.maxScrollThreshold) return false;
if (this.isTabBlurred) return false;
return true;
}
reloadPage() {
const params = new URLSearchParams(location.search);
if (this.currentVideoTime > 0) {
params.set('t', Math.floor(this.currentVideoTime) + 's');
}
location.replace(`${location.origin}${location.pathname}?${params.toString()}`);
}
addCSSHideAds() {
const styles = `
#player-ads,
#masthead-ad,
ytd-ad-slot-renderer,
ytd-rich-item-renderer:has(.ytd-ad-slot-renderer),
ytd-rich-section-renderer:has(.ytd-statement-banner-renderer),
ytd-reel-video-renderer:has(.ytd-ad-slot-renderer),
tp-yt-paper-dialog:has(#feedback.ytd-enforcement-message-view-model),
tp-yt-paper-dialog:has(> ytd-checkbox-survey-renderer),
.ytp-suggested-action,
.yt-mealbar-promo-renderer,
ytmusic-mealbar-promo-renderer,
ytmusic-statement-banner-renderer,
.ytd-display-ad-renderer,
.ytd-statement-banner-renderer,
.ytd-in-feed-ad-layout-renderer,
.ytp-ad-overlay-container,
.ytp-ad-text-overlay,
ytd-promoted-sparkles-web-renderer,
ytd-promoted-video-renderer,
.ytd-banner-promo-renderer,
.ytd-video-masthead-ad-v3-renderer,
.ytd-primetime-promo-renderer {
display: none !important;
}
.ytp-ad-skip-button-slot,
.ytp-ad-preview-slot,
.ytp-ad-message-slot {
display: none !important;
}
`;
GM_addStyle(styles);
}
}
new YouTubeAdSkipper();
})();