// ==UserScript== // @name Youtube AD Skipper 油管广告拦截跳过 // @name:zh-CN Youtube AD Skipper 油管广告拦截跳过 // @namespace http://tampermonkey.net/ // @version 0.7 // @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 // @downloadURL none // ==/UserScript== (function () { "use strict"; function log() { return console.info("[Youtube AD Skipper]", ...arguments); } 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 (++i < 6) { if (i > 1) { adOverlay = moviePlayer.getElementsByClassName( "ytp-ad-player-overlay" )[0]; if (!adOverlay) { log("skip done!!!"); return; } } const skipButton = adOverlay.getElementsByClassName("ytp-ad-skip-button")[0]; if (skipButton) { const isMobile = location.hostname === "m.youtube.com"; if (isMobile) { dispatchTouch(skipButton); log("skip touch ->", i); } else { skipButton.click(); log("skip click ->", i); } } else { const video = moviePlayer.getElementsByTagName("video")[0]; video.currentTime = video.duration; log("skip play ->", i); } await sleep(); } log("skip failed..."); } 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]; log("found ad:", adInfo && adInfo.innerText); await skipAd(moviePlayer, adOverlay); } catch (err) { log("got error:", err.message); } finally { isBusying = false; } }); if (window.self !== window.top) { return; } pageObserver.observe(document.body, { childList: true, subtree: true, }); log("--- start ---"); })();