自动跳过 YouTube 广告 by DarkShadow44

立即自动跳过 YouTube 广告。不会被 YouTube 广告拦截器警告检测到。由 DarkShadow44 增强。

  1. // ==UserScript==
  2. // @name Youtube Ads BYPASSER👻
  3. // @name:ar تخطي إعلانات YouTube تلقائيًا بواسطة DarkShadow44
  4. // @name:es Saltar Automáticamente Anuncios De YouTube por DarkShadow44
  5. // @name:fr Ignorer Automatiquement Les Publicités YouTube par DarkShadow44
  6. // @name:hi YouTube विज्ञापन स्वचालित रूप से छोड़ें DarkShadow44 द्वारा
  7. // @name:id Lewati Otomatis Iklan YouTube oleh DarkShadow44
  8. // @name:ja YouTube 広告を自動スキップ by DarkShadow44
  9. // @name:ko YouTube 광고 자동 건너뛰기 by DarkShadow44
  10. // @name:nl YouTube-Advertenties Automatisch Overslaan door DarkShadow44
  11. // @name:pt-BR Pular Automaticamente Anúncios Do YouTube por DarkShadow44
  12. // @name:ru Автоматический Пропуск Рекламы На YouTube от DarkShadow44
  13. // @name:vi Tự Động Bỏ Qua Quảng Cáo YouTube bởi DarkShadow44
  14. // @name:zh-CN 自动跳过 YouTube 广告 by DarkShadow44
  15. // @name:zh-TW 自動跳過 YouTube 廣告 by DarkShadow44
  16. // @namespace https://github.com/DarkShadow44/userscripts
  17. // @version 7.2.3
  18. // @description Automatically skip YouTube ads instantly. Undetected by YouTube ad blocker warnings. Created by DarkShadow44.
  19. // @description:ar تخطي إعلانات YouTube تلقائيًا على الفور. دون أن يتم اكتشاف ذلك من خلال تحذيرات أداة حظر الإعلانات في YouTube. مُحسَّن بواسطة DarkShadow44.
  20. // @description:es Omite automáticamente los anuncios de YouTube al instante. Sin que te detecten las advertencias del bloqueador de anuncios de YouTube. Mejorado por DarkShadow44.
  21. // @description:fr Ignorez automatiquement et instantanément les publicités YouTube. Non détecté par les avertissements du bloqueur de publicités YouTube. Amélioré par DarkShadow44.
  22. // @description:hi YouTube विज्ञापनों को स्वचालित रूप से तुरंत छोड़ दें। YouTube विज्ञापन अवरोधक चेतावनियों द्वारा पता नहीं लगाया गया। DarkShadow44 द्वारा संवर्धित।
  23. // @description:id Lewati iklan YouTube secara otomatis secara instan. Tidak terdeteksi oleh peringatan pemblokir iklan YouTube. Ditingkatkan oleh DarkShadow44.
  24. // @description:ja YouTube 広告を即座に自動的にスキップします。YouTube 広告ブロッカーの警告には検出されません。DarkShadow44 によって強化されました。
  25. // @description:ko YouTube 광고를 즉시 자동으로 건너뜁니다. YouTube 광고 차단 경고에 감지되지 않습니다. DarkShadow44에 의해 향상되었습니다.
  26. // @description:nl Sla YouTube-advertenties direct automatisch over. Ongemerkt door YouTube-adblockerwaarschuwingen. Verbeterd door DarkShadow44.
  27. // @description:pt-BR Pule anúncios do YouTube instantaneamente. Não detectado pelos avisos do bloqueador de anúncios do YouTube. Aprimorado por DarkShadow44.
  28. // @description:ru Автоматически пропускать рекламу YouTube мгновенно. Не обнаруживается предупреждениями блокировщиков рекламы YouTube. Улучшено DarkShadow44.
  29. // @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. Được cải tiến bởi DarkShadow44.
  30. // @description:zh-CN 立即自动跳过 YouTube 广告。不会被 YouTube 广告拦截器警告检测到。由 DarkShadow44 增强。
  31. // @description:zh-TW 立即自動跳過 YouTube 廣告。 YouTube 廣告攔 chặn器警告未被偵測到。由 DarkShadow44 增強。
  32. // @author DarkShadow44
  33. // @icon https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRBLAC4_sqnWL80QVwS35yIcoMOOOz4Z63TcM9tyE977As_mXuzVqhitmPMZCrEF-CW74I&usqp=CAU
  34. // @match https://www.youtube.com/*
  35. // @match https://m.youtube.com/*
  36. // @match https://music.youtube.com/*
  37. // @exclude https://studio.youtube.com/*
  38. // @grant none
  39. // @license MIT
  40. // @compatible firefox
  41. // @compatible chrome
  42. // @compatible opera
  43. // @compatible safari
  44. // @compatible edge
  45. // @noframes
  46. // @homepage https://github.com/DarkShadow44/userscripts/tree/main/scripts/Auto-Skip-YouTube-Ads-Enhanced
  47. // ==/UserScript==
  48.  
  49. // --- START: DarkShadow44 Popup Enhancement ---
  50. let darkShadowPopupDisplayed = false;
  51.  
  52. function showDarkShadowPopup() {
  53. if (darkShadowPopupDisplayed || document.getElementById('darkshadow-popup')) {
  54. return; // Popup already shown or exists
  55. }
  56.  
  57. const popup = document.createElement('div');
  58. popup.id = 'darkshadow-popup';
  59. popup.style.position = 'fixed';
  60. popup.style.bottom = '20px';
  61. popup.style.right = '20px';
  62. popup.style.padding = '15px 20px';
  63. popup.style.backgroundColor = '#282c34'; // Dark background
  64. popup.style.color = '#61dafb'; // Light blue text
  65. popup.style.border = '2px solid #61dafb';
  66. popup.style.borderRadius = '8px';
  67. popup.style.zIndex = '99999';
  68. popup.style.fontSize = '14px';
  69. popup.style.fontFamily = 'Arial, sans-serif';
  70. popup.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
  71. popup.innerHTML = 'Ads Bypasser by DarkShadow44 <span id="darkshadow-popup-close" style="cursor:pointer; margin-left:15px; font-weight:bold; color: #ff6b6b;">×</span>';
  72.  
  73. document.body.appendChild(popup);
  74. darkShadowPopupDisplayed = true;
  75.  
  76. document.getElementById('darkshadow-popup-close').addEventListener('click', () => {
  77. popup.remove();
  78. });
  79.  
  80. // Auto-hide after 7 seconds
  81. setTimeout(() => {
  82. if (document.getElementById('darkshadow-popup')) {
  83. document.getElementById('darkshadow-popup').remove();
  84. }
  85. }, 7000);
  86. }
  87.  
  88. // Method 1: DOMContentLoaded
  89. document.addEventListener('DOMContentLoaded', () => {
  90. if (document.body) showDarkShadowPopup();
  91. });
  92.  
  93. // Method 2: window.onload
  94. window.addEventListener('load', () => {
  95. if (document.body) showDarkShadowPopup();
  96. });
  97.  
  98. // Method 3 & 4: setTimeout fallbacks
  99. setTimeout(() => {
  100. if (document.body) showDarkShadowPopup();
  101. }, 500);
  102. setTimeout(() => {
  103. if (document.body) showDarkShadowPopup();
  104. }, 1500);
  105.  
  106. // Method 5: MutationObserver
  107. const dsObserverOptions = { childList: true, subtree: true };
  108. const dsObserverCallback = function(mutationsList, observer) {
  109. if (!darkShadowPopupDisplayed && document.body) {
  110. showDarkShadowPopup();
  111. // If popup is now displayed, we can disconnect this observer
  112. // or keep it if the body might be cleared and popup needs to be re-added
  113. if (darkShadowPopupDisplayed) {
  114. observer.disconnect();
  115. }
  116. }
  117. };
  118. const dsPopupObserver = new MutationObserver(dsObserverCallback);
  119.  
  120. // Start observing, ensure body exists
  121. function startDsObserver() {
  122. if (document.body) {
  123. dsPopupObserver.observe(document.body, dsObserverOptions);
  124. // Initial attempt in case observer fires late
  125. showDarkShadowPopup();
  126. } else {
  127. // If body is not yet available, wait for DOMContentLoaded
  128. document.addEventListener('DOMContentLoaded', () => {
  129. if (document.body) {
  130. dsPopupObserver.observe(document.body, dsObserverOptions);
  131. showDarkShadowPopup();
  132. }
  133. });
  134. }
  135. }
  136. startDsObserver();
  137.  
  138. // Additional Fallback: Interval check
  139. let dsPopupAttempts = 0;
  140. const dsPopupInterval = setInterval(() => {
  141. if (document.body && !darkShadowPopupDisplayed) {
  142. showDarkShadowPopup();
  143. }
  144. dsPopupAttempts++;
  145. if (darkShadowPopupDisplayed || dsPopupAttempts > 10) { // Stop after 10s or if shown
  146. clearInterval(dsPopupInterval);
  147. }
  148. }, 1000);
  149.  
  150. // --- END: DarkShadow44 Popup Enhancement ---
  151.  
  152.  
  153. // --- ORIGINAL SCRIPT CODE (UNCHANGED) ---
  154. function skipAd() {
  155. if (checkIsYouTubeShorts()) return
  156.  
  157. // This element appears when a video ad appears.
  158. const adShowing = document.querySelector('.ad-showing')
  159.  
  160. // Timed pie countdown ad.
  161. const pieCountdown = document.querySelector('.ytp-ad-timed-pie-countdown-container')
  162.  
  163. // Survey questions in video player.
  164. const surveyQuestions = document.querySelector('.ytp-ad-survey-questions')
  165.  
  166. if (adShowing === null && pieCountdown === null && surveyQuestions === null) return
  167.  
  168. let playerEl
  169. let player
  170. if (isYouTubeMobile || isYouTubeMusic) {
  171. playerEl = document.querySelector('#movie_player')
  172. player = playerEl
  173. } else {
  174. playerEl = document.querySelector('#ytd-player')
  175. player = playerEl && playerEl.getPlayer()
  176. }
  177.  
  178. if (playerEl === null || player === null) {
  179. console.log({
  180. message: 'Player not found',
  181. timeStamp: getCurrentTimeString()
  182. })
  183. return
  184. }
  185.  
  186. // ad.classList.remove('ad-showing')
  187.  
  188. let adVideo = null
  189.  
  190. if (pieCountdown === null && surveyQuestions === null) {
  191. adVideo = document.querySelector(
  192. '#ytd-player video.html5-main-video, #song-video video.html5-main-video'
  193. )
  194.  
  195. console.table({
  196. message: 'Ad video',
  197. video: adVideo !== null,
  198. src: adVideo?.src,
  199. paused: adVideo?.paused,
  200. currentTime: adVideo?.currentTime,
  201. duration: adVideo?.duration,
  202. timeStamp: getCurrentTimeString()
  203. })
  204.  
  205. if (adVideo === null || !adVideo.src || adVideo.paused || isNaN(adVideo.duration)) return
  206.  
  207. console.log({
  208. message: 'Ad video has finished loading',
  209. timeStamp: getCurrentTimeString()
  210. })
  211. }
  212.  
  213. if (isYouTubeMusic && adVideo !== null) {
  214. adVideo.currentTime = adVideo.duration
  215.  
  216. console.table({
  217. message: 'Ad skipped',
  218. timeStamp: getCurrentTimeString(),
  219. adShowing: adShowing !== null,
  220. pieCountdown: pieCountdown !== null,
  221. surveyQuestions: surveyQuestions !== null
  222. })
  223. } else {
  224. const videoData = player.getVideoData()
  225. const videoId = videoData.video_id
  226. const start = Math.floor(player.getCurrentTime())
  227.  
  228. if ('loadVideoWithPlayerVars' in playerEl) {
  229. playerEl.loadVideoWithPlayerVars({ videoId, start })
  230. } else {
  231. playerEl.loadVideoByPlayerVars({ videoId, start })
  232. }
  233.  
  234. console.table({
  235. message: 'Ad skipped',
  236. videoId,
  237. start,
  238. title: videoData.title,
  239. timeStamp: getCurrentTimeString(),
  240. adShowing: adShowing !== null,
  241. pieCountdown: pieCountdown !== null,
  242. surveyQuestions: surveyQuestions !== null
  243. })
  244. }
  245. }
  246.  
  247. function checkIsYouTubeShorts() {
  248. return location.pathname.startsWith('/shorts/')
  249. }
  250.  
  251. function getCurrentTimeString() {
  252. return new Date().toTimeString().split(' ', 1)[0]
  253. }
  254.  
  255. function addCss() {
  256. const adsSelectors = [
  257. // Ad banner in the upper right corner, above the video playlist.
  258. '#player-ads',
  259. '#panels > ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]',
  260.  
  261. // Masthead ad on home page.
  262. '#masthead-ad',
  263.  
  264. // Sponsored ad video items on home page.
  265. // 'ytd-ad-slot-renderer',
  266.  
  267. // '.ytp-suggested-action',
  268. '.yt-mealbar-promo-renderer',
  269.  
  270. // Featured product ad banner at the bottom left of the video.
  271. '.ytp-featured-product',
  272.  
  273. // Products shelf ad banner below the video description.
  274. 'ytd-merch-shelf-renderer',
  275.  
  276. // YouTube Music Premium trial promotion dialog, bottom left corner.
  277. 'ytmusic-mealbar-promo-renderer',
  278.  
  279. // YouTube Music Premium trial promotion banner on home page.
  280. 'ytmusic-statement-banner-renderer'
  281. ]
  282. const adsSelector = adsSelectors.join(',')
  283. const css = `${adsSelector} { display: none !important; }`
  284. const style = document.createElement('style')
  285. style.textContent = css
  286. document.head.appendChild(style)
  287. }
  288.  
  289. /**
  290. * Remove ad elements using JavaScript because these selectors require the use of the CSS
  291. * `:has` selector which is not supported in older browser versions.
  292. */
  293. function removeAdElements() {
  294. const adSelectors = [
  295. // Sponsored ad video items on home page.
  296. // ['ytd-rich-item-renderer', '.ytd-ad-slot-renderer'],
  297.  
  298. // ['ytd-rich-section-renderer', '.ytd-statement-banner-renderer'],
  299.  
  300. // Ad videos on YouTube Shorts.
  301. ['ytd-reel-video-renderer', '.ytd-ad-slot-renderer']
  302.  
  303. // Ad blocker warning dialog.
  304. // ['tp-yt-paper-dialog', '#feedback.ytd-enforcement-message-view-model'],
  305.  
  306. // Survey dialog on home page, located at bottom right.
  307. // ['tp-yt-paper-dialog', ':scope > ytd-checkbox-survey-renderer'],
  308.  
  309. // Survey to rate suggested content, located at bottom right.
  310. // ['tp-yt-paper-dialog', ':scope > ytd-single-option-survey-renderer']
  311. ]
  312. for (const adSelector of adSelectors) {
  313. const adEl = document.querySelector(adSelector[0])
  314. if (adEl === null) continue
  315. const neededEl = adEl.querySelector(adSelector[1])
  316. if (neededEl === null) continue
  317. adEl.remove()
  318. }
  319. }
  320.  
  321. const isYouTubeMobile = location.hostname === 'm.youtube.com'
  322. const isYouTubeDesktop = !isYouTubeMobile
  323.  
  324. const isYouTubeMusic = location.hostname === 'music.youtube.com'
  325. const isYouTubeVideo = !isYouTubeMusic
  326.  
  327. addCss()
  328.  
  329. if (isYouTubeVideo) {
  330. window.setInterval(removeAdElements, 1000)
  331. removeAdElements()
  332. }
  333.  
  334. window.setInterval(skipAd, 500)
  335. skipAd()
  336.  
  337. // const observer = new MutationObserver(skipAd) // This was the original ad skipper observer
  338. // observer.observe(document.body, {
  339. // attributes: true,
  340. // attributeFilter: ['class'],
  341. // childList: true,
  342. // subtree: true
  343. // })