// ==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();
});
})();