视频网站自动网页全屏|倍速播放

支持哔哩哔哩、B站直播、腾讯视频、优酷视频、爱奇艺、芒果TV、搜狐视频、AcFun弹幕网自动网页全屏;快捷键切换:全屏(F)、网页全屏(P)、下一个视频(N)、弹幕开关(D);支持任意视频倍速播放,提示记忆倍速;B站播放完自动退出网页全屏和取消连播。

安装此脚本?
作者推荐脚本

您可能也喜欢M站_哔咪动漫脚本

安装此脚本
// ==UserScript==
// @name         视频网站自动网页全屏|倍速播放
// @namespace    http://tampermonkey.net/
// @version      2.6.2
// @author       Feny
// @description  支持哔哩哔哩、B站直播、腾讯视频、优酷视频、爱奇艺、芒果TV、搜狐视频、AcFun弹幕网自动网页全屏;快捷键切换:全屏(F)、网页全屏(P)、下一个视频(N)、弹幕开关(D);支持任意视频倍速播放,提示记忆倍速;B站播放完自动退出网页全屏和取消连播。
// @license      GPL-3.0-only
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAqdJREFUWEftl91LFFEYxp/3jB9ESZjtSl51F1RUSgRCF/kHlF1IhiFhF65dqEQkBUErdJMStBukGwQre2NZUiCRqUiURkW65mIfqGUFsW6Ii0jY7p4Tc3Rqd5zaGVldAudynve8z28e3jMzh5Dmi1R/V0vQyRRWxgWG6x22SrcnOAhQcQIbwVtXba8y1EANSpS1xzJin5c/Dz+jRDPvGWoErwRw35zuh8ChpcXXFjbwi9k/WADA9viGgovGnxtFs6EmcApMvCdBA3oIIirl4N8NNQngmRYJiwTOE7EHHLERAmXFawQ6AdCQkRbjsZIMUvIFoV0HMSsEDjCgSK8tJqAHAEDAMWLKLOexx8tiVVDEhLLVQAtzRPcwKOUANSWCw1/rsBe6PcFz8dpfAdTFgtF+EmIvBG7pID7mZNl2zkVCFQbahzqHfYerddpNhFpdsnfqauzl8ZoEuO4JXdIKOefynnZlimxXhBbqjTZL/el8pzrAVjTGmKh12Bq1ddJs974abQDXfFMuAhQ6EodwDTHWAf6/BAoK8nD0cDEKtuVhyD+OzvvLXnyWJshyApedJ1F65M9n4tlAAF5fL168fGfJWCu2DDA61GpodLvjCdp8vfjyNWQJJGUAquvMzBzafD0yEc65KZCUAmiOo4FPEqS753VSiFUB0FxbPF244en6J8SqAoTD8zhYcjZ9AP6RCVRWNacHYPD5GJqudmBi8tvaAkxNBeUuuNv5NOkAqgUpm4FIJCrfA+r0z4bnTZmvCKCv+wrsts0JBg8fvZLGY28NfoqToFhOoOJ4CS40lMu2I28mpXFP37DpJ9YXWgZQG+Tm5mBL7qakA2aGakUAZhqbrVkH0BLoB34fzcyml5K6pd/yaicRlQlgV0q6mmwitMOpyfpVKfsFya4w73cz9xQAAAAASUVORK5CYII=
// @homepage     https://github.com/xFeny/monkey-web-fullscreen
// @include      *://pages.iqiyi.com/p/zy/*
// @include      *://www.ezdmw.site/Index/video/*
// @include      *://player.ezdmw.com/danmuku/*
// @include      *://*bimiacg*.net/*/play*
// @include      *://acgfta.com/play*
// @include      *://ppoft.com/play*
// @match        *://tv.sohu.com/v/*
// @match        *://www.mgtv.com/b/*
// @match        *://www.acfun.cn/v/*
// @match        *://www.iqiyi.com/v_*
// @match        *://v.qq.com/x/page/*
// @match        *://v.qq.com/x/cover/*
// @match        *://haokan.baidu.com/v*
// @match        *://live.bilibili.com/*
// @match        *://v.youku.com/video?*
// @match        *://live.acfun.cn/live/*
// @match        *://www.acfun.cn/bangumi/*
// @match        *://www.bilibili.com/list/*
// @match        *://www.bilibili.com/video/*
// @match        *://www.bilibili.com/*/play/*
// @match        *://v.qq.com/live/p/newtopic/*
// @match        *://www.bilibili.com/festival/*
// @match        *://v.douyu.com/show/*
// @grant        GM_addStyle
// @grant        GM_addValueChangeListener
// @grant        GM_getValue
// @grant        GM_info
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_unregisterMenuCommand
// @grant        unsafeWindow
// @note         *://*/*
// ==/UserScript==

(t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const o=document.createElement("style");o.textContent=t,document.head.append(o)})(' @charset "UTF-8";.showToast{color:#fff!important;font-size:13.5px!important;padding:5px 15px!important;border-radius:5px!important;position:absolute!important;z-index:2147483647!important;font-weight:400!important;transition:opacity .5s ease-in;background:#000000bf!important}#bilibili-player .bpx-player-toast-wrap,#bilibili-player .bpx-player-cmd-dm-wrap,#bilibili-player .bpx-player-dialog-wrap,.live-room-app #sidebar-vm,.live-room-app #prehold-nav-vm,.live-room-app #shop-popover-vm,.login-tip{display:none!important} ');

(function () {
  'use strict';

  const positions = Object.freeze({
    bottomLeft: "bottom: 17%; left: 10px;",
    center: "top: 50%; left: 50%; transform: translate(-50%, -50%);"
  });
  const ONE_SECOND = 1e3;
  const constants = Object.freeze({
    EMPTY: "",
    DEF_PLAY_RATE: 1,
    MAX_PLAY_RATE: 16,
    ONE_SEC: ONE_SECOND,
    SHOW_TOAST_TIME: ONE_SECOND * 5,
    SHOW_TOAST_POSITION: positions.bottomLeft,
    MSG_SOURCE: "SCRIPTS_AUTO_WEB_FULLSCREEN",
    QQ_VID_REG: /v.qq.com\/x/,
    ACFUN_VID_REG: /acfun.cn\/v/,
    IQIYI_VID_REG: /iqiyi.com\/v_*/,
    BILI_VID_REG: /bilibili.com\/video/,
    SYMBOL: Object.freeze({
      ADD: "+",
      SUBTRACT: "-",
      MULTIPLY: "×",
      DIVIDE: "÷"
    })
  });
  const selectorConfig = {
    "live.bilibili.com": { webfull: "#businessContainerElement" },
    "www.bilibili.com": { webfull: "div[aria-label='网页全屏']", next: ".bpx-player-ctrl-next" },
    "live.acfun.cn": { full: ".fullscreen-screen", webfull: ".fullscreen-web", danmaku: ".danmaku-enabled" },
    "tv.sohu.com": { full: ".x-fullscreen-btn", webfull: ".x-pagefs-btn", danmaku: ".tm-tmbtn", next: ".x-next-btn" },
    "haokan.baidu.com": { full: ".art-icon-fullscreen", webfull: ".art-control-fullscreenWeb", next: ".art-control-next" },
    "www.iqiyi.com": { full: ".iqp-btn-fullscreen", webfull: ".iqp-btn-webscreen", danmaku: "#barrage_switch", next: ".iqp-btn-next" },
    "www.mgtv.com": { full: ".fullscreenBtn i", webfull: ".webfullscreenBtn i", danmaku: "div[class*='danmuSwitch']", next: ".icon-next" },
    "v.qq.com": { full: ".txp_btn_fullscreen", webfull: "div[aria-label='网页全屏']", danmaku: ".barrage-switch", next: ".txp_btn_next_u" },
    "v.pptv.com": { full: ".w-zoom-container > div", webfull: ".w-expand-container > div", danmaku: ".w-barrage", next: ".w-next-container" },
    "www.acfun.cn": { full: ".fullscreen-screen", webfull: ".fullscreen-web", danmaku: ".danmaku-enabled", next: ".btn-next-part .control-btn" },
    "v.youku.com": { full: "#fullscreen-icon", webfull: "#webfullscreen-icon", danmaku: "div[class*='switch-img_12hDa turn-']", next: ".kui-next-icon-0" }
  };
  const VideoListenerHandler = {
    loadedmetadata() {
      this.volume = 1;
      this.isToast = false;
    },
    loadeddata() {
      this.volume = 1;
      this.isToast = false;
    },
    timeupdate() {
      if (isNaN(this.duration)) return;
      if (!App.isIqiyi()) this.isToast = false;
      const cachePlayRate = App.getCachePlayRate();
      if (!cachePlayRate || cachePlayRate === this.playbackRate) return;
      if (!App.setPlayRate(cachePlayRate) || this.isToast) return;
      App.playRateToast();
      this.isToast = true;
    },
    canplay() {
      this.play();
    },
    play() {
      this.isEnded = false;
      App.webFullScreen(this);
    },
    ended() {
      this.isEnded = true;
      this.isToast = false;
      if (!App.isBili() && !App.isAcFun()) return;
      const pod = App.query(".video-pod");
      const pods = App.querys('.video-pod .switch-btn:not(.on), .video-pod__item:last-of-type[data-scrolled="true"]');
      if (!pod || pods.length > 0) App.exitWebFullScreen();
    }
  };
  const douyu = {
    getRoot() {
      return document.querySelector("demand-video").shadowRoot;
    },
    getControllerBar() {
      return this.getRoot().querySelector("#demandcontroller-bar").shadowRoot;
    },
    getVideo() {
      return this.getRoot().querySelector("video");
    },
    play() {
      this.getControllerBar().querySelector(".ControllerBarPlay")?.click();
    },
    pause() {
      this.getControllerBar().querySelector(".ControllerBarStop")?.click();
    },
    getWebfullIcon() {
      return this.getControllerBar().querySelector(".ControllerBar-PageFull-Icon");
    },
    getFullIcon() {
      return this.getControllerBar().querySelector(".ControllerBar-WindowFull-Icon");
    },
    getDanmakuIcon() {
      return document.querySelector("demand-player-extension").shadowRoot.querySelector(".BarrageSwitch-icon");
    },
    addStyle() {
      const root = this.getRoot();
      let style = root.querySelector("style");
      if (style) return;
      style = document.createElement("style");
      style.textContent = `
      .showToast {
        color: #fff !important;
        font-size: 13.5px !important;
        padding: 5px 15px !important;
        border-radius: 5px !important;
        position: absolute !important;
        z-index: 2147483647 !important;
        font-weight: normal !important;
        transition: opacity 500ms ease-in;
        background: rgba(0, 0, 0, 0.75) !important;
      }
    `;
      root.prepend(style);
    }
  };
  var _GM_addValueChangeListener = /* @__PURE__ */ (() => typeof GM_addValueChangeListener != "undefined" ? GM_addValueChangeListener : void 0)();
  var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
  var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  var _GM_unregisterMenuCommand = /* @__PURE__ */ (() => typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)();
  var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  const {
    EMPTY: EMPTY$1,
    ONE_SEC,
    MSG_SOURCE: MSG_SOURCE$1,
    QQ_VID_REG,
    BILI_VID_REG,
    IQIYI_VID_REG,
    ACFUN_VID_REG,
    SHOW_TOAST_TIME,
    SHOW_TOAST_POSITION
  } = constants;
  const matches = _GM_info.script.matches.filter((match) => match !== "*://*/*").map((match) => match.replace(/\*/g, "\\S+"));
  const App = {
    init() {
      this.setupHoverListener();
      this.setupVisibleListener();
      this.setupKeydownListener();
      this.setupMutationObserver();
      this.setupUrlChangeListener();
    },
    isTopWin: () => window.top === window,
    isDouyu: () => location.host === "v.douyu.com",
    isBili: () => BILI_VID_REG.test(location.href),
    isTencent: () => QQ_VID_REG.test(location.href),
    isIqiyi: () => IQIYI_VID_REG.test(location.href),
    isAcFun: () => ACFUN_VID_REG.test(location.href),
    isLivePage: () => location.href.includes("live"),
    isBiliLive: () => location.host === "live.bilibili.com",
    query: (selector, context) => (context || document).querySelector(selector),
    querys: (selector, context) => (context || document).querySelectorAll(selector),
    validVideoDur: (video) => !isNaN(video.duration) && video.duration !== Infinity,
    inMatches: () => matches.some((matche) => new RegExp(matche).test(location.href)),
    isElementVisible: (element) => element?.offsetWidth > 0 && element?.offsetHeight > 0,
    postMessage: (win = null, data) => win?.postMessage({ source: MSG_SOURCE$1, ...data }, "*"),
    log: (...data) => console.log(...["%c******* 脚本日志 *******\n", "color:green;font-size:16px;", ...data]),
    dispatchClick: (element) => element?.dispatchEvent(new MouseEvent("click", { bubbles: true })),
    normalWebsite() {
      return !this.videoCenterPoint;
    },
    getVideo() {
      if (this.isDouyu()) return douyu.getVideo();
      return this.query("video:not([loop]):not([src=''])") || this.query("video:not([loop])");
    },
    getElement() {
      if (this.isDouyu()) return douyu.getWebfullIcon();
      return document.querySelector(selectorConfig[location.host]?.webfull);
    },
    getVideoIframe() {
      if (!this.videoCenterPoint?.frameSrc) return null;
      const url = new URL(this.videoCenterPoint.frameSrc);
      const src = decodeURI(url.pathname + url.search);
      return this.query(`iframe[src*="${src}"]`);
    },
    debounce(fn, delay = ONE_SEC) {
      let timer;
      return function() {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => fn.apply(this, arguments), delay);
      };
    },
    setupVisibleListener() {
      window.addEventListener("visibilitychange", () => {
        window.top.focus();
        if (this.normalWebsite()) return;
        const video = this.isLivePage() ? this.getVideo() : this.video;
        if (video?.isEnded || !this.isElementVisible(video)) return;
        document.hidden ? video?.pause() : video?.play();
      });
    },
    setupHoverListener() {
      if (this.inMatches()) return;
      document.addEventListener("mouseover", (event) => {
        const x = event.clientX;
        const y = event.clientY;
        const videos = this.querys("video");
        for (const video of videos) {
          const rect = video.getBoundingClientRect();
          const isWiderThanWindow = video.offsetWidth > window.innerWidth;
          const isInRect = rect.left <= x && rect.right >= x && rect.top <= y && rect.bottom >= y;
          if (!isInRect || !this.validVideoDur(video) || isWiderThanWindow) continue;
          if (this.video === video) return;
          this.addVideoEvtListener(video);
        }
      });
    },
    setupUrlChangeListener() {
      const _wr = (method) => {
        const original = history[method];
        history[method] = function() {
          original.apply(history, arguments);
          window.dispatchEvent(new Event(method));
        };
      };
      const handler = this.debounce(() => this.setupMutationObserver());
      ["popstate", "pushState", "replaceState"].forEach((t) => _wr(t) & window.addEventListener(t, handler));
    },
    setupMutationObserver() {
      const observer = new MutationObserver(() => {
        const video = this.getVideo();
        this.element = this.getElement();
        if (video?.play) this.setupVideoListener();
        if (!this.inMatches() && this.video) return observer.disconnect();
        if (!video?.play || !this.element || !this.webFullScreen(video)) return;
        observer.disconnect();
        this.biliLiveExtras();
        this.webSiteLoginObserver();
      });
      observer.observe(document.body, { childList: true, subtree: true });
      setTimeout(() => observer.disconnect(), ONE_SEC * 10);
    },
    video: null,
    videoBoundListeners: [],
    setupVideoListener() {
      const video = this.getVideo();
      this.addVideoEvtListener(video);
      this.healthCurrentVideo();
    },
    addVideoEvtListener(video) {
      this.video = video;
      this.setVideoCenterPoint(video);
      if (this.isLivePage()) return;
      this.removeVideoEvtListener();
      for (const type of Object.keys(VideoListenerHandler)) {
        const handler = VideoListenerHandler[type];
        this.video.addEventListener(type, handler);
        this.videoBoundListeners.push([this.video, type, handler]);
      }
    },
    removeVideoEvtListener() {
      this.videoBoundListeners.forEach((listener) => {
        const [target, type, handler] = listener;
        target.removeEventListener(type, handler);
      });
      this.videoBoundListeners = [];
    },
    getPlayingVideo() {
      const videos = this.querys("video");
      for (const video of videos) {
        const isWiderThanWindow = video.offsetWidth > window.innerWidth;
        if (this.video === video || video.paused || !this.validVideoDur(video) || isWiderThanWindow) continue;
        return this.addVideoEvtListener(video);
      }
    },
    healthCurrentVideo() {
      if (this.healthID) clearInterval(this.healthID);
      this.healthID = setInterval(() => this.getPlayingVideo(), ONE_SEC);
    },
    setVideoCenterPoint(video) {
      const { left, top, width, height } = video.getBoundingClientRect();
      const videoCenterPoint = { x: left + width / 2, y: top + height / 2, src: video.src };
      this.setParentFrameSrc(videoCenterPoint);
    },
    setParentFrameSrc(videoCenterPoint) {
      this.videoCenterPoint = videoCenterPoint;
      if (this.isTopWin()) return this.setupScriptMenuCommand();
      videoCenterPoint.frameSrc = location.href;
      this.postMessage(window.parent, { videoCenterPoint });
    },
    showToast(content, duration = SHOW_TOAST_TIME) {
      if (this.isDouyu()) douyu.addStyle();
      const el = document.createElement("div");
      if (content instanceof HTMLElement) el.appendChild(content);
      if (Object.is(typeof content, typeof EMPTY$1)) el.textContent = content;
      el.setAttribute("class", "showToast");
      el.setAttribute("style", SHOW_TOAST_POSITION);
      const target = this.video?.parentElement?.parentElement;
      this.query(".showToast", target)?.remove();
      target?.appendChild(el);
      setTimeout(() => {
        el.style.opacity = 0;
        setTimeout(() => el.remove(), ONE_SEC / 2);
      }, duration);
    }
  };
  const setStorage = function(value) {
    _GM_setValue(this.name, value);
  };
  const getStorage = function(defaultValue) {
    return _GM_getValue(this.name, defaultValue);
  };
  const storage = {
    CACHED_PLAY_RATE: Object.freeze({
      name: "FENY_SCRIPTS_V_PLAYBACK_RATE",
      set(value) {
        localStorage.setItem(this.name, value);
      },
      get() {
        return localStorage.getItem(this.name);
      }
    }),
    PLAY_RATE_STEP: Object.freeze({
      name: "PLAY_RATE_STEP",
      set: setStorage,
      get() {
        return Number.parseFloat(getStorage.bind(this, 0.25)());
      }
    }),
    VIDEO_FASTFORWARD_DURATION: Object.freeze({
      name: "VIDEO_FASTFORWARD_DURATION",
      set: setStorage,
      get() {
        return Number.parseInt(getStorage.bind(this, 30)());
      }
    }),
    VIDEO_TIME_STEP: Object.freeze({
      name: "VIDEO_TIME_STEP",
      set: setStorage,
      get() {
        return Number.parseInt(getStorage.bind(this, 5)());
      }
    }),
    CLOSE_AUTO_WEB_FULL: Object.freeze({
      name: "CLOSE_AUTO_WEB_FULL_SCREEN",
      set: setStorage,
      get() {
        return getStorage.bind(this, false)();
      }
    }),
    OVERRIDE_KEYBOARD: Object.freeze({
      name: "OVERRIDE_KEYBOARD",
      set: setStorage,
      get() {
        return getStorage.bind(this, false)();
      }
    })
  };
  const eventCode = Object.freeze({
    KeyA: "KeyA",
    KeyD: "KeyD",
    KeyF: "KeyF",
    KeyN: "KeyN",
    KeyP: "KeyP",
    KeyS: "KeyS",
    KeyZ: "KeyZ",
    Space: "Space",
    ArrowLeft: "ArrowLeft",
    ArrowRight: "ArrowRight",
    NumpadAdd: "NumpadAdd",
    NumpadSubtract: "NumpadSubtract"
  });
  const { VIDEO_TIME_STEP: VIDEO_TIME_STEP$1, VIDEO_FASTFORWARD_DURATION: VIDEO_FASTFORWARD_DURATION$1 } = storage;
  const { EMPTY, SYMBOL: SYMBOL$1, MSG_SOURCE } = constants;
  const KeydownHandler = {
    isNumberKey: (key) => /^[0-9]$/.test(key),
    preventDefault(event) {
      const overrideKey = [eventCode.Space, eventCode.ArrowLeft, eventCode.ArrowRight];
      const isOverrideKey = this.isOverrideKeyboard() && overrideKey.includes(event.code);
      if (!this.isNumberKey(event.key) && !isOverrideKey) return;
      event.preventDefault();
      event.stopPropagation();
      event.stopImmediatePropagation();
    },
    setupKeydownListener() {
      window.addEventListener("keyup", (event) => this.preventDefault(event), true);
      window.addEventListener("keydown", (event) => this.keydownHandler.call(this, event), true);
      window.addEventListener("message", (event) => {
        const { data } = event;
        if (!data?.source || !data.source.includes(MSG_SOURCE)) return;
        if (data?.videoCenterPoint) return this.setParentFrameSrc(data.videoCenterPoint);
        this.processEvent(data);
      });
    },
    keydownHandler(event) {
      if (this.normalWebsite()) return;
      let key = event.key.toUpperCase();
      const { code, target, shiftKey } = event;
      if (["INPUT", "TEXTAREA", "DEMAND-SEARCH-BOX"].includes(target.tagName)) return;
      if (!Object.keys(eventCode).includes(code) && !this.isNumberKey(key)) return;
      this.preventDefault(event);
      if (eventCode.Space === code) key = eventCode.Space.toUpperCase();
      if (shiftKey && eventCode.NumpadAdd === code) key = SYMBOL$1.MULTIPLY;
      if (shiftKey && eventCode.NumpadSubtract === code) key = SYMBOL$1.DIVIDE;
      if (!this.isTopWin() && eventCode.KeyP === code) return this.postMessage(window.top, { key });
      this.processEvent({ key });
    },
    processEvent(data) {
      if (!this.video) this.postMsgToFrames(data);
      if (data?.key) this.execHotKeyActions(data.key);
    },
    execHotKeyActions(key) {
      if (this.normalWebsite()) return;
      const keyMapping = this.getKeyMapping();
      if (keyMapping[key]) return keyMapping[key]();
      if (this.isNumberKey(key)) this.setPlayRate(key) && this.playRateToast();
    },
    getKeyMapping() {
      return {
        N: () => this.triggerIconElement("next"),
        A: () => this.adjustPlayRate(SYMBOL$1.ADD),
        S: () => this.adjustPlayRate(SYMBOL$1.SUBTRACT),
        [SYMBOL$1.ADD]: () => this.adjustPlayRate(SYMBOL$1.ADD),
        [SYMBOL$1.SUBTRACT]: () => this.adjustPlayRate(SYMBOL$1.SUBTRACT),
        [SYMBOL$1.MULTIPLY]: () => this.adjustPlayRate(SYMBOL$1.MULTIPLY),
        [SYMBOL$1.DIVIDE]: () => this.adjustPlayRate(SYMBOL$1.DIVIDE),
        Z: () => this.setPlayRate(1) && this.showToast("已恢复正常倍速播放"),
        F: () => this.isDouyu() ? douyu.getFullIcon().click() : this.triggerIconElement("full", 0),
        D: () => this.isDouyu() ? douyu.getDanmakuIcon().click() : this.triggerIconElement("danmaku", 3),
        ARROWLEFT: () => this.isOverrideKeyboard() ? this.adjustVideoTime(SYMBOL$1.SUBTRACT) : null,
        ARROWRIGHT: () => this.isOverrideKeyboard() ? this.adjustVideoTime() : null,
        0: () => this.adjustVideoTime(VIDEO_FASTFORWARD_DURATION$1.get()),
        P: () => {
          if (!this.inMatches()) return this.enhance();
          if (this.isDouyu()) return douyu.getWebfullIcon().click();
          this.isBiliLive() ? this.biliLiveWebFullScreen() : this.triggerIconElement("webfull");
        },
        SPACE: () => {
          if (!this.video || !this.isOverrideKeyboard()) return;
          if (this.isDouyu()) return this.video.paused ? douyu.play() : douyu.pause();
          this.video.paused ? this.video.play() : this.video.pause();
        }
      };
    },
    triggerIconElement(name, index) {
      if (!this.inMatches()) return;
      if (this.isBiliLive()) return this.getBiliLiveIcons()?.[index]?.click();
      this.query(selectorConfig[location.host]?.[name])?.click();
    },
    adjustVideoTime(second = VIDEO_TIME_STEP$1.get(), _symbol) {
      if (!this.video || !this.validVideoDur(this.video)) return;
      if (_symbol && ![SYMBOL$1.ADD, SYMBOL$1.SUBTRACT].includes(_symbol)) return;
      if (Object.is(typeof second, typeof EMPTY) && !_symbol) {
        _symbol = second;
        second = VIDEO_TIME_STEP$1.get();
      }
      second = Object.is(SYMBOL$1.SUBTRACT, _symbol) ? -second : second;
      const currentTime = this.video.currentTime + second;
      this.video.currentTime = Math.max(0, currentTime);
    },
    postMsgToFrames(data) {
      this.querys("iframe:not([src=''])").forEach((iframe) => this.postMessage(iframe.contentWindow, data));
    }
  };
  const { PLAY_RATE_STEP: PLAY_RATE_STEP$1, VIDEO_TIME_STEP, OVERRIDE_KEYBOARD, CLOSE_AUTO_WEB_FULL, VIDEO_FASTFORWARD_DURATION } = storage;
  const MenuCommandHandler = {
    isCloseAuto: () => CLOSE_AUTO_WEB_FULL.get(),
    isOverrideKeyboard: () => OVERRIDE_KEYBOARD.get(),
    setupScriptMenuCommand() {
      if (!this.isTopWin() || this.isLivePage()) return;
      this.registerMenuCommand();
      this.setupCommandChangeListener();
    },
    registerMenuCommand() {
      this.registerPlayRateCommand();
      this.registerVideoTimeCommand();
      this.registerFastforwardCommand();
      this.registerCloseAutoFullCommand();
      this.registerOverrideKeyboardCommand();
    },
    setupCommandChangeListener() {
      if (this.isSetupCommandChangeListener) return;
      const handler = () => this.registerMenuCommand();
      [OVERRIDE_KEYBOARD.name, CLOSE_AUTO_WEB_FULL.name].forEach((key) => _GM_addValueChangeListener(key, handler));
      this.isSetupCommandChangeListener = true;
    },
    registerPlayRateCommand() {
      const title = "设置倍速步进";
      _GM_unregisterMenuCommand(this.play_rate_command_id);
      this.play_rate_command_id = _GM_registerMenuCommand(title, () => {
        const input = prompt(title, PLAY_RATE_STEP$1.get());
        if (!isNaN(input) && Number.parseFloat(input)) PLAY_RATE_STEP$1.set(input);
      });
    },
    registerVideoTimeCommand() {
      const title = "设置快进/快退秒数";
      _GM_unregisterMenuCommand(this.video_time_command_id);
      this.video_time_command_id = _GM_registerMenuCommand(title, () => {
        const input = prompt(title, VIDEO_TIME_STEP.get());
        if (!isNaN(input) && Number.parseInt(input)) VIDEO_TIME_STEP.set(input);
      });
    },
    registerFastforwardCommand() {
      const title = "设置数字零键快进秒数";
      _GM_unregisterMenuCommand(this.fastforward_command_id);
      this.fastforward_command_id = _GM_registerMenuCommand(title, () => {
        const input = prompt(title, VIDEO_FASTFORWARD_DURATION.get());
        if (!isNaN(input) && Number.parseInt(input)) VIDEO_FASTFORWARD_DURATION.set(input);
      });
    },
    registerCloseAutoFullCommand() {
      if (!this.inMatches()) return;
      const isClose = this.isCloseAuto();
      const title = isClose ? "开启自动网页全屏" : "关闭自动网页全屏";
      _GM_unregisterMenuCommand(this.close_auto_command_id);
      this.close_auto_command_id = _GM_registerMenuCommand(title, () => CLOSE_AUTO_WEB_FULL.set(!isClose));
    },
    registerOverrideKeyboardCommand() {
      const isOverride = this.isOverrideKeyboard();
      const title = isOverride ? "关闭 空格 ◀▶ 键控制" : "开启 空格 ◀▶ 键控制";
      _GM_unregisterMenuCommand(this.override_keyboard_command_id);
      this.override_keyboard_command_id = _GM_registerMenuCommand(title, () => OVERRIDE_KEYBOARD.set(!isOverride));
    }
  };
  const WebSiteLoginHandler = {
    webSiteLoginObserver() {
      this.handleIqyLogin();
      this.handleBiliLogin();
      this.handleTencentLogin();
    },
    elementObserver(target, matches2, clickTarget) {
      const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          if (mutation.addedNodes.length === 0) return;
          mutation.addedNodes.forEach((node) => {
            if (node.nodeType !== Node.ELEMENT_NODE) return;
            if (!node.matches(matches2)) return;
            this.query(clickTarget)?.click();
            observer.disconnect();
          });
        });
      });
      target = target instanceof HTMLElement ? target : this.query(target);
      observer.observe(target, { attributes: true, childList: true, subtree: true });
    },
    handleTencentLogin() {
      if (!this.isTencent()) return;
      const selector = ".main-login-wnd-module_close-button__mt9WU";
      this.elementObserver("#login_win", selector, selector);
    },
    handleIqyLogin() {
      if (!this.isIqiyi()) return;
      const selector = ".simple-buttons_close_btn__6N7HD";
      this.elementObserver("#qy_pca_login_root", selector, selector);
      const observer = new MutationObserver(() => {
        const selector2 = ":is(*[id*='mask-layer'], #modal-vip-cashier-scope)";
        this.querys(selector2).forEach((el) => el.remove());
        this.query(".simple-buttons_close_btn__6N7HD")?.click();
        const adTime = this.query(".public-time");
        if (adTime.style.display === "none") return;
        if (this.video.currentTime !== this.video.duration) return;
        this.querys("*:not(.public-vip)", adTime).forEach((el) => el.click());
      });
      observer.observe(this.query(".cd-time"), { attributes: true, childList: true, subtree: true });
    },
    handleBiliLogin() {
      if (!this.isBili()) return;
      if (document.cookie.includes("DedeUserID")) return player?.requestQuality(80);
      setTimeout(() => {
        _unsafeWindow.__BiliUser__.isLogin = true;
        _unsafeWindow.__BiliUser__.cache.data.isLogin = true;
        _unsafeWindow.__BiliUser__.cache.data.mid = Date.now();
      }, constants.ONE_SEC * 3);
    }
  };
  const WebFullScreenHandler = {
    isFull() {
      return window.innerWidth === this.video.offsetWidth;
    },
    webFullScreen(video) {
      const w = video?.offsetWidth || 0;
      if (Object.is(0, w)) return false;
      if (this.isCloseAuto()) return true;
      if (window.innerWidth === w || w > window.innerWidth) return true;
      if (!this.isBiliLive()) return this.dispatchClick(this.element);
      return this.biliLiveWebFullScreen();
    },
    biliLiveWebFullScreen() {
      const control = this.getBiliLiveIcons();
      if (control.length === 0) return false;
      const win = _unsafeWindow.top;
      win.scrollTo({ top: 70 });
      const el = this.query(":is(.lite-room, #player-ctnr)", win.document);
      if (el) win.scrollTo({ top: el?.getBoundingClientRect()?.top || 0 });
      return this.dispatchClick(control[1]);
    },
    exitWebFullScreen() {
      if (window.innerWidth === this.video.offsetWidth) this.getElement()?.click();
      const cancelButton = this.query(".bpx-player-ending-related-item-cancel");
      if (cancelButton) setTimeout(() => cancelButton.click(), 100);
    },
    biliLiveExtras() {
      _unsafeWindow.top?.livePlayer?.volume(100);
      _unsafeWindow.top?.livePlayer?.switchQuality("10000");
      localStorage.setItem("FULLSCREEN-GIFT-PANEL-SHOW", 0);
      document.body.classList.add("hide-asida-area", "hide-aside-area");
    },
    getBiliLiveIcons() {
      const video = this.getVideo();
      if (!video) return [];
      this.dispatchMousemoveEvent(video);
      return this.querys("#web-player-controller-wrap-el .right-area .icon");
    },
    dispatchMousemoveEvent(target) {
      const offsetWidth = target.offsetWidth;
      const clientY = target.offsetHeight / 2;
      const moveEvt = (clientX) => {
        const dict = { clientX, clientY, bubbles: true };
        const mousemove = new MouseEvent("mousemove", dict);
        target.dispatchEvent(mousemove);
      };
      for (let i = 0; i < offsetWidth; i += 100) moveEvt(i);
    }
  };
  const ScriptsEnhanceHandler = {
    enhance() {
      this.triggerMouseoverEvent(this.getHoverElement());
      this.triggerEscapeEvent();
    },
    getHoverElement() {
      if (!this.videoCenterPoint) return;
      if (this.hoverElement) return this.hoverElement;
      if (this.video) return this.hoverElement = this.video?.parentElement?.parentElement;
      const iframe = this.getVideoIframe();
      if (iframe) return this.hoverElement = iframe;
      const { x, y } = this.videoCenterPoint;
      const iframes = this.querys("iframe:not([src=''])");
      for (const element of iframes) {
        const rect = element.getBoundingClientRect();
        const isInRect = x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
        if (!isInRect) continue;
        return this.hoverElement = element;
      }
    },
    triggerMouseoverEvent(element) {
      console.log("鼠标悬停网页全屏元素:", element);
      if (!element) return;
      const clientX = element.offsetWidth / 2;
      const clientY = element.offsetHeight / 2;
      const dict = { clientX, clientY, bubbles: true };
      const mouseover = new MouseEvent("mouseover", dict);
      element?.dispatchEvent(mouseover);
    },
    triggerEscapeEvent() {
      if (!this.video || !this.hoverElement) return;
      const dict = { key: "Escape", keyCode: 27, bubbles: true };
      const keydown = new KeyboardEvent("keydown", dict);
      document?.dispatchEvent(keydown);
    }
  };
  const { PLAY_RATE_STEP, CACHED_PLAY_RATE } = storage;
  const { SYMBOL, DEF_PLAY_RATE, MAX_PLAY_RATE } = constants;
  const strategy = {
    [SYMBOL.MULTIPLY]: (playRate) => playRate * 2,
    [SYMBOL.DIVIDE]: (playRate) => playRate / 2,
    [SYMBOL.ADD]: (playRate) => playRate + PLAY_RATE_STEP.get(),
    [SYMBOL.SUBTRACT]: (playRate) => playRate - PLAY_RATE_STEP.get()
  };
  const VideoPlaybackRateHandler = {
    checkVideoUsable() {
      if (!this.video) return false;
      if (this.isLivePage()) return false;
      return true;
    },
    setPlayRate(playRate) {
      if (!this.checkVideoUsable()) return;
      this.video.playbackRate = playRate;
      this.cachePlayRate();
      return true;
    },
    adjustPlayRate(_symbol) {
      if (!this.checkVideoUsable()) return;
      let playRate = this.video.playbackRate;
      playRate = strategy[_symbol](playRate);
      playRate = Math.max(PLAY_RATE_STEP.get(), playRate);
      this.video.playbackRate = Math.min(MAX_PLAY_RATE, playRate);
      this.cachePlayRate();
      this.playRateToast();
    },
    cachePlayRate() {
      CACHED_PLAY_RATE.set(this.video.playbackRate);
    },
    getCachePlayRate: () => Number.parseFloat(CACHED_PLAY_RATE.get() || DEF_PLAY_RATE),
    playRateToast() {
      const span = document.createElement("span");
      span.appendChild(document.createTextNode("正在以"));
      const child = span.cloneNode(true);
      child.textContent = `${this.video.playbackRate.toFixed(2).replace(/\.?0+$/, "")}x`;
      child.setAttribute("style", "margin:0 3px!important;color:#ff6101!important;");
      span.appendChild(child);
      span.appendChild(document.createTextNode("倍速播放"));
      this.showToast(span);
    }
  };
  const logicHandlers = [
    { handler: KeydownHandler },
    { handler: MenuCommandHandler },
    { handler: WebSiteLoginHandler },
    { handler: WebFullScreenHandler },
    { handler: VideoPlaybackRateHandler },
    { handler: ScriptsEnhanceHandler }
  ];
  logicHandlers.forEach(({ handler }) => {
    for (const key of Object.keys(handler)) {
      const method = handler[key];
      method instanceof Function ? App[key] = method.bind(App) : App[key] = method;
    }
  });
  App.init();

})();