NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name miyoushe video mod
// @namespace https://www.miyoushe.com/
// @version 20250330
// @description 米游社视频快捷键mod
// @author Hentai
// @match https://www.miyoushe.com/*
// @icon https://img-static.mihoyo.com/favicon.ico
// @grant none
// @license MIT
// ==/UserScript==
let init = false;
let initTimer = 0;
let videoLs = [];
function load() {
initTimer = setInterval(() => {
const ls = document.querySelectorAll('.mhy-layout__main video');
if (!ls.length) return;
init = true;
videoLs = ls;
// console.info(videoLs);
clearInterval(initTimer);
initTimer = 0;
}, 100);
}
load();
document.addEventListener("keydown", keymap);
document.addEventListener("keyup", keymap_up);
window.navigation.addEventListener("navigate", (event) => {
if (initTimer) return;
init = false;
load();
});
function pickVideoDOM() {
// 如果有多个的话就要考虑选择当前的video了,可以根据窗口位置什么的判断
// 但是按照道理讲只有一个video,所以现在直接返回0
// console.info(videoLs[0]);
return videoLs[0];
}
function togglePlay() {
const dom = pickVideoDOM();
if (!dom) return;
if (dom.paused) {
dom.play();
} else {
dom.pause();
}
}
function wheelListener(e) {
const dom = pickVideoDOM();
if (!dom) return;
let volume = dom.volume * 100 + (e.deltaY < 0 ? 5 : -5);
if (volume < 0) volume = 0;
if (volume > 100) volume = 100;
dom.volume = volume / 100;
}
let keyTimer = new Map();
function keymap(e) {
//console.info(mayTyping(e.target));
if (mayTyping(e.target)) return;
// console.info(e);
const dom = pickVideoDOM();
if (!dom) return;
switch (e.key) {
case " ":
e.preventDefault();
e.stopPropagation();
togglePlay();
break;
case "ArrowUp":
e.preventDefault();
e.stopPropagation();
wheelListener({deltaY: -1});
break;
case "ArrowDown":
e.preventDefault();
e.stopPropagation();
wheelListener({deltaY: 1});
break;
case "ArrowLeft":
case "ArrowRight":
e.preventDefault();
e.stopPropagation();
//
dom.playbackRate = e.ctrlKey ? 5 : 2;
//
if (!keyTimer.get(e.key))
keyTimer.set(e.key, new Date().valueOf());
break;
case "Enter":
e.preventDefault();
e.stopPropagation();
if (e.ctrlKey)
dom.requestFullscreen();
else {
const ifFixed = document.querySelector('#videoPlayer').style.position === 'fixed';
if (ifFixed) {
document.querySelector('#videoPlayer').style.position = null;
document.querySelector('#videoPlayer').style.zIndex = null;
document.querySelector('#videoPlayer').style.left = null;
document.querySelector('#videoPlayer').style.top = null;
document.querySelector('#videoPlayer').style.width = null;
document.querySelector('#videoPlayer').style.height = null;
} else {
document.querySelector('#videoPlayer').style.position = 'fixed';
document.querySelector('#videoPlayer').style.zIndex = 999;
document.querySelector('#videoPlayer').style.left = 0;
document.querySelector('#videoPlayer').style.top = 0;
document.querySelector('#videoPlayer').style.width = '100vw';
document.querySelector('#videoPlayer').style.height = '100vh';
}
}
break;
}
}
function keymap_up(e) {
//console.info(mayTyping(e.target));
if (mayTyping(e.target)) return;
let now = new Date().valueOf();
// console.info(e);
const dom = pickVideoDOM();
if (!dom) return;
switch (e.key) {
case "ArrowLeft":
case "ArrowRight":
e.preventDefault();
e.stopPropagation();
//
dom.playbackRate = 1;
//
if (now - keyTimer.get(e.key) < 500) {
dom.currentTime += e.key === "ArrowLeft" ? -5 : 5;
}
//
keyTimer.delete(e.key);
break;
}
}
function mayTyping(target) {
if (!target) return false;
let dom = target;
while (true) {
if (dom.tagName === 'BODY') return false;
else if (dom.tagName === 'HTML') return false;
else if (dom.tagName === 'TEXTAREA') return true;
else if (dom.tagName === 'INPUT') {
switch (dom.type) {
case 'input':
case 'date':
case 'datetime':
case 'datetime-local':
case 'file':
case 'number':
case 'password':
// case 'radio':
case 'search':
case 'text':
case 'time':
case 'tel':
case 'url':
return true;
break;
}
} else if (dom.contentEditable && dom.contentEditable.toLowerCase() === 'true')
return true;
else if (!dom.parentElement) return false;
dom = dom.parentElement;
}
return false;
}