Youtube AD Skipper 油管广告拦截跳过

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

目前为 2023-10-31 提交的版本。查看 最新版本

// ==UserScript==
// @name                  Youtube AD Skipper 油管广告拦截跳过
// @name:zh-CN            Youtube AD Skipper 油管广告拦截跳过
// @namespace             http://tampermonkey.net/
// @version               0.5
// @description           Quickly skip video ads in Youtube. 快速跳过油管中的视频广告。
// @description:zh-CN     Quickly skip video ads in Youtube. 快速跳过油管中的视频广告。
// @icon                  https://www.gstatic.com/youtube/img/branding/favicon/favicon_144x144.png
// @author                gabe
// @license               MIT
// @match                 https://*.youtube.com/*
// @grant                 none
// ==/UserScript==

(function () {
  "use strict";

  function sleep(delay = 500) {
    return new Promise(function (resolve) {
      const timer = setTimeout(function () {
        clearTimeout(timer);
        resolve();
      }, delay);
    });
  }

  function newTouch(el) {
    const rect = el.getBoundingClientRect();
    const x = (rect.left + rect.right) / 2;
    const y = (rect.top + rect.bottom) / 2;
    return new Touch({
      identifier: Date.now(),
      target: el,
      clientX: x,
      clientY: y,
      screenX: x,
      screenY: y,
      pageX: x + document.body.scrollLeft,
      pageY: y + document.body.scrollTop,
      radiusX: 10.0,
      radiusY: 10.0,
      rotationAngle: 0.0,
      force: 1,
    });
  }

  function newTouchEvent(touch, name) {
    return new TouchEvent(name, {
      cancelable: true,
      bubbles: true,
      touches: [touch],
      targetTouches: [touch],
      changedTouches: [touch],
    });
  }

  function dispatchTouch(el) {
    const touch = newTouch(el);
    el.dispatchEvent(newTouchEvent(touch, "touchstart"));
    // el.dispatchEvent(newTouchEvent(touch, "touchmove"));
    el.dispatchEvent(newTouchEvent(touch, "touchend"));
  }

  async function skipAd(moviePlayer, adOverlay) {
    let i = 0;
    while (true) {
      if (++i > 5) {
        console.info("[Youtube AD Skipper] skip failed...");
        return;
      }

      if (i > 1) {
        adOverlay = moviePlayer.getElementsByClassName(
          "ytp-ad-player-overlay"
        )[0];
        if (!adOverlay) {
          return;
        }
      }

      const skipButton =
        adOverlay.getElementsByClassName("ytp-ad-skip-button")[0];

      if (skipButton) {
        const isMobile = location.hostname === "m.youtube.com";
        if (isMobile) {
          dispatchTouch(skipButton);
          console.info("[Youtube AD Skipper] skip touch ->", i);
        } else {
          skipButton.click();
          console.info("[Youtube AD Skipper] skip click ->", i);
        }
        await sleep();
        continue;
      }

      const video = moviePlayer.getElementsByTagName("video")[0];
      video.currentTime = video.duration;
      console.info("[Youtube AD Skipper] skip play ->", i);
      await sleep();
    }
  }

  let isBusying = false;
  const pageObserver = new MutationObserver(async function () {
    if (isBusying) {
      return;
    }

    const moviePlayer = document.getElementById("movie_player");
    if (!moviePlayer) {
      return;
    }

    const adOverlay = moviePlayer.getElementsByClassName(
      "ytp-ad-player-overlay"
    )[0];
    if (!adOverlay) {
      return;
    }

    isBusying = true;

    try {
      const adInfo = adOverlay.getElementsByClassName(
        "ytp-ad-player-overlay-instream-info"
      )[0];
      console.info(
        "[Youtube AD Skipper] found ad: ",
        adInfo && adInfo.innerText
      );
      await skipAd(moviePlayer, adOverlay);
    } catch (err) {
      console.info("[Youtube AD Skipper] got error: ", err.message);
    } finally {
      isBusying = false;
    }
  });

  pageObserver.observe(document.body, {
    childList: true,
    subtree: true,
  });
  console.info("[Youtube AD Skipper] start!!!");
})();

QingJ © 2025

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