HTML5 视频增强脚本

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

当前为 2022-07-14 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name              HTML5 视频增强脚本
// @version           1657804186
// @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: 18px;
  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 {
  inset: 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"
    },
    {
      match: `^https?://haokan.baidu.com/v?`,
      player: "#mse .art-video-player"
    }
  ];
  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();
  });
})();