diff --git a/.resources/global.d.ts b/.resources/global.d.ts
index 1b72fe7..ab9c2c9 100644
--- a/.resources/global.d.ts
+++ b/.resources/global.d.ts
@@ -69,5 +69,6 @@ interface YouTubeVideoData {
video_id: string
}
-declare type TrustedTypePolicyFactory = import('trusted-types/lib').TrustedTypePolicyFactory
-declare const trustedTypes: TrustedTypePolicyFactory
+interface YouTubeMoviePlayerElement extends HTMLElement {
+ loadVideoByPlayerVars(options: { videoId: string; start?: number }): void
+}
diff --git a/package.json b/package.json
index 375ed01..d0ea677 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,6 @@
"@types/node": "^20.14.13",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
- "@types/trusted-types": "2.0.7",
"concurrently": "^8.2.2",
"eslint": "8.57.0",
"eslint-plugin-react": "^7.35.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index df8e21c..87cf79a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -45,9 +45,6 @@ importers:
'@types/react-dom':
specifier: 18.3.0
version: 18.3.0
- '@types/trusted-types':
- specifier: 2.0.7
- version: 2.0.7
concurrently:
specifier: ^8.2.2
version: 8.2.2
@@ -357,9 +354,6 @@ packages:
'@types/react@18.3.3':
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
- '@types/trusted-types@2.0.7':
- resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
-
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
@@ -1906,8 +1900,6 @@ snapshots:
'@types/prop-types': 15.7.13
csstype: 3.1.3
- '@types/trusted-types@2.0.7': {}
-
'@types/unist@3.0.3': {}
'@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.6.2))(eslint@8.57.0)(typescript@5.6.2)':
diff --git a/scripts/Auto-Skip-YouTube-Ads/README.md b/scripts/Auto-Skip-YouTube-Ads/README.md
index bbb4e43..27aa020 100644
--- a/scripts/Auto-Skip-YouTube-Ads/README.md
+++ b/scripts/Auto-Skip-YouTube-Ads/README.md
@@ -1,186 +1,192 @@
-## 📰 Introduction
-
-Automatically skip YouTube ads instantly. Undetected by YouTube ad blocker warnings.
-
-立即自动跳过 YouTube 广告。不会被 YouTube 广告拦截器警告检测到。
-
-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.
-
-## 📑 Changelog
-
-### 6.0.2 - 2025-02-02
-
-- Disable some unnecessary CSS.
-
-### 6.0.0 - 2025-01-29
-
-_Happy Lunar New Year!_
-
-- Completely rewritten way to skip ads, more efficient, not detected by YouTube ad blocker warning.
-- New way to skip ads is temporarily not working on YouTube Music.
-
-### 5.3.0 - 2025-01-23
-
-- Supports older browser versions.
-
-### 5.2.0 - 2025-01-21
-
-- Support for **YouTube mobile** version 🎉
-- Revisit fix for issue [#2]: Fully resolved the problem where videos couldn't be paused on mobile. The previous fix was incomplete.
-
-### 5.1.3 - 2025-01-18
-
-- Fix ad skipping issue.
-
-### 5.1.2 - 2025-01-17
-
-- Fix issue [#2] where video can't be paused on mobile.
-
-### 5.1.1 - 2024-12-27
-
-- Hide the survey to rate suggested content, located at bottom right.
-
-### 5.1.0 - 2024-12-26
-
-- Skip pie countdown ads 🎉
-
-### 5.0.0 - 2024-12-25
-
-_Merry Christmas!_
-
-- **No need to reload the page** when there is no way to skip the ad anymore 🤯
-- Configuration removed, no longer needed.
-
-### 4.8.2 - 2024-12-21
-
-- Fix timestamp loss when reloading.
-
-### 4.8.1 - 2024-12-03
-
-- Hide survey dialog on home page.
-
-### 4.8.0 - 2024-11-26
-
-- The current video's timestamp will be preserved when the page is reloaded ([#267857]).
-
-### 4.7.4 - 2024-11-20
-
-- Improved ad skipping.
-
-### 4.7.0 - 2024-10-26
-
-- Add option "Don't reload while the user is busy" in Tampermonkey's menu to avoid reloading page when user is busy doing something, like reading comments, entering text. Enabled by default.
-
-### 4.6.2 - 2024-10-13
-
-- Improve hiding of ad banners.
-
-### 4.6.0 - 2024-10-07
-
-- Support skipping ads on **YouTube Music** (PR [#1]).
-
-### 4.5.2 - 2024-09-30
-
-- Fix Shorts reload infinitely ([#258626], [#259545], [#261679]).
-
-### 4.5.0 - 2024-09-26
-
-- Add option to enable/disable "Reload the page when there is no other way to skip ads" feature in Tampermonkey's menu. Enabled by default.\
- ![Screenshot-001]
-
-### 4.4.0 - 2024-08-30
-
-- Automatically reload web page when ad blocker warnings appear.
-
-### 4.3.13 - 2024-08-26
-
-- Fixed bug where video could not be paused using pause/play key on keyboard or media controls ([#257424]).
-- Improve the performance.
-
-### 4.3.9 - 2024-08-21
-
-- Fix `@match` invalid syntax ([#256841]).
-
-### 4.3.8 - 2024-08-20
-
-- Fix the issue of removing ad videos in Shorts.
-
-### 4.3.6 - 2024-08-07
-
-- Fix bug where video rewinds a segment after skipping an ad ([#254113]).
-
-### 4.3.4 - 2024-08-02
-
-- Improve the performance.
-
-### 4.2.1 - 2024-07-30
-
-- Fixed video automatically replay when ended.
-
-### 4.2.0 - 2024-07-30
-
-- Videos will now no longer occasionally pause due to ad blocker use.
-- Faster ad video skipping speed.
-
-### 4.1.0 - 2024-07-10
-
-- No need to reload the page when the ad blocker warning dialog appears.
-
-### 4.0.0 - 2024-07-09
-
-- The page will now reload if an ad blocker warning dialog appears. Because YouTube now pauses the video at first if an ad blocker is detected.
-- Write to the Console every time skip an ad video, etc. Purpose to help debug. To open the Console, press `Ctrl+Shift+J`.
-
-### 3.1.2 - 2024-07-06
-
-- Playing video after clicking dismiss the ad blocker warning popup.
-
-### 3.1.1 - 2024-07-04
-
-- Add a few CSS that hides the ads.
-
-### 3.1.0 - 2024-07-02
-
-- Skip ads faster when the tab is active.
-- Fixed bug when set time to end of ad video without the video duration being available.
-- Change icon.
-
-### 3.0.2 - 2024-06-28
-
-- Rewriting to only use `setInterval` simplifies things, and fix some bugs.
-
-### 2.1.3 - 2024-06-21
-
-- Fix `popupContainer` not found error.
-
-### 2.1.0 - 2024-06-20
-
-- Auto close YouTube's ad blocker warning popup.
-
-### 2.0.1 - 2024-06-19
-
-- Improved skip ad button detection.
-- Fall back to `setInterval` when `MutationObserver` is not supported.
-
-### 2.0.0 - 2024-06-18
-
-- Rewrite the entire code, use `MutationObserver` instead of `setInterval`.
-
-### 1.0.0 - 2024-06-17
-
-- Stable release.
-
-## 💳 Credits
-
-Youtube icons created by Ruslan Babkin - Flaticon.
-
-[#2]: https://github.com/tientq64/userscripts/issues/2
-[#267857]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/267857
-[#258626]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/258626
-[#259545]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/259545
-[#261679]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/261679
-[#257424]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/257424
-[#256841]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/256841
-[#254113]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/254113
-[#1]: https://github.com/tientq64/userscripts/pull/1
-[Screenshot-001]: https://cdn.jsdelivr.net/gh/tientq64/userscripts/scripts/Auto-Skip-YouTube-Ads/assets/screenshot-001.png
+## 📰 Introduction
+
+Automatically skip YouTube ads instantly. Undetected by YouTube ad blocker warnings.
+
+立即自动跳过 YouTube 广告。不会被 YouTube 广告拦截器警告检测到。
+
+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.
+
+## 📑 Changelog
+
+### 7.0.0 - 2025-02-15
+
+- Version 6 had many bug reports, reverting to the previous version 5 ([#6], [#279168]).
+
+### 6.0.2 - 2025-02-02
+
+- Disable some unnecessary CSS.
+
+### 6.0.0 - 2025-01-29
+
+_Happy Lunar New Year!_
+
+- Completely rewritten way to skip ads, more efficient, not detected by YouTube ad blocker warning.
+- New way to skip ads is temporarily not working on YouTube Music.
+
+### 5.3.0 - 2025-01-23
+
+- Supports older browser versions.
+
+### 5.2.0 - 2025-01-21
+
+- Support for **YouTube mobile** version 🎉
+- Revisit fix for issue [#2]: Fully resolved the problem where videos couldn't be paused on mobile. The previous fix was incomplete.
+
+### 5.1.3 - 2025-01-18
+
+- Fix ad skipping issue.
+
+### 5.1.2 - 2025-01-17
+
+- Fix issue [#2] where video can't be paused on mobile.
+
+### 5.1.1 - 2024-12-27
+
+- Hide the survey to rate suggested content, located at bottom right.
+
+### 5.1.0 - 2024-12-26
+
+- Skip pie countdown ads 🎉
+
+### 5.0.0 - 2024-12-25
+
+_Merry Christmas!_
+
+- **No need to reload the page** when there is no way to skip the ad anymore 🤯
+- Configuration removed, no longer needed.
+
+### 4.8.2 - 2024-12-21
+
+- Fix timestamp loss when reloading.
+
+### 4.8.1 - 2024-12-03
+
+- Hide survey dialog on home page.
+
+### 4.8.0 - 2024-11-26
+
+- The current video's timestamp will be preserved when the page is reloaded ([#267857]).
+
+### 4.7.4 - 2024-11-20
+
+- Improved ad skipping.
+
+### 4.7.0 - 2024-10-26
+
+- Add option "Don't reload while the user is busy" in Tampermonkey's menu to avoid reloading page when user is busy doing something, like reading comments, entering text. Enabled by default.
+
+### 4.6.2 - 2024-10-13
+
+- Improve hiding of ad banners.
+
+### 4.6.0 - 2024-10-07
+
+- Support skipping ads on **YouTube Music** (PR [#1]).
+
+### 4.5.2 - 2024-09-30
+
+- Fix Shorts reload infinitely ([#258626], [#259545], [#261679]).
+
+### 4.5.0 - 2024-09-26
+
+- Add option to enable/disable "Reload the page when there is no other way to skip ads" feature in Tampermonkey's menu. Enabled by default.\
+ ![Screenshot-001]
+
+### 4.4.0 - 2024-08-30
+
+- Automatically reload web page when ad blocker warnings appear.
+
+### 4.3.13 - 2024-08-26
+
+- Fixed bug where video could not be paused using pause/play key on keyboard or media controls ([#257424]).
+- Improve the performance.
+
+### 4.3.9 - 2024-08-21
+
+- Fix `@match` invalid syntax ([#256841]).
+
+### 4.3.8 - 2024-08-20
+
+- Fix the issue of removing ad videos in Shorts.
+
+### 4.3.6 - 2024-08-07
+
+- Fix bug where video rewinds a segment after skipping an ad ([#254113]).
+
+### 4.3.4 - 2024-08-02
+
+- Improve the performance.
+
+### 4.2.1 - 2024-07-30
+
+- Fixed video automatically replay when ended.
+
+### 4.2.0 - 2024-07-30
+
+- Videos will now no longer occasionally pause due to ad blocker use.
+- Faster ad video skipping speed.
+
+### 4.1.0 - 2024-07-10
+
+- No need to reload the page when the ad blocker warning dialog appears.
+
+### 4.0.0 - 2024-07-09
+
+- The page will now reload if an ad blocker warning dialog appears. Because YouTube now pauses the video at first if an ad blocker is detected.
+- Write to the Console every time skip an ad video, etc. Purpose to help debug. To open the Console, press `Ctrl+Shift+J`.
+
+### 3.1.2 - 2024-07-06
+
+- Playing video after clicking dismiss the ad blocker warning popup.
+
+### 3.1.1 - 2024-07-04
+
+- Add a few CSS that hides the ads.
+
+### 3.1.0 - 2024-07-02
+
+- Skip ads faster when the tab is active.
+- Fixed bug when set time to end of ad video without the video duration being available.
+- Change icon.
+
+### 3.0.2 - 2024-06-28
+
+- Rewriting to only use `setInterval` simplifies things, and fix some bugs.
+
+### 2.1.3 - 2024-06-21
+
+- Fix `popupContainer` not found error.
+
+### 2.1.0 - 2024-06-20
+
+- Auto close YouTube's ad blocker warning popup.
+
+### 2.0.1 - 2024-06-19
+
+- Improved skip ad button detection.
+- Fall back to `setInterval` when `MutationObserver` is not supported.
+
+### 2.0.0 - 2024-06-18
+
+- Rewrite the entire code, use `MutationObserver` instead of `setInterval`.
+
+### 1.0.0 - 2024-06-17
+
+- Stable release.
+
+## 💳 Credits
+
+Youtube icons created by Ruslan Babkin - Flaticon.
+
+[#6]: https://github.com/tientq64/userscripts/issues/6
+[#2]: https://github.com/tientq64/userscripts/issues/2
+[#1]: https://github.com/tientq64/userscripts/pull/1
+[#279168]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/279168
+[#267857]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/267857
+[#261679]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/261679
+[#259545]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/259545
+[#258626]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/258626
+[#257424]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/257424
+[#256841]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/256841
+[#254113]: https://greasyfork.org/scripts/498197-auto-skip-youtube-ads/discussions/254113
+[Screenshot-001]: https://cdn.jsdelivr.net/gh/tientq64/userscripts/scripts/Auto-Skip-YouTube-Ads/assets/screenshot-001.png
diff --git a/scripts/Auto-Skip-YouTube-Ads/script.user.js b/scripts/Auto-Skip-YouTube-Ads/script.user.js
index 08a9b3b..feebd61 100644
--- a/scripts/Auto-Skip-YouTube-Ads/script.user.js
+++ b/scripts/Auto-Skip-YouTube-Ads/script.user.js
@@ -1,38 +1,35 @@
// ==UserScript==
// @name Auto Skip YouTube Ads
-// @name:ar تخطي إعلانات YouTube تلقائيًا
+// @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 6.0.4
-// @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 廣告攔截器警告未被偵測到。
+// @version 7.0.0
+// @description Automatically skip YouTube ads almost instantly. Remove the ad blocker warning pop-up.
+// @description:ar تخطي إعلانات YouTube تلقائيًا في الحال. إزالة النافذة المنبثقة لتحذير مانع الإعلانات.
+// @description:es Omite automáticamente los anuncios de YouTube casi al instante. Elimina la ventana emergente de advertencia del bloqueador de anuncios.
+// @description:hi YouTube विज्ञापनों को लगभग तुरंत ही स्वचालित रूप से छोड़ दें। विज्ञापन अवरोधक चेतावनी पॉप-अप हटाएँ।
+// @description:id Lewati iklan YouTube secara otomatis hampir seketika. Hapus pop-up peringatan pemblokir iklan.
+// @description:ja YouTube 広告をほぼ瞬時に自動的にスキップします。広告ブロッカーの警告ポップアップを削除します。
+// @description:ko YouTube 광고를 거의 즉시 자동으로 건너뜁니다. 광고 차단 경고 팝업을 제거합니다.
+// @description:pt-BR Pule automaticamente os anúncios do YouTube quase instantaneamente. Remova o pop-up de aviso do bloqueador de anúncios.
+// @description:ru Автоматически пропускайте рекламу YouTube почти мгновенно. Уберите всплывающее предупреждение о блокировщике рекламы.
+// @description:vi Tự động bỏ qua quảng cáo YouTube gần như ngay lập tức. Loại bỏ cửa sổ bật lên cảnh báo trình chặn quảng cáo.
+// @description:zh-CN 几乎立即自动跳过 YouTube 广告。删除广告拦截器警告弹出窗口。
+// @description:zh-TW 幾乎立即自動跳過 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/*
// @grant none
// @license MIT
// @compatible firefox
@@ -44,90 +41,253 @@
// @homepage https://github.com/tientq64/userscripts/tree/main/scripts/Auto-Skip-YouTube-Ads
// ==/UserScript==
+/**
+ * Skip ads. Remove ad elements.
+ */
function skipAd() {
- const isYouTubeShorts = checkIsYouTubeShorts()
- if (isYouTubeShorts) return
+ removeAdElements()
- const ad = getInterruptiveAd()
- if (ad === null) return
+ video = null
+ fineScrubber = document.querySelector('.ytp-fine-scrubbing')
- let playerEl
- let player
- if (isYouTubeMobile) {
- playerEl = document.querySelector('#movie_player')
- player = playerEl
- } else {
- playerEl = document.querySelector('#ytd-player')
- player = playerEl && playerEl.getPlayer()
+ // Check if the current URL is a YouTube Shorts URL and exit the function if true.
+ if (window.location.pathname.startsWith('/shorts/')) return
+
+ const moviePlayer = document.querySelector('#movie_player')
+
+ if (moviePlayer) {
+ hasAd = moviePlayer.classList.contains('ad-showing')
+ video = moviePlayer.querySelector('video.html5-main-video')
}
- if (playerEl === null || player === null) return
- // ad.classList.remove('ad-showing')
+ if (hasAd) {
+ const skipButton = document.querySelector(`
+ .ytp-skip-ad-button,
+ .ytp-ad-skip-button,
+ .ytp-ad-skip-button-modern,
+ .ytp-ad-survey-answer-button
+ `)
+ // Click the skip ad button if available.
+ if (skipButton) {
+ skipButton.click()
+ skipButton.remove()
+ }
+ // Otherwise, fast forward to the end of the ad video.
+ // Use `9999` instead of `video.duration` to avoid errors when `duration` is not a number.
+ else if (video && video.src) {
+ video.currentTime = 9999
+ }
+ }
- const videoData = player.getVideoData()
- const videoId = videoData.video_id
- const start = Math.floor(player.getCurrentTime())
+ if (video) {
+ video.addEventListener('pause', handleVideoPause)
+ video.addEventListener('pointerup', allowPauseVideo)
+ video.addEventListener('timeupdate', handleVideoTimeUpdate)
+ }
- if ('loadVideoWithPlayerVars' in playerEl) {
- playerEl.loadVideoWithPlayerVars({ videoId, start })
- } else {
- playerEl.loadVideoByPlayerVars({ videoId, start })
+ // Timed pie countdown ad.
+ const pieCountdown = document.querySelector('.ytp-ad-timed-pie-countdown-container')
+ if (pieCountdown) {
+ pieCountdown.remove()
+ replaceCurrentVideo()
}
- console.log('Ad skipped!', videoId, start, videoData.title)
+ // Handle when ad blocker warning appears inside video player.
+ const adBlockerWarningInner = document.querySelector(
+ '.yt-playability-error-supported-renderers'
+ )
+ if (adBlockerWarningInner) {
+ adBlockerWarningInner.remove()
+ document.addEventListener('yt-navigate-finish', handleYouTubeNavigateFinish)
+ replaceCurrentVideo()
+ }
+
+ // Video play/pause button.
+ const playButton = document.querySelector(
+ 'button.ytp-play-button, button.player-control-play-pause-icon'
+ )
+ if (playButton) {
+ playButton.addEventListener('click', allowPauseVideo)
+ }
}
-function getInterruptiveAd() {
- // This element appears when a video ad appears.
- const adShowing = document.querySelector('.ad-showing')
- if (adShowing !== null) return adShowing
+function queryHasSelector(selector, hasSelector, element = document) {
+ const el = element.querySelector(selector)
+ if (el === null) return null
+ const hasEl = el.querySelector(hasSelector)
+ if (hasEl === null) return null
+ return el
+}
- // Timed pie countdown ad.
- const pieCountdown = document.querySelector('.ytp-ad-timed-pie-countdown-container')
- if (pieCountdown !== null) return pieCountdown
+function queryHasSelectorAll(selector, hasSelector, element = document) {
+ const els = element.querySelectorAll(selector)
+ const result = []
+ for (const el of els) {
+ const hasEl = el.querySelector(hasSelector)
+ if (hasEl === null) continue
+ result.push(el)
+ }
+ return result
+}
+
+function getCurrentVideoId() {
+ const params = new URLSearchParams(location.search)
+ const videoId = params.get('v')
+ return videoId
+}
+
+/**
+ * Check if the user is focused on the input.
+ */
+function checkEnteringInput() {
+ if (document.activeElement === null) {
+ return false
+ }
+ return document.activeElement.matches('input, textarea, select')
+}
+
+/**
+ * Temporarily allows the video to be paused, for a short period of time.
+ */
+function allowPauseVideo() {
+ pausedByUser = true
+ window.clearTimeout(allowPauseVideoTimeoutId)
+ allowPauseVideoTimeoutId = window.setTimeout(disallowPauseVideo, 500)
+}
+
+/**
+ * Pausing the video is not allowed. The purpose is to prevent video from being paused,
+ * against the behavior of pausing video when YouTube ad blocking warning dialog appears.
+ * Unless certain conditions, such as pausing by user, etc.
+ */
+function disallowPauseVideo() {
+ pausedByUser = false
+ window.clearTimeout(allowPauseVideoTimeoutId)
+}
+
+function handleWindowBlur() {
+ isTabBlurred = true
+}
+
+function handleWindowFocus() {
+ isTabBlurred = false
+}
+
+/**
+ * Handle when video is paused. If certain conditions are not met, it will continue
+ * playing. Returning early in this function means the video should be paused as it should
+ * be.
+ */
+function handleVideoPause() {
+ if (isYouTubeMusic) return
+
+ // If it was stopped by the user, it's ok, let the video pause as it should, and exit the function.
+ if (pausedByUser) {
+ disallowPauseVideo()
+ return
+ }
- return null
+ // The video will pause normally if the tab is not focused. This is to allow for pausing the video via the media controller (of the browser or operating system), etc.
+ // Note: While this also gives YouTube the opportunity to pause videos to annoy users, it's an acceptable trade-off.
+ if (document.hidden) return
+ if (isTabBlurred) return
+
+ if (fineScrubber && fineScrubber.style.display !== 'none') return
+ if (video === null) return
+ if (video.duration - video.currentTime < 0.1) return
+
+ // This is YouTube's disruptive behavior towards users, so the video should continue to play as normal.
+ video.play()
}
-function checkIsYouTubeShorts() {
- return location.pathname.startsWith('/shorts/')
+function handleVideoTimeUpdate() {
+ if (hasAd || video === null) return
+ currentVideoTime = video.currentTime
}
+/**
+ * Handle both keyboard press or release events.
+ */
+function handleWindowKeyDownAndKeyUp(event) {
+ if (isYouTubeMusic) return
+ if (checkEnteringInput()) return
+ const code = event.code
+ if (event.type === 'keydown') {
+ if (code === 'KeyK' || code === 'MediaPlayPause') {
+ allowPauseVideo()
+ }
+ } else {
+ if (code === 'Space') {
+ allowPauseVideo()
+ }
+ }
+}
+
+function handleYouTubeNavigateFinish() {
+ currentVideoTime = 0
+ replaceCurrentVideo()
+}
+
+async function replaceCurrentVideo() {
+ const start = Math.floor(currentVideoTime)
+ for (let i = 0; i < 16; i++) {
+ await waitFor(500)
+ const videoId = getCurrentVideoId()
+ if (!videoId || !video || video.src) continue
+ if (isYouTubeMobile) {
+ const player = document.querySelector('#movie_player')
+ if (!player) continue
+ player.loadVideoByPlayerVars({ videoId, start })
+ } else {
+ const player = document.querySelector('#ytd-player')
+ if (!player) continue
+ player.loadVideoWithPlayerVars({ videoId, start })
+ }
+ }
+}
+
+function waitFor(millis) {
+ return new Promise((resolve) => {
+ window.setTimeout(resolve, millis)
+ })
+}
+
+/**
+ * Add CSS hides some ad elements on the page.
+ */
function addCss() {
- const adsSelectors = [
+ const hideCssSelector = [
// Ad banner in the upper right corner, above the video playlist.
'#player-ads',
// Masthead ad on home page.
'#masthead-ad',
- // Sponsored ad video items on home page.
- // 'ytd-ad-slot-renderer',
+ 'ytd-ad-slot-renderer',
- // '.ytp-suggested-action',
- '.yt-mealbar-promo-renderer',
+ // Ad blocker warning inside the player.
+ 'yt-playability-error-supported-renderers#error-screen',
- // 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',
+ '.ytp-suggested-action',
+ '.yt-mealbar-promo-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; }`
+ ].join(',')
+ const css = `
+ #ytd-player { visibility: visible !important; }
+ ${hideCssSelector} { 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
+ * 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() {
@@ -135,16 +295,19 @@ function removeAdElements() {
// Ad banner in the upper right corner, above the video playlist.
['#panels', 'ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]'],
+ // Temporarily comment out this selector to fix issue [#265124](https://greasyfork.org/en/scripts/498197-auto-skip-youtube-ads/discussions/265124).
+ // ['#panels', 'ytd-ads-engagement-panel-content-renderer'],
+
// 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 Short.
- ['ytd-reel-video-renderer', '.ytd-ad-slot-renderer']
+ ['ytd-reel-video-renderer', '.ytd-ad-slot-renderer'],
// Ad blocker warning dialog.
- // ['tp-yt-paper-dialog', '#feedback.ytd-enforcement-message-view-model'],
+ ['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'],
@@ -153,19 +316,63 @@ function removeAdElements() {
// ['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 adEls = queryHasSelectorAll(adSelector[0], adSelector[1])
+ for (const adEl of adEls) {
+ adEl.remove()
+ }
}
}
+/**
+ * Is it YouTube mobile version.
+ */
const isYouTubeMobile = location.hostname === 'm.youtube.com'
-window.setInterval(skipAd, 500)
-window.setInterval(removeAdElements, 1000)
+/**
+ * Is the current page YouTube Music.
+ */
+const isYouTubeMusic = location.hostname === 'music.youtube.com'
+
+/**
+ * Current video element.
+ */
+let video = null
+
+let fineScrubber = null
+let hasAd = false
+let currentVideoTime = 0
+
+/**
+ * Is the video paused by the user, not paused by YouTube's ad blocker warning dialog.
+ */
+let pausedByUser = false
+
+/**
+ * Is the current tab blurred.
+ */
+let isTabBlurred = false
+
+let allowPauseVideoTimeoutId = 0
+
+// Observe DOM changes to detect ads.
+if (window.MutationObserver) {
+ const observer = new MutationObserver(skipAd)
+ observer.observe(document.body, {
+ attributes: true,
+ attributeFilter: ['class', 'src'],
+ childList: true,
+ subtree: true
+ })
+}
+// If DOM observation is not supported. Detect ads every 500ms (2 times per second).
+else {
+ window.setInterval(skipAd, 500)
+}
+
+window.addEventListener('blur', handleWindowBlur)
+window.addEventListener('focus', handleWindowFocus)
+window.addEventListener('keydown', handleWindowKeyDownAndKeyUp)
+window.addEventListener('keyup', handleWindowKeyDownAndKeyUp)
addCss()
-removeAdElements()
skipAd()
diff --git a/scripts/Auto-Skip-YouTube-Ads/script.user.ts b/scripts/Auto-Skip-YouTube-Ads/script.user.ts
index a947404..22c5f94 100644
--- a/scripts/Auto-Skip-YouTube-Ads/script.user.ts
+++ b/scripts/Auto-Skip-YouTube-Ads/script.user.ts
@@ -1,38 +1,35 @@
// ==UserScript==
// @name Auto Skip YouTube Ads
-// @name:ar تخطي إعلانات YouTube تلقائيًا
+// @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 6.0.4
-// @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 廣告攔截器警告未被偵測到。
+// @version 7.0.0
+// @description Automatically skip YouTube ads almost instantly. Remove the ad blocker warning pop-up.
+// @description:ar تخطي إعلانات YouTube تلقائيًا في الحال. إزالة النافذة المنبثقة لتحذير مانع الإعلانات.
+// @description:es Omite automáticamente los anuncios de YouTube casi al instante. Elimina la ventana emergente de advertencia del bloqueador de anuncios.
+// @description:hi YouTube विज्ञापनों को लगभग तुरंत ही स्वचालित रूप से छोड़ दें। विज्ञापन अवरोधक चेतावनी पॉप-अप हटाएँ।
+// @description:id Lewati iklan YouTube secara otomatis hampir seketika. Hapus pop-up peringatan pemblokir iklan.
+// @description:ja YouTube 広告をほぼ瞬時に自動的にスキップします。広告ブロッカーの警告ポップアップを削除します。
+// @description:ko YouTube 광고를 거의 즉시 자동으로 건너뜁니다. 광고 차단 경고 팝업을 제거합니다.
+// @description:pt-BR Pule automaticamente os anúncios do YouTube quase instantaneamente. Remova o pop-up de aviso do bloqueador de anúncios.
+// @description:ru Автоматически пропускайте рекламу YouTube почти мгновенно. Уберите всплывающее предупреждение о блокировщике рекламы.
+// @description:vi Tự động bỏ qua quảng cáo YouTube gần như ngay lập tức. Loại bỏ cửa sổ bật lên cảnh báo trình chặn quảng cáo.
+// @description:zh-CN 几乎立即自动跳过 YouTube 广告。删除广告拦截器警告弹出窗口。
+// @description:zh-TW 幾乎立即自動跳過 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/*
// @grant none
// @license MIT
// @compatible firefox
@@ -43,92 +40,263 @@
// @noframes
// ==/UserScript==
+/**
+ * Skip ads. Remove ad elements.
+ */
function skipAd(): void {
- const isYouTubeShorts: boolean = checkIsYouTubeShorts()
- if (isYouTubeShorts) return
-
- const ad: HTMLElement | null = getInterruptiveAd()
- if (ad === null) return
+ removeAdElements()
- let playerEl: YtdPlayerElement | YouTubeMoviePlayerElement | null
- let player: YouTubePlayer | YouTubeMoviePlayerElement | null
- if (isYouTubeMobile) {
- playerEl = document.querySelector('#movie_player')
- player = playerEl
- } else {
- playerEl = document.querySelector('#ytd-player')
- player = playerEl && playerEl.getPlayer()
- }
- if (playerEl === null || player === null) return
+ video = null
+ fineScrubber = document.querySelector('.ytp-fine-scrubbing')
- // ad.classList.remove('ad-showing')
+ // Check if the current URL is a YouTube Shorts URL and exit the function if true.
+ if (window.location.pathname.startsWith('/shorts/')) return
- const videoData: YouTubeVideoData = player.getVideoData()
- const videoId: string = videoData.video_id
- const start: number = Math.floor(player.getCurrentTime())
+ const moviePlayer = document.querySelector('#movie_player')
- if ('loadVideoWithPlayerVars' in playerEl) {
- playerEl.loadVideoWithPlayerVars({ videoId, start })
- } else {
- playerEl.loadVideoByPlayerVars({ videoId, start })
+ if (moviePlayer) {
+ hasAd = moviePlayer.classList.contains('ad-showing')
+ video = moviePlayer.querySelector('video.html5-main-video')
}
- console.log('Ad skipped!', videoId, start, videoData.title)
-}
+ if (hasAd) {
+ const skipButton = document.querySelector(`
+ .ytp-skip-ad-button,
+ .ytp-ad-skip-button,
+ .ytp-ad-skip-button-modern,
+ .ytp-ad-survey-answer-button
+ `)
+ // Click the skip ad button if available.
+ if (skipButton) {
+ skipButton.click()
+ skipButton.remove()
+ }
+ // Otherwise, fast forward to the end of the ad video.
+ // Use `9999` instead of `video.duration` to avoid errors when `duration` is not a number.
+ else if (video && video.src) {
+ video.currentTime = 9999
+ }
+ }
-function getInterruptiveAd(): HTMLElement | null {
- // This element appears when a video ad appears.
- const adShowing = document.querySelector('.ad-showing')
- if (adShowing !== null) return adShowing
+ if (video) {
+ video.addEventListener('pause', handleVideoPause)
+ video.addEventListener('pointerup', allowPauseVideo)
+ video.addEventListener('timeupdate', handleVideoTimeUpdate)
+ }
// Timed pie countdown ad.
const pieCountdown = document.querySelector(
'.ytp-ad-timed-pie-countdown-container'
)
- if (pieCountdown !== null) return pieCountdown
+ if (pieCountdown) {
+ pieCountdown.remove()
+ replaceCurrentVideo()
+ }
+
+ // Handle when ad blocker warning appears inside video player.
+ const adBlockerWarningInner = document.querySelector(
+ '.yt-playability-error-supported-renderers'
+ )
+ if (adBlockerWarningInner) {
+ adBlockerWarningInner.remove()
+ document.addEventListener('yt-navigate-finish', handleYouTubeNavigateFinish)
+ replaceCurrentVideo()
+ }
+
+ // Video play/pause button.
+ const playButton = document.querySelector(
+ 'button.ytp-play-button, button.player-control-play-pause-icon'
+ )
+ if (playButton) {
+ playButton.addEventListener('click', allowPauseVideo)
+ }
+}
+
+function queryHasSelector(
+ selector: string,
+ hasSelector: string,
+ element: Document | Element = document
+): T | null {
+ const el = element.querySelector(selector)
+ if (el === null) return null
+ const hasEl = el.querySelector(hasSelector)
+ if (hasEl === null) return null
+ return el
+}
+
+function queryHasSelectorAll(
+ selector: string,
+ hasSelector: string,
+ element: Document | Element = document
+): T[] {
+ const els = element.querySelectorAll(selector)
+ const result: T[] = []
+ for (const el of els) {
+ const hasEl = el.querySelector(hasSelector)
+ if (hasEl === null) continue
+ result.push(el)
+ }
+ return result
+}
+
+function getCurrentVideoId(): string | null {
+ const params = new URLSearchParams(location.search)
+ const videoId: string | null = params.get('v')
+ return videoId
+}
+
+/**
+ * Check if the user is focused on the input.
+ */
+function checkEnteringInput(): boolean {
+ if (document.activeElement === null) {
+ return false
+ }
+ return document.activeElement.matches('input, textarea, select')
+}
+
+/**
+ * Temporarily allows the video to be paused, for a short period of time.
+ */
+function allowPauseVideo(): void {
+ pausedByUser = true
+ window.clearTimeout(allowPauseVideoTimeoutId)
+ allowPauseVideoTimeoutId = window.setTimeout(disallowPauseVideo, 500)
+}
+
+/**
+ * Pausing the video is not allowed. The purpose is to prevent video from being paused,
+ * against the behavior of pausing video when YouTube ad blocking warning dialog appears.
+ * Unless certain conditions, such as pausing by user, etc.
+ */
+function disallowPauseVideo(): void {
+ pausedByUser = false
+ window.clearTimeout(allowPauseVideoTimeoutId)
+}
+
+function handleWindowBlur(): void {
+ isTabBlurred = true
+}
+
+function handleWindowFocus(): void {
+ isTabBlurred = false
+}
+
+/**
+ * Handle when video is paused. If certain conditions are not met, it will continue
+ * playing. Returning early in this function means the video should be paused as it should
+ * be.
+ */
+function handleVideoPause(): void {
+ if (isYouTubeMusic) return
- return null
+ // If it was stopped by the user, it's ok, let the video pause as it should, and exit the function.
+ if (pausedByUser) {
+ disallowPauseVideo()
+ return
+ }
+
+ // The video will pause normally if the tab is not focused. This is to allow for pausing the video via the media controller (of the browser or operating system), etc.
+ // Note: While this also gives YouTube the opportunity to pause videos to annoy users, it's an acceptable trade-off.
+ if (document.hidden) return
+ if (isTabBlurred) return
+
+ if (fineScrubber && fineScrubber.style.display !== 'none') return
+ if (video === null) return
+ if (video.duration - video.currentTime < 0.1) return
+
+ // This is YouTube's disruptive behavior towards users, so the video should continue to play as normal.
+ video.play()
+}
+
+function handleVideoTimeUpdate(): void {
+ if (hasAd || video === null) return
+ currentVideoTime = video.currentTime
+}
+
+/**
+ * Handle both keyboard press or release events.
+ */
+function handleWindowKeyDownAndKeyUp(event: KeyboardEvent): void {
+ if (isYouTubeMusic) return
+ if (checkEnteringInput()) return
+ const code: string = event.code
+ if (event.type === 'keydown') {
+ if (code === 'KeyK' || code === 'MediaPlayPause') {
+ allowPauseVideo()
+ }
+ } else {
+ if (code === 'Space') {
+ allowPauseVideo()
+ }
+ }
+}
+
+function handleYouTubeNavigateFinish(): void {
+ currentVideoTime = 0
+ replaceCurrentVideo()
+}
+
+async function replaceCurrentVideo(): Promise {
+ const start: number = Math.floor(currentVideoTime)
+ for (let i = 0; i < 16; i++) {
+ await waitFor(500)
+ const videoId: string | null = getCurrentVideoId()
+ if (!videoId || !video || video.src) continue
+ if (isYouTubeMobile) {
+ const player = document.querySelector('#movie_player')
+ if (!player) continue
+ player.loadVideoByPlayerVars({ videoId, start })
+ } else {
+ const player = document.querySelector('#ytd-player')
+ if (!player) continue
+ player.loadVideoWithPlayerVars({ videoId, start })
+ }
+ }
}
-function checkIsYouTubeShorts(): boolean {
- return location.pathname.startsWith('/shorts/')
+function waitFor(millis: number): Promise {
+ return new Promise((resolve) => {
+ window.setTimeout(resolve, millis)
+ })
}
+/**
+ * Add CSS hides some ad elements on the page.
+ */
function addCss(): void {
- const adsSelectors: string[] = [
+ const hideCssSelector: string = [
// Ad banner in the upper right corner, above the video playlist.
'#player-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',
+ 'ytd-ad-slot-renderer',
- // Featured product ad banner at the bottom left of the video.
- '.ytp-featured-product',
+ // Ad blocker warning inside the player.
+ 'yt-playability-error-supported-renderers#error-screen',
- // Products shelf ad banner below the video description.
- 'ytd-merch-shelf-renderer',
+ '.ytp-suggested-action',
+ '.yt-mealbar-promo-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: string = adsSelectors.join(',')
- const css: string = `${adsSelector} { display: none !important; }`
- const style = document.createElement('style')
+ ].join(',')
+ const css: string = `
+ #ytd-player { visibility: visible !important; }
+ ${hideCssSelector} { display: none !important; }
+ `
+ const style: HTMLStyleElement = document.createElement('style')
style.textContent = css
document.head.appendChild(style)
}
/**
- * Remove ad elements using JavaScript because these selectors require the use of the CSS
+ * 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(): void {
@@ -136,16 +304,19 @@ function removeAdElements(): void {
// Ad banner in the upper right corner, above the video playlist.
['#panels', 'ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]'],
+ // Temporarily comment out this selector to fix issue [#265124](https://greasyfork.org/en/scripts/498197-auto-skip-youtube-ads/discussions/265124).
+ // ['#panels', 'ytd-ads-engagement-panel-content-renderer'],
+
// 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 Short.
- ['ytd-reel-video-renderer', '.ytd-ad-slot-renderer']
+ ['ytd-reel-video-renderer', '.ytd-ad-slot-renderer'],
// Ad blocker warning dialog.
- // ['tp-yt-paper-dialog', '#feedback.ytd-enforcement-message-view-model'],
+ ['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'],
@@ -154,19 +325,63 @@ function removeAdElements(): void {
// ['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 adEls = queryHasSelectorAll(adSelector[0], adSelector[1])
+ for (const adEl of adEls) {
+ adEl.remove()
+ }
}
}
+/**
+ * Is it YouTube mobile version.
+ */
const isYouTubeMobile: boolean = location.hostname === 'm.youtube.com'
-window.setInterval(skipAd, 500)
-window.setInterval(removeAdElements, 1000)
+/**
+ * Is the current page YouTube Music.
+ */
+const isYouTubeMusic: boolean = location.hostname === 'music.youtube.com'
+
+/**
+ * Current video element.
+ */
+let video: HTMLVideoElement | null = null
+
+let fineScrubber: HTMLDivElement | null = null
+let hasAd: boolean = false
+let currentVideoTime: number = 0
+
+/**
+ * Is the video paused by the user, not paused by YouTube's ad blocker warning dialog.
+ */
+let pausedByUser: boolean = false
+
+/**
+ * Is the current tab blurred.
+ */
+let isTabBlurred: boolean = false
+
+let allowPauseVideoTimeoutId: number = 0
+
+// Observe DOM changes to detect ads.
+if (window.MutationObserver) {
+ const observer: MutationObserver = new MutationObserver(skipAd)
+ observer.observe(document.body, {
+ attributes: true,
+ attributeFilter: ['class', 'src'],
+ childList: true,
+ subtree: true
+ })
+}
+// If DOM observation is not supported. Detect ads every 500ms (2 times per second).
+else {
+ window.setInterval(skipAd, 500)
+}
+
+window.addEventListener('blur', handleWindowBlur)
+window.addEventListener('focus', handleWindowFocus)
+window.addEventListener('keydown', handleWindowKeyDownAndKeyUp)
+window.addEventListener('keyup', handleWindowKeyDownAndKeyUp)
addCss()
-removeAdElements()
skipAd()