HTML5 视频增强脚本

脚本基于 Violentmonkey 开发,为 HTML5 视频,添加一些通用功能

目前為 2022-07-09 提交的版本,檢視 最新版本

// ==UserScript==
// @name              HTML5 视频增强脚本
// @version           1657356111
// @description       脚本基于 Violentmonkey 开发,为 HTML5 视频,添加一些通用功能
// @author            So
// @namespace         https://github.com/Git-So/video-userscript
// @homepageURL       https://github.com/Git-So/video-userscript
// @supportURL        https://github.com/Git-So/video-userscript/issues
// @match             http://*/*
// @match             https://*/*
// @grant             GM_addStyle
// ==/UserScript==

var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
(function() {
  "use strict";
  GM_addStyle(`
@charset "UTF-8";
@keyframes toast-show {
  from {
    opacity: 0;
  }
  25% {
    opacity: 1;
  }
  75% {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
.sooo--video {
  /**
  * 动作提示
  */
  /**
  * 关灯影院模式
  */
  /**
  * 视频镜像
  */
}
.sooo--video-action-toast {
  position: absolute !important;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  padding: 10px 15px;
  font-size: 1.5em;
  color: whitesmoke;
  background-color: rgba(0, 0, 0, 0.555);
  z-index: 9000;
}
.sooo--video-action-toast-animation {
  animation: toast-show 1.2s alternate forwards;
}
.sooo--video-movie-mode {
  z-index: 99999999 !important;
}
.sooo--video-movie-mode-parent {
  z-index: auto !important;
}
.sooo--video-movie-mode-modal {
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  position: fixed !important;
  background: rgba(0, 0, 0, 0.9);
  z-index: 1000000;
}
.sooo--video-mirror video {
  transform: rotateX(0deg) rotateY(180deg);
}  `);
  var style = "";
  const value = [
    {
      match: `^https?://www.bilibili.com/video/`,
      player: "#bilibili-player .bpx-player-container .bpx-player-video-area"
    }
  ];
  class Video {
    rule() {
      for (const rule of value) {
        const rg = new RegExp(rule.match);
        if (location.href.search(rg) > -1)
          return rule;
      }
      return null;
    }
    defaultMedia() {
      var _a;
      const items = document.querySelectorAll("video");
      let media = (_a = items[0]) != null ? _a : null;
      for (const item of items) {
        if (!item.paused)
          break;
        media = item;
      }
      return media;
    }
    defaultPlayer(media = null) {
      let player = media != null ? media : this.defaultMedia();
      if (!player)
        return null;
      return actionByAncestor(player, (parent) => {
        return parent.clientHeight == (player == null ? void 0 : player.clientHeight) && parent.clientWidth == (player == null ? void 0 : player.clientWidth);
      });
    }
    media() {
      const rule = this.rule();
      if (rule) {
        if (rule.media)
          return document.querySelector(rule.media);
        return document.querySelector(`${rule.player} video`);
      }
      return this.defaultMedia();
    }
    player(media = null) {
      const rule = this.rule();
      if (rule)
        return document.querySelector(rule.player);
      return this.defaultPlayer(media);
    }
  }
  function actionByAncestor(element, action) {
    for (let _i = 0; _i < 500; _i++) {
      const parent = element.parentElement;
      if (!parent || parent.tagName == "BODY")
        break;
      if (!action(parent))
        break;
      element = parent;
    }
    return element;
  }
  function reanimation(func) {
    window.requestAnimationFrame(() => window.requestAnimationFrame(() => {
      func();
    }));
  }
  function toast(player, text) {
    if (!player)
      return;
    const className = "sooo--video-action-toast";
    const animationClassName = "sooo--video-action-toast-animation";
    if (!player.querySelector(`.${className}`)) {
      const element = document.createElement("DIV");
      element.classList.add(className);
      player.append(element);
    }
    const toast2 = player.querySelector(`.${className}`);
    toast2.classList.remove(animationClassName);
    toast2.innerHTML = "";
    toast2.append(text);
    reanimation(() => {
      toast2.classList.add(animationClassName);
    });
  }
  function isActiveElementEditable() {
    const activeElement = document.activeElement;
    if (!activeElement)
      return false;
    if (activeElement.isContentEditable)
      return true;
    if ("value" in activeElement)
      return true;
    return false;
  }
  function isExistMedia() {
    return !!new Video().media();
  }
  function between(value2, min = 0, max = 1) {
    if (value2 < min)
      return min;
    if (value2 > max)
      return max;
    return value2;
  }
  class Action {
    constructor() {
      __publicField(this, "_name", "");
      __publicField(this, "video", new Video());
      __publicField(this, "_media", null);
      __publicField(this, "_player", null);
    }
    get name() {
      return this._name;
    }
    get media() {
      if (!this._media)
        this._media = this.video.media();
      return this._media;
    }
    get player() {
      if (!this._player)
        this._player = this.video.player(this.media);
      return this._player;
    }
    safeAction(action, that = this) {
      if (!this.media)
        return;
      action.apply(that);
    }
    toast(text) {
      toast(this.player, text);
    }
  }
  class SwitchAction extends Action {
    get isEnable() {
      return false;
    }
    enableAction() {
    }
    enable() {
      this.safeAction(this.enableAction);
      this.toast(`${this.name}: \u5F00`);
    }
    disableAction() {
    }
    disable() {
      this.safeAction(this.disableAction);
      this.toast(`${this.name}: \u5173`);
    }
    toggle() {
      this.isEnable ? this.disable() : this.enable();
    }
  }
  class StepAction extends Action {
    constructor() {
      super(...arguments);
      __publicField(this, "step", 1);
    }
    setValue(_value, _isStep = true) {
    }
    add(step = this.step) {
      this.setValue(+step);
    }
    sub(step = this.step) {
      this.setValue(-step);
    }
  }
  class Fullscreen extends SwitchAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u89C6\u9891\u5168\u5C4F");
    }
    get isEnable() {
      return !!document.fullscreenElement;
    }
    enableAction() {
      var _a;
      (_a = this.player) == null ? void 0 : _a.requestFullscreen();
    }
    disableAction() {
      document.exitFullscreen();
    }
  }
  class PlayState extends SwitchAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u89C6\u9891\u64AD\u653E");
    }
    get isEnable() {
      var _a;
      return !((_a = this.media) == null ? void 0 : _a.paused);
    }
    enableAction() {
      var _a;
      (_a = this.media) == null ? void 0 : _a.play();
    }
    disableAction() {
      var _a;
      (_a = this.media) == null ? void 0 : _a.pause();
    }
  }
  class PictureInPicture extends SwitchAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u753B\u4E2D\u753B");
    }
    get isEnable() {
      return !!document.pictureInPictureElement;
    }
    enableAction() {
      var _a;
      (_a = this.media) == null ? void 0 : _a.requestPictureInPicture();
    }
    disableAction() {
      if (!this.isEnable)
        return;
      document.exitPictureInPicture();
    }
  }
  class CurrentTime extends StepAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u89C6\u9891\u8FDB\u5EA6");
      __publicField(this, "step", 10);
    }
    setValue(value2, isStep = true) {
      this.safeAction(() => {
        const currentTime = isStep ? this.media.currentTime + value2 : value2;
        this.media.currentTime = currentTime;
        this.toast(`${this.name}: ${value2 < 0 ? "" : "+"}${value2}\u79D2`);
      });
    }
  }
  class Volume extends StepAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u97F3\u91CF");
      __publicField(this, "step", 0.1);
    }
    setValue(value2, isStep = true) {
      this.safeAction(() => {
        const volume = isStep ? this.media.volume + value2 : value2;
        this.media.volume = between(volume, 0, 1);
        this.toast(`${this.name}:${this.media.volume * 100 | 0}% `);
      });
    }
  }
  class PlaybackRate extends StepAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u500D\u6570\u64AD\u653E");
      __publicField(this, "step", 1);
      __publicField(this, "playbackRate", [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 5]);
      __publicField(this, "defaultIdx", 3);
    }
    get currIdx() {
      if (!this.media)
        return this.defaultIdx;
      const idx = this.playbackRate.indexOf(this.media.playbackRate);
      return idx < 0 ? this.defaultIdx : idx;
    }
    setValue(value2, isStep = true) {
      this.safeAction(() => {
        value2 = isStep ? this.currIdx + value2 : value2;
        const idx = between(value2, 0, this.playbackRate.length - 1);
        const rate = this.playbackRate[idx];
        this.media.playbackRate = rate;
        this.toast(`${this.name}: ${rate}x`);
      });
    }
    restart() {
      this.setValue(this.defaultIdx, false);
    }
  }
  class MovieMode extends SwitchAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u5F71\u9662\u6A21\u5F0F");
      __publicField(this, "className", "sooo--video-movie-mode");
      __publicField(this, "parentClassName", "sooo--video-movie-mode-parent");
      __publicField(this, "modalClassName", "sooo--video-movie-mode-modal");
    }
    get isEnable() {
      var _a;
      return !!((_a = this.player) == null ? void 0 : _a.classList.contains(this.className));
    }
    enableAction() {
      var _a;
      (_a = this.player) == null ? void 0 : _a.classList.add(this.className);
      document.body.append((() => {
        const modal = document.createElement("DIV");
        modal.className = this.modalClassName;
        return modal;
      })());
      actionByAncestor(this.player, (element) => {
        element.classList.add(this.parentClassName);
        return true;
      });
    }
    disableAction() {
      var _a, _b;
      (_a = this.player) == null ? void 0 : _a.classList.remove(this.className);
      (_b = document.querySelector(`.${this.modalClassName}`)) == null ? void 0 : _b.remove();
      document.querySelectorAll(`.${this.parentClassName}`).forEach((el) => {
        el.classList.remove(this.parentClassName);
      });
    }
  }
  class Mirror extends SwitchAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u89C6\u9891\u955C\u50CF");
      __publicField(this, "className", "sooo--video-mirror");
    }
    get isEnable() {
      var _a;
      return !!((_a = this.player) == null ? void 0 : _a.classList.contains(this.className));
    }
    enableAction() {
      var _a;
      (_a = this.player) == null ? void 0 : _a.classList.add(this.className);
    }
    disableAction() {
      var _a;
      (_a = this.player) == null ? void 0 : _a.classList.remove(this.className);
    }
  }
  class Loop extends SwitchAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u5FAA\u73AF\u64AD\u653E");
    }
    get isEnable() {
      var _a;
      return !!((_a = this.media) == null ? void 0 : _a.loop);
    }
    enableAction() {
      this.media.loop = true;
    }
    disableAction() {
      this.media.loop = false;
    }
  }
  class Muted extends SwitchAction {
    constructor() {
      super(...arguments);
      __publicField(this, "_name", "\u89C6\u9891\u9759\u97F3");
    }
    get isEnable() {
      var _a;
      return !!((_a = this.media) == null ? void 0 : _a.muted);
    }
    enableAction() {
      this.media.muted = true;
    }
    disableAction() {
      this.media.muted = false;
    }
  }
  document.addEventListener("keydown", (e) => {
    if (isActiveElementEditable() || !isExistMedia())
      return;
    let hasAction = true;
    switch (true) {
      case e.code == "Enter":
        new Fullscreen().toggle();
        break;
      case e.code == "Space":
        new PlayState().toggle();
        break;
      case (e.shiftKey && e.code == "KeyA"):
        new CurrentTime().sub();
        break;
      case (e.shiftKey && e.code == "KeyD"):
        new CurrentTime().add();
        break;
      case (e.shiftKey && e.code == "KeyW"):
        new Volume().add();
        break;
      case (e.shiftKey && e.code == "KeyS"):
        new Volume().sub();
        break;
      case (e.shiftKey && e.code == "KeyZ"):
        new PlaybackRate().sub();
        break;
      case (e.shiftKey && e.code == "KeyX"):
        new PlaybackRate().restart();
        break;
      case (e.shiftKey && e.code == "KeyC"):
        new PlaybackRate().add();
        break;
      case (e.ctrlKey && e.shiftKey && e.code == "BracketRight"):
        new PictureInPicture().toggle();
        break;
      case (e.shiftKey && e.code == "KeyO"):
        new MovieMode().toggle();
        break;
      case (e.shiftKey && e.code == "KeyH"):
        new Mirror().toggle();
        break;
      case (e.shiftKey && e.code == "KeyL"):
        new Loop().toggle();
        break;
      case (e.shiftKey && e.code == "KeyM"):
        new Muted().toggle();
        break;
      default:
        hasAction = false;
    }
    if (!hasAction)
      return;
    e.stopPropagation();
    e.stopImmediatePropagation();
    e.preventDefault();
  });
})();

QingJ © 2025

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