Youtube AD Skipper 油管广告拦截跳过

Quickly skip video ads in Youtube. 快速跳过油管中的视频广告。

  1. // ==UserScript==
  2. // @name Youtube AD Skipper 油管广告拦截跳过
  3. // @name:zh-CN Youtube AD Skipper 油管广告拦截跳过
  4. // @namespace http://tampermonkey.net/
  5. // @version 0.10
  6. // @description Quickly skip video ads in Youtube. 快速跳过油管中的视频广告。
  7. // @description:zh-CN Quickly skip video ads in Youtube. 快速跳过油管中的视频广告。
  8. // @icon https://www.gstatic.com/youtube/img/branding/favicon/favicon_144x144.png
  9. // @author gabe
  10. // @license MIT
  11. // @match https://*.youtube.com/*
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. "use strict";
  17.  
  18. const SKIP_BUTTON = ".ytp-ad-skip-button, .ytp-ad-skip-button-modern";
  19. const AD_OVERLAY = ".ytp-ad-player-overlay, .ytp-ad-survey-player-overlay";
  20. const AD_INFO =
  21. ".ytp-ad-player-overlay-instream-info, .ytp-ad-survey-player-overlay-instream-info";
  22.  
  23. function log() {
  24. return console.info("[Youtube AD Skipper]", ...arguments);
  25. }
  26.  
  27. function sleep(delay = 500) {
  28. return new Promise(function (resolve) {
  29. const timer = setTimeout(function () {
  30. clearTimeout(timer);
  31. resolve();
  32. }, delay);
  33. });
  34. }
  35.  
  36. function newTouch(el) {
  37. const rect = el.getBoundingClientRect();
  38. const x = (rect.left + rect.right) / 2;
  39. const y = (rect.top + rect.bottom) / 2;
  40. return new Touch({
  41. identifier: Date.now(),
  42. target: el,
  43. clientX: x,
  44. clientY: y,
  45. screenX: x,
  46. screenY: y,
  47. pageX: x + document.body.scrollLeft,
  48. pageY: y + document.body.scrollTop,
  49. radiusX: 10.0,
  50. radiusY: 10.0,
  51. rotationAngle: 0.0,
  52. force: 1,
  53. });
  54. }
  55.  
  56. function newTouchEvent(touch, name) {
  57. return new TouchEvent(name, {
  58. cancelable: true,
  59. bubbles: true,
  60. touches: [touch],
  61. targetTouches: [touch],
  62. changedTouches: [touch],
  63. });
  64. }
  65.  
  66. function dispatchTouch(el) {
  67. const touch = newTouch(el);
  68. el.dispatchEvent(newTouchEvent(touch, "touchstart"));
  69. // el.dispatchEvent(newTouchEvent(touch, "touchmove"));
  70. el.dispatchEvent(newTouchEvent(touch, "touchend"));
  71. }
  72.  
  73. async function skipAd(moviePlayer, adOverlay) {
  74. let i = 0;
  75. while (++i < 6) {
  76. if (i > 1) {
  77. adOverlay = moviePlayer.querySelector(AD_OVERLAY);
  78. if (!adOverlay) {
  79. log("skip done!!!");
  80. return;
  81. }
  82. }
  83.  
  84. const skipButton = adOverlay.querySelector(SKIP_BUTTON);
  85. const isMobile = location.hostname === "m.youtube.com";
  86. if (skipButton) {
  87. if (isMobile) {
  88. dispatchTouch(skipButton);
  89. log("skip touch ->", i);
  90. } else {
  91. skipButton.click();
  92. log("skip click ->", i);
  93. }
  94. } else {
  95. const video = moviePlayer.getElementsByTagName("video")[0];
  96. video.currentTime = video.duration;
  97. log("skip play ->", i);
  98. }
  99.  
  100. await sleep();
  101. }
  102.  
  103. log("skip failed...");
  104. }
  105.  
  106. let isBusying = false;
  107. const pageObserver = new MutationObserver(async function () {
  108. if (isBusying) {
  109. return;
  110. }
  111.  
  112. try {
  113. isBusying = true;
  114.  
  115. const moviePlayer = document.getElementById("movie_player");
  116. if (!moviePlayer) {
  117. return;
  118. }
  119.  
  120. const adOverlay = moviePlayer.querySelector(AD_OVERLAY);
  121. if (!adOverlay) {
  122. return;
  123. }
  124.  
  125. const adInfo = adOverlay.querySelector(AD_INFO);
  126. log("found ad:", adInfo && adInfo.innerText);
  127. await skipAd(moviePlayer, adOverlay);
  128. } catch (err) {
  129. log("got error:", err.message);
  130. } finally {
  131. isBusying = false;
  132. }
  133. });
  134.  
  135. if (window.self !== window.top) {
  136. return;
  137. }
  138.  
  139. pageObserver.observe(document.body, {
  140. childList: true,
  141. subtree: true,
  142. });
  143.  
  144. log("--- start ---");
  145. })();

QingJ © 2025

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