YAAS (YouTube Ads Auto Skip)

Automatically closes the banner ad or clicks the "Skip ad" button.

  1. // ==UserScript==
  2. // @name YAAS (YouTube Ads Auto Skip)
  3. // @description Automatically closes the banner ad or clicks the "Skip ad" button.
  4. // @name:uk YAAS (Автоматичний пропуск реклами на YouTube).
  5. // @description:uk Автоматично закриває рекламний банер чи клікає по кнопці "Пропустити рекламу".
  6. // @version 3.0.5
  7. // @namespace https://greatest.deepsurf.us/uk/users/741855
  8. // @author boboha
  9. // @match *://*.youtube.com/*
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. let skiped = true,
  16. video_speed = 1,
  17. player,
  18. video;
  19. const SEC = 1000,
  20. TO = 0 * SEC,
  21. TO_SUBSCIBED_VIDEO = 10 * SEC,
  22. TO_SUBSCIBED_BANNER = 5 * SEC,
  23. AD_SPEED = 6,
  24. log = (...msg) => { console.log('[YAAS]', ...msg) },
  25. isSubscribed = () => document.querySelector('#subscribe-button [subscribed]') ? true : false,
  26. skipVideo = (btn) => {
  27. skiped = false;
  28. btn.addEventListener('click', setSkiped, false);
  29. setTimeout(() => {
  30. skip(btn);
  31. }, isSubscribed() ? TO_SUBSCIBED_VIDEO : TO);
  32. },
  33. setSkiped = () => { skiped = true; log('Video skiped!') },
  34. skip = (btn) => {
  35. if (btn.nodeType === 1 && getComputedStyle(btn).display === 'inline-block') {
  36. btn.click();
  37. } else {
  38. setTimeout(() => {
  39. !skiped && skip(btn);
  40. }, 100);
  41. }
  42. },
  43. closeBanner = (btn) => {
  44. btn.addEventListener('click', setClosed, false);
  45. setTimeout(() => {
  46. btn.click();
  47. }, isSubscribed() ? TO_SUBSCIBED_BANNER : TO);
  48. },
  49. setClosed = () => { log('Banner closed!') },
  50. observer = new MutationObserver(mutations => {
  51. for (const mutation of mutations) {
  52. try {
  53. if (mutation.target.className === 'video-ads ytp-ad-module') {
  54. if (mutation.addedNodes.length) {
  55. // Video loading
  56. if (mutation.addedNodes[0].className === 'ytp-ad-player-overlay') {
  57. if (!video.muted) video.muted = true;
  58. if (video.playbackRate != AD_SPEED) video.playbackRate = AD_SPEED;
  59. log('Video is loaded...', '(', Math.round(video.duration), 's )');
  60. }
  61. // Banner loading
  62. else if (mutation.addedNodes[0].className === 'ytp-ad-overlay-slot') {
  63. log('Banner is loaded...');
  64. // Banner closing
  65. const close_button = mutation.addedNodes[0].querySelector('.ytp-ad-overlay-close-container > .ytp-ad-overlay-close-button');
  66. close_button && closeBanner(close_button);
  67. }
  68. // Pre ad countdown start
  69. else if (mutation.addedNodes[0].className === 'ytp-ad-message-overlay') {
  70. video_speed = video.playbackRate;
  71. }
  72. // Interstitial ad countdown
  73. else if (mutation.addedNodes[0].className === 'ytp-ad-action-interstitial') {
  74. if (!isSubscribed()) {
  75. const btn = mutation.target.querySelector('.ytp-ad-text.ytp-ad-skip-button-text');
  76. btn && btn.click();
  77. log('Interstitial ad skiped!');
  78. }
  79. }
  80. // else {}
  81. } else if (mutation.removedNodes.length) {
  82. if (mutation.removedNodes[0].id.startsWith('player-overlay')) {
  83. video.muted=false;
  84. video.playbackRate = video_speed;
  85. log('Video ended');
  86. }
  87. // Pre ad countdown end
  88. else if (mutation.removedNodes[0].className === 'ytp-ad-message-overlay') {
  89. video.muted = true;
  90. video.playbackRate = AD_SPEED;
  91. }
  92. }
  93. }
  94.  
  95. // Video skiping
  96. if (mutation.target.className === 'ytp-ad-skip-button-slot') {
  97. const skip_button = mutation.target.querySelector('.ytp-ad-skip-button-container > .ytp-ad-skip-button');
  98. skip_button && skipVideo(skip_button);
  99. }
  100. } catch (e) {
  101. console.groupCollapsed(e.message, mutation.target);
  102. log(mutation);
  103. console.groupEnd();
  104. }
  105. }
  106. }),
  107. initPlayer = () => {
  108. if (player) {
  109. log('Init Player');
  110. } else {
  111. player = document.querySelector('#movie_player');
  112. initPlayer();
  113. }
  114. },
  115. toggleObserver = () => {
  116. if (location.pathname === '/watch') {
  117. if (player) {
  118. if (!video) {
  119. video = document.querySelector('video.html5-main-video');
  120. observer.observe(player, {childList: true, attributes: true, subtree: true});
  121. log('Observer start');
  122. }
  123. } else {
  124. initPlayer();
  125. toggleObserver();
  126. }
  127. } else {
  128. if (player) {
  129. observer.disconnect();
  130. player = null;
  131. video = null;
  132. log('Observer stop');
  133. } else {
  134. initPlayer();
  135. }
  136. }
  137. };
  138.  
  139. window.addEventListener('yt-navigate-start', toggleObserver);
  140. toggleObserver();
  141.  
  142. })();