動畫瘋自動播放廣告

自動同意年齡提示,到達時間後自動跳過廣告,並註冊一些快捷鍵(詳見最下方的更新日誌)

目前為 2024-12-14 提交的版本,檢視 最新版本

// ==UserScript==
// @name               Auto play ads on ani.gamer.com.tw
// @name:zh-CN         动画疯自动播放广告
// @name:zh-TW         動畫瘋自動播放廣告
// @namespace          ling921
// @version            0.1
// @description        Agree to age prompt, auto skip ads when time is up, and register some keyboard shortcuts (see the release notes below for details)
// @description:zh-CN  自动同意年龄提示,到达时间后自动跳过广告,并注册一些快捷键(详见最下方的更新日志)
// @description:zh-TW  自動同意年齡提示,到達時間後自動跳過廣告,並註冊一些快捷鍵(詳見最下方的更新日誌)
// @author             ling921
// @match              https://ani.gamer.com.tw/animeVideo.php*
// @match              https://*.safeframe.googlesyndication.com/*
// @match              https://imasdk.googleapis.com/*
// @icon               http://gamer.com.tw/favicon.ico
// @grant              none
// @run-at             document-idle
// @license            MIT
// ==/UserScript==

/**
 * Global variable to store video player
 * @type {HTMLVideoElement}
 */
var videoPlayer;

(function () {
  "use strict";

  // Handle top level window
  if (window === window.top) {
    // Register keyboard shortcuts
    document.addEventListener("keydown", (event) => {
      // Ignore input fields event propagation
      if (
        event.target.tagName === "INPUT" ||
        event.target.tagName === "TEXTAREA" ||
        event.target.isContentEditable
      ) {
        return;
      }

      if (!event.ctrlKey && !event.metaKey && !event.shiftKey) {
        // [ goes to previous video
        if (event.key === "[") {
          const prevButton = document.querySelector(".vjs-pre-button");
          if (prevButton) {
            console.log("Go to previous video");
            prevButton.click();
          } else {
            console.log("No previous video button found");
          }
        }
        // ] goes to next video
        else if (event.key === "]") {
          const nextButton = document.querySelector(".vjs-next-button");
          if (nextButton) {
            console.log("Go to next video");
            nextButton.click();
          } else {
            console.log("No next video button found");
          }
        }
        // P pause or play
        else if (event.key === "p") {
          const playButton = document.querySelector(".vjs-play-control");
          if (playButton) {
            console.log("Pause or play");
            playButton.click();
          }
        }
        // T enter or exit theater mode
        else if (event.key === "t") {
          const theaterButton = document.querySelector(".vjs-indent-button");
          if (theaterButton) {
            console.log("Enter or exit theater mode");
            theaterButton.click();
          }
        }
        // F enter or exit fullscreen
        else if (event.key === "f") {
          const fullscreenButton = document.querySelector(
            ".vjs-fullscreen-control"
          );
          if (fullscreenButton) {
            console.log("Enter or exit fullscreen");
            fullscreenButton.click();
          }
        }
      }
    });

    videoPlayer = document.querySelector("#ani_video_html5_api");
    if (videoPlayer) {
      console.log("Add event listener to videoPlayer");
      videoPlayer.addEventListener("loadstart", () => {
        videoPlayer.muted = false;
      });
    }

    // Define observer to execute functions when DOM changes
    const observer = new MutationObserver(() => {
      agreeAgePrompt();
      handleVideoPlayerAds();
    });

    // Start observing the body for changes
    observer.observe(document.body, { childList: true, subtree: true });
  }
  // Handle iframe window
  else {
    if (window.location.href.includes("safeframe.googlesyndication.com")) {
      const observer = new MutationObserver(() => {
        handleIframeAds(document);
      });
      observer.observe(document.body, { childList: true, subtree: true });
    } else if (window.location.href.includes("imasdk.googleapis.com")) {
      const observer = new MutationObserver(() => {
        handleIframeAds2(document);
      });
      observer.observe(document.body, { childList: true, subtree: true });
    }
  }
})();

/**
 * Agree to age prompt
 */
function agreeAgePrompt() {
  const agePrompt = document.querySelector("button.choose-btn-agree#adult");
  if (agePrompt) {
    console.log("Agree to age prompt");
    agePrompt.click();
  }
}

/**
 * Handle ads in video player
 */
function handleVideoPlayerAds() {
  const skipButton = document.querySelector("#adSkipButton");
  if (skipButton) {
    if (skipButton.classList.contains("enable")) {
      console.log("Ads time is up, skip ads (#adSkipButton)");
      skipButton.click();
    } else {
      videoPlayer.muted = true;
    }
  }

  const skipButton2 = document.querySelector(".nativeAD-skip-button.enable");
  if (skipButton2 && !skipButton2.classList.contains("vjs-hidden")) {
    console.log("Ads time is up, skip ads (.nativeAD-skip-button)");
    skipButton2.click();
  }
}

/**
 * Handle ads in iframe
 * @param {Document} doc - The iframe document
 */
function handleIframeAds(doc) {
  const adsCountDown = doc.querySelector("#count-down-text");
  if (adsCountDown) {
    const dismissDialog = () => {
      const dismissButton = doc.querySelector("#card #dismiss-button-element");
      if (dismissButton) {
        if (dismissButton.style.display !== "none") {
          console.log("Dismiss dialog Ad");
          dismissButton.click();
        } else {
          console.log("Dismiss button is hidden, waiting for it to appear...");
        }
      } else {
        console.log("Dismiss button is not found");
      }
    };
    if (adsCountDown.offsetParent === null) {
      dismissDialog();
    } else if (adsCountDown.textContent === "1 秒後即可獲得獎勵") {
      setTimeout(dismissDialog, 1000);
    }
  }
}

/**
 * Handle ads in iframe
 * @param {Document} doc - The iframe document
 */
function handleIframeAds2(doc) {
  const skipButton = doc.querySelector('[aria-label="Skip Ad"]');
  if (skipButton) {
    if (skipButton.textContent === "Skip Ad") {
      console.log('Click Skip Ad ([aria-label="Skip Ad"])');
      skipButton.click();
    } else {
      videoPlayer.muted = true;
    }
  }
}

// Release notes

// 2024-12-14 version 0.1
// - 自動同意年齡確認
// - 廣告倒數結束結束自動跳過廣告
// - 播放廣告時靜音,播放影片時取消靜音
// - 註冊快捷鍵 [ 和 ] 分別跳到上一個和下一個視頻
// - 註冊快速鍵 P 暫停或播放
// - 註冊快速鍵 T 進入或退出劇院模式
// - 註冊快捷鍵 F 進入或退出全螢幕