// ==UserScript==
// @name Auto Skip YouTube Ads
// @name:ar تخطي إعلانات YouTube تلقائيًا
// @name:es Saltar Automáticamente Anuncios De YouTube
// @name:fr Ignorer Automatiquement Les Publicités YouTube
// @name:hi YouTube विज्ञापन स्वचालित रूप से छोड़ें
// @name:id Lewati Otomatis Iklan YouTube
// @name:ja YouTube 広告を自動スキップ
// @name:ko YouTube 광고 자동 건너뛰기
// @name:nl YouTube-Advertenties Automatisch Overslaan
// @name:pt-BR Pular Automaticamente Anúncios Do YouTube
// @name:ru Автоматический Пропуск Рекламы На YouTube
// @name:vi Tự Động Bỏ Qua Quảng Cáo YouTube
// @name:zh-CN 自动跳过 YouTube 广告
// @name:zh-TW 自動跳過 YouTube 廣告
// @namespace https://github.com/tientq64/userscripts
// @version 7.2.1
// @description Automatically skip YouTube ads instantly. Undetected by YouTube ad blocker warnings.
// @description:ar تخطي إعلانات YouTube تلقائيًا على الفور. دون أن يتم اكتشاف ذلك من خلال تحذيرات أداة حظر الإعلانات في YouTube.
// @description:es Omite automáticamente los anuncios de YouTube al instante. Sin que te detecten las advertencias del bloqueador de anuncios de YouTube.
// @description:fr Ignorez automatiquement et instantanément les publicités YouTube. Non détecté par les avertissements du bloqueur de publicités YouTube.
// @description:hi YouTube विज्ञापनों को स्वचालित रूप से तुरंत छोड़ दें। YouTube विज्ञापन अवरोधक चेतावनियों द्वारा पता नहीं लगाया गया।
// @description:id Lewati iklan YouTube secara otomatis secara instan. Tidak terdeteksi oleh peringatan pemblokir iklan YouTube.
// @description:ja YouTube 広告を即座に自動的にスキップします。YouTube 広告ブロッカーの警告には検出されません。
// @description:ko YouTube 광고를 즉시 자동으로 건너뜁니다. YouTube 광고 차단 경고에 감지되지 않습니다.
// @description:nl Sla YouTube-advertenties direct automatisch over. Ongemerkt door YouTube-adblockerwaarschuwingen.
// @description:pt-BR Pule anúncios do YouTube instantaneamente. Não detectado pelos avisos do bloqueador de anúncios do YouTube.
// @description:ru Автоматически пропускать рекламу YouTube мгновенно. Не обнаруживается предупреждениями блокировщиков рекламы YouTube.
// @description:vi Tự động bỏ qua quảng cáo YouTube ngay lập tức. Không bị phát hiện bởi cảnh báo trình chặn quảng cáo của YouTube.
// @description:zh-CN 立即自动跳过 YouTube 广告。不会被 YouTube 广告拦截器警告检测到。
// @description:zh-TW 立即自動跳過 YouTube 廣告。 YouTube 廣告攔截器警告未被偵測到。
// @author tientq64
// @icon https://cdn-icons-png.flaticon.com/64/2504/2504965.png
// @match https://www.youtube.com/*
// @match https://m.youtube.com/*
// @match https://music.youtube.com/*
// @exclude https://studio.youtube.com/*
// @grant none
// @license MIT
// @compatible firefox
// @compatible chrome
// @compatible opera
// @compatible safari
// @compatible edge
// @noframes
// @homepage https://github.com/tientq64/userscripts/tree/main/scripts/Auto-Skip-YouTube-Ads
// ==/UserScript==
function skipAd() {
if (checkIsYouTubeShorts()) return
// This element appears when a video ad appears.
const adShowing = document.querySelector('.ad-showing')
// Timed pie countdown ad.
const pieCountdown = document.querySelector('.ytp-ad-timed-pie-countdown-container')
// Survey questions in video player.
const surveyQuestions = document.querySelector('.ytp-ad-survey-questions')
if (adShowing === null && pieCountdown === null && surveyQuestions === null) return
let playerEl
let player
if (isYouTubeMobile || isYouTubeMusic) {
playerEl = document.querySelector('#movie_player')
player = playerEl
} else {
playerEl = document.querySelector('#ytd-player')
player = playerEl && playerEl.getPlayer()
}
if (playerEl === null || player === null) {
console.log({
message: 'Player not found',
timeStamp: getCurrentTimeString()
})
return
}
// ad.classList.remove('ad-showing')
let adVideo = null
if (pieCountdown === null && surveyQuestions === null) {
adVideo = document.querySelector(
'#ytd-player video.html5-main-video, #song-video video.html5-main-video'
)
console.table({
message: 'Ad video',
video: adVideo !== null,
src: adVideo?.src,
paused: adVideo?.paused,
currentTime: adVideo?.currentTime,
duration: adVideo?.duration,
timeStamp: getCurrentTimeString()
})
if (adVideo === null || !adVideo.src || adVideo.paused || isNaN(adVideo.duration)) return
console.log({
message: 'Ad video has finished loading',
timeStamp: getCurrentTimeString()
})
}
if (isYouTubeMusic && adVideo !== null) {
adVideo.currentTime = adVideo.duration
console.table({
message: 'Ad skipped',
timeStamp: getCurrentTimeString(),
adShowing: adShowing !== null,
pieCountdown: pieCountdown !== null,
surveyQuestions: surveyQuestions !== null
})
} else {
const videoData = player.getVideoData()
const videoId = videoData.video_id
const start = Math.floor(player.getCurrentTime())
if ('loadVideoWithPlayerVars' in playerEl) {
playerEl.loadVideoWithPlayerVars({ videoId, start })
} else {
playerEl.loadVideoByPlayerVars({ videoId, start })
}
console.table({
message: 'Ad skipped',
videoId,
start,
title: videoData.title,
timeStamp: getCurrentTimeString(),
adShowing: adShowing !== null,
pieCountdown: pieCountdown !== null,
surveyQuestions: surveyQuestions !== null
})
}
}
function checkIsYouTubeShorts() {
return location.pathname.startsWith('/shorts/')
}
function getCurrentTimeString() {
return new Date().toTimeString().split(' ', 1)[0]
}
function addCss() {
const adsSelectors = [
// Ad banner in the upper right corner, above the video playlist.
'#player-ads',
'#panels > ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]',
// Masthead ad on home page.
'#masthead-ad',
// Sponsored ad video items on home page.
// 'ytd-ad-slot-renderer',
// '.ytp-suggested-action',
'.yt-mealbar-promo-renderer',
// Featured product ad banner at the bottom left of the video.
'.ytp-featured-product',
// Products shelf ad banner below the video description.
'ytd-merch-shelf-renderer',
// YouTube Music Premium trial promotion dialog, bottom left corner.
'ytmusic-mealbar-promo-renderer',
// YouTube Music Premium trial promotion banner on home page.
'ytmusic-statement-banner-renderer'
]
const adsSelector = adsSelectors.join(',')
const css = `${adsSelector} { display: none !important; }`
const style = document.createElement('style')
style.textContent = css
document.head.appendChild(style)
}
/**
* Remove ad elements using JavaScript because these selectors require the use of the CSS
* `:has` selector which is not supported in older browser versions.
*/
function removeAdElements() {
const adSelectors = [
// Sponsored ad video items on home page.
// ['ytd-rich-item-renderer', '.ytd-ad-slot-renderer'],
// ['ytd-rich-section-renderer', '.ytd-statement-banner-renderer'],
// Ad videos on YouTube Shorts.
['ytd-reel-video-renderer', '.ytd-ad-slot-renderer']
// Ad blocker warning dialog.
// ['tp-yt-paper-dialog', '#feedback.ytd-enforcement-message-view-model'],
// Survey dialog on home page, located at bottom right.
// ['tp-yt-paper-dialog', ':scope > ytd-checkbox-survey-renderer'],
// Survey to rate suggested content, located at bottom right.
// ['tp-yt-paper-dialog', ':scope > ytd-single-option-survey-renderer']
]
for (const adSelector of adSelectors) {
const adEl = document.querySelector(adSelector[0])
if (adEl === null) continue
const neededEl = adEl.querySelector(adSelector[1])
if (neededEl === null) continue
adEl.remove()
}
}
const isYouTubeMobile = location.hostname === 'm.youtube.com'
const isYouTubeMusic = location.hostname === 'music.youtube.com'
const isYouTubeDesktop = !isYouTubeMobile && !isYouTubeMusic
const isYouTubeVideo = isYouTubeMobile || isYouTubeDesktop
addCss()
if (isYouTubeVideo) {
window.setInterval(removeAdElements, 1000)
removeAdElements()
}
window.setInterval(skipAd, 500)
skipAd()
// const observer = new MutationObserver(skipAd)
// observer.observe(document.body, {
// attributes: true,
// attributeFilter: ['class'],
// childList: true,
// subtree: true
// })