// ==UserScript==
// @name Starburst Ads
// @namespace C2FFB7B4-83BC-11EE-85E1-21839234574D
// @version 1.0.0
// @description Faster.. Faster!... Even Faster!!!
// @description:zh 快... 要更快! 還要更快!!!
// @author Rick0
// @match https://www.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant none
// @compatible firefox Tampermonkey
// @compatible chrome Tampermonkey
// @license MIT
// @noframes
// ==/UserScript==
(function() {
"use strict";
const canRun = () => location.href.search(/[?&]v=/) > -1, skipAd = () => {
const abortController = new AbortController(), videoContainer = document.querySelector("#movie_player"), videoPlayer = videoContainer.querySelector(".video-stream"), fadVideo = () => {
videoPlayer.muted = !0, videoPlayer.currentTime = videoPlayer.duration, videoPlayer.paused && videoPlayer.play(), console.debug("fadVideo finish.", videoPlayer);
}, isAd = () => videoContainer.classList.contains("ad-showing") || videoContainer.classList.contains("ad-interrupting");
isAd() && videoPlayer.readyState > 0 && fadVideo();
const handleLoaddata = () => {
isAd() && fadVideo();
};
videoPlayer.addEventListener("loadeddata", handleLoaddata), abortController.signal.addEventListener("abort", () => {
videoPlayer.removeEventListener("loadeddata", handleLoaddata), console.debug("removeEventListener loadeddata");
}), new Promise((resolve) => {
const adsContainer = videoContainer.querySelector(".video-ads");
if (adsContainer !== null) {
resolve(adsContainer);
return;
}
const adsContainerObserver = new MutationObserver(() => {
const adsContainer2 = videoContainer.querySelector(".video-ads");
adsContainer2 !== null && (adsContainerObserver.disconnect(), resolve(adsContainer2));
});
adsContainerObserver.observe(videoContainer, { childList: !0 }), abortController.signal.addEventListener("abort", () => {
adsContainerObserver.disconnect(), resolve(null), console.debug("adsContainerObserver.disconnect()");
});
}).then((adsContainer) => {
if (adsContainer === null)
return;
clickSkipAdsButton(adsContainer);
const skipAdsButtonObserver = new MutationObserver(() => {
clickSkipAdsButton(adsContainer);
});
skipAdsButtonObserver.observe(adsContainer, {
childList: !0,
subtree: !0
}), abortController.signal.addEventListener("abort", () => {
skipAdsButtonObserver.disconnect(), console.debug("skipAdsButtonObserver.disconnect()");
});
}).catch((err) => {
console.debug("adsContainer", err);
});
const clickSkipAdsButton = (buttonContainer) => {
const skipAdsButtonList = [
"button.ytp-ad-skip-button",
"button.ytp-ad-skip-button-modern"
];
buttonContainer.querySelectorAll(skipAdsButtonList.join(",")).forEach((button) => {
button.click(), console.debug("clickSkipAdsButton", button);
});
};
return console.debug("skipAd"), abortController;
}, hiddenAds = () => {
const addStyle = (cssCode) => {
const style = document.createElement("style");
style.innerHTML = cssCode, document.head.append(style);
}, hiddenAdSelectors = [
// 右側聊天室上方的廣告
'ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]',
// 右側聊天室下方的廣告
"#player-ads",
// 右側推薦影片最上第一個會有廣告
"ytd-ad-slot-renderer",
// 搜尋結果的第一個項目是廣告
// `ytd-rich-item-renderer:has(ytd-ad-slot-renderer)`,
"ytd-rich-grid-row:first-child ytd-rich-item-renderer:first-child",
// == 影片相關 ==
// 影片廣告的控制按鈕之類的內容
".video-ads",
// 影片右上角資訊欄會彈出的內容
".html5-video-player .ytp-cards-teaser",
// 影片結束後的推薦影片
".html5-video-player > .ytp-ce-element",
// 影片右下角的浮水印按鈕
".html5-video-player .annotation.annotation-type-custom.iv-branding"
], invisibleSelectorList = [
// 播放中的廣告影片
".ad-showing video.video-stream, .ad-interrupting video.video-stream",
// 廣告影片標題
".ad-showing > .ytp-chrome-top, .ad-interrupting > .ytp-chrome-top",
// 廣告的進度條
".ad-showing .ytp-progress-list > .ytp-play-progress, .ad-interrupting .ytp-progress-list > .ytp-play-progress",
".ad-showing .ytp-progress-list > .ytp-load-progress, .ad-interrupting .ytp-progress-list > .ytp-load-progress",
// 廣告的字幕
".ad-showing > .ytp-caption-window-container, .ad-interrupting > .ytp-caption-window-container"
], otherStyles = [
// 設定播放器背景色,當處於一般影片模式+淺色主題時,隱藏廣告影片會透出一片白色,很突兀
"ytd-player#ytd-player{background-color:black!important;}"
];
addStyle(
`${hiddenAdSelectors.join(
","
)}{display:none!important;}${invisibleSelectorList.join(
","
)}{visibility:hidden!important;}${otherStyles.join("")}`
), console.debug("hiddenAds");
}, closeDialog = () => {
new Promise((resolve) => {
const ytdApp = document.querySelector("ytd-app"), dialog = ytdApp.querySelector("ytd-popup-container");
if (dialog !== null) {
resolve(dialog);
return;
}
new MutationObserver((_m, observer) => {
const dialog2 = ytdApp.querySelector("ytd-popup-container");
dialog2 !== null && (observer.disconnect(), resolve(dialog2));
}).observe(ytdApp, { childList: !0 });
}).then((dialog) => {
new MutationObserver(() => {
const closeButtonList = [
'yt-button-renderer#dismiss-button button[aria-label="不用了,謝謝"]',
// 關閉推薦試用 YouTube Premium
'yt-button-renderer#confirm-button button[aria-label="是"]'
// 背景播放音樂,會出現是否繼續播放,
];
dialog.querySelectorAll(closeButtonList.join(",")).forEach((button) => {
button.click(), console.debug("closedDialog click button", button);
});
}).observe(dialog, {
childList: !0,
subtree: !0
});
});
}, runSkipAd = (() => {
let abortController = null;
return () => {
abortController == null || abortController.abort(), canRun() && (abortController = skipAd());
};
})();
hiddenAds(), runSkipAd(), closeDialog(), document.addEventListener("yt-navigate-start", () => {
console.debug(`[yt-navigate-start] ${location.href}`), runSkipAd();
}), console.debug("first run");
})();