nuko / miyoushe video mod

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