Auto Close YouTube Ads

Close and/or Mute YouTube ads automatically!

目前為 2018-01-29 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Auto Close YouTube Ads
  3. // @namespace http://fuzetsu.acypa.com
  4. // @version 1.1.18
  5. // @description Close and/or Mute YouTube ads automatically!
  6. // @author fuzetsu
  7. // @match *://*.youtube.com/*
  8. // @exclude *://*.youtube.com/subscribe_embed?*
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @grant GM_deleteValue
  12. // @grant GM_registerMenuCommand
  13. // @require https://gf.qytechs.cn/scripts/5679-wait-for-elements/code/Wait%20For%20Elements.js?version=141779
  14. // ==/UserScript==
  15.  
  16. var Util = {
  17. log: function () {
  18. var args = [].slice.call(arguments);
  19. args.unshift('%c' + SCRIPT_NAME + ':', 'font-weight: bold;color: purple;');
  20. console.log.apply(console, args);
  21. },
  22. clearTicks: function(ticks) {
  23. ticks.forEach(function(tick) {
  24. if(typeof tick === 'number') {
  25. clearInterval(tick);
  26. } else {
  27. tick.stop();
  28. }
  29. });
  30. ticks.length = 0;
  31. },
  32. keepTrying: function(wait, action) {
  33. var tick = setInterval(function() {
  34. if(action()) {
  35. clearInterval(tick);
  36. }
  37. }, wait);
  38. },
  39. storeGet: function(key) {
  40. if (typeof GM_getValue === "undefined") {
  41. var value = localStorage.getItem(key);
  42. if (value === "true" || value === "false") {
  43. return (value === "true") ? true : false;
  44. }
  45. return value;
  46. }
  47. return GM_getValue(key);
  48. },
  49. storeSet: function(key, value) {
  50. if (typeof GM_setValue === "undefined") {
  51. return localStorage.setItem(key, value);
  52. }
  53. return GM_setValue(key, value);
  54. },
  55. storeDel: function(key) {
  56. if (typeof GM_deleteValue === "undefined") {
  57. return localStorage.removeItem(key);
  58. }
  59. return GM_deleteValue(key);
  60. },
  61. q: function(query, context) {
  62. return (context || document).querySelector(query);
  63. },
  64. qq: function(query, context) {
  65. return [].slice.call((context || document).querySelectorAll(query));
  66. },
  67. };
  68.  
  69. var SCRIPT_NAME = 'Auto Close YouTube Ads';
  70. var SEC_WAIT = parseInt(Util.storeGet('SEC_WAIT'));
  71. var MUTE_AD = Util.storeGet('MUTE_AD');
  72. var HIDE_AD = Util.storeGet('HIDE_AD');
  73. var MUTE_BUTTON_SELECTOR = '.ytp-mute-button';
  74. var MUTE_INDICATOR_SELECTOR = '.ytp-volume-slider-handle';
  75. var ticks = [];
  76. var videoUrl;
  77.  
  78. if(!MUTE_AD && MUTE_AD !== false) MUTE_AD = true;
  79. if(!SEC_WAIT && SEC_WAIT !== 0) SEC_WAIT = 3;
  80.  
  81. function waitForAds() {
  82. ticks.push(
  83. waitAndClick('.videoAdUiSkipButton', function(btn) {
  84. Util.keepTrying(1000, function() {
  85. btn.click();
  86. if(!Util.q('.videoAdUiSkipButton')) {
  87. return true;
  88. }
  89. });
  90. }),
  91. waitAndClick('a.close-button', function(btn) {
  92. Util.q('div.recall-button').remove();
  93. })
  94. );
  95. if(MUTE_AD) {
  96. ticks.push(waitForElems('.videoAdUi', function(ad) {
  97. if(HIDE_AD) {
  98. ad.style.zIndex = 10;
  99. ad.style.background = 'black';
  100. }
  101. var muteButton = Util.q(MUTE_BUTTON_SELECTOR);
  102. var muteIndicator = Util.q(MUTE_INDICATOR_SELECTOR);
  103. if(!muteIndicator) return Util.log('unable to determine mute state, skipping mute');
  104. if( muteIndicator.style.left === '0px') {
  105. Util.log('Video ad detected, audio already muted so respecting user setting');
  106. return;
  107. }
  108. // mute the ad
  109. muteButton.click();
  110. Util.log('Video ad detected, muting audio');
  111. // wait for the ad to dissapear before unmuting
  112. Util.keepTrying(500, function() {
  113. if(!Util.q('.videoAdUi')) {
  114. if(muteIndicator.style.left === '0px') {
  115. muteButton.click();
  116. Util.log('Video ad ended, unmuting audio');
  117. } else {
  118. Util.log('Video ad ended, audio already unmuted');
  119. }
  120. return true;
  121. }
  122. });
  123. }));
  124. }
  125. }
  126.  
  127. function waitAndClick(sel, cb, extraWait) {
  128. return waitForElems(sel, function(btn) {
  129. Util.log('Found ad, closing in', SEC_WAIT, 'seconds');
  130. setTimeout(function() {
  131. btn.click();
  132. if(cb) {
  133. cb(btn);
  134. }
  135. }, SEC_WAIT * 1000 + (extraWait || 0));
  136. });
  137. }
  138.  
  139. Util.log('Started');
  140.  
  141. if(window.self === window.top) {
  142. waitForUrl(/^https:\/\/www\.youtube\.com\/watch\?.*v=.+/, function() {
  143. if(videoUrl && location.href !== videoUrl) {
  144. Util.log('Changed video, removing old wait');
  145. Util.clearTicks(ticks);
  146. }
  147. videoUrl = location.href;
  148. Util.log('Entered video, waiting for ads');
  149. waitForAds();
  150. ticks.push(
  151. waitForUrl(function(url) {
  152. return url !== videoUrl;
  153. }, function() {
  154. videoUrl = null;
  155. Util.clearTicks(ticks);
  156. Util.log('Left video, stopped waiting for ads');
  157. }, true)
  158. );
  159. });
  160. } else {
  161. if(/https:\/\/www\.youtube\.com\/embed\//.test(location.href)) {
  162. Util.log('Found embedded video, waiting for ads');
  163. waitForAds();
  164. }
  165. }
  166.  
  167. // register menu commands
  168. GM_registerMenuCommand(SCRIPT_NAME + ': set ad close delay', function() {
  169. var wait = parseInt(prompt('Current setting is ' + SEC_WAIT + ' seconds. Enter the number of seconds you would like the script to wait before closing an ad. 0 means no delay.'));
  170. if(!isNaN(wait)) {
  171. SEC_WAIT = wait;
  172. Util.storeSet('SEC_WAIT', SEC_WAIT);
  173. }
  174. });
  175. GM_registerMenuCommand(SCRIPT_NAME + ': ' + (MUTE_AD ? 'disable' : 'enable') + ' video ad muting (warning clicking this will refresh the page)', function() {
  176. Util.storeSet('MUTE_AD', !MUTE_AD);
  177. location.reload();
  178. });
  179. GM_registerMenuCommand(SCRIPT_NAME + ': ' + (HIDE_AD ? 'disable' : 'enable') + ' video ad hiding (warning clicking this will refresh the page)', function() {
  180. Util.storeSet('HIDE_AD', !HIDE_AD);
  181. location.reload();
  182. });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址