video, faster

speed up video on any site

当前为 2024-01-29 提交的版本,查看 最新版本

// ==UserScript==
// @name        video, faster
// @namespace   Violentmonkey Scripts
// @include     *://*/*
// @grant       none
// @version     2.0
// @author      KraXen72
// @description speed up video on any site
// @grant       GM_registerMenuCommand
// @grant       GM_unregisterMenuCommand
// @grant       GM_addStyle
// @license     MIT
// ==/UserScript==

// TODO
// auto look for video elements on location change
// remember speed across videos (reapply)?

// NOTE: to get compact video speed buttons, add this css in violentMonkey custom css in settings
/*
 [data-message="video, faster"] + .submenu-buttons + .submenu-commands {
 display: flex;
 justify-content: center;
}
[data-message="video, faster"] + .submenu-buttons + .submenu-commands .menu-item {
 padding: 0.5rem;
 margin: 0px;
 width: auto;
}
[data-message="video, faster"] + .submenu-buttons + .submenu-commands .menu-item .icon {
 display: none;
}
*/

GM_addStyle(`
  .userscript-video-top-bar {
    box-sizing: border-box;
      background-color: black;
      color: white;
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 22px;
      z-index: 100;
      display: flex;
      padding: 2px 16px;
      transition: opacity 0.2s ease-in-out;
  }
.userscript-video-top-bar:hover { opacity: 1 }
.userscript-video-top-bar button {
  margin: 0 3px;
  height: 100%;
  padding: 2px;
  font-size: 14px;
  line-height: 14px;
  width: min-content;
}
.userscript-simple-btn {
  background: #262626 !important;
  color: white;
  border: 1px solid #191919 !important;
  border-radius: 2px;
  font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
  font-weight: normal;
}
.userscript-simple-btn:hover {
  background: #303030 !important;
  border-color: #383838 !important;
}
.userscript-simple-btn:active {
  background: #383838 !important;
}
.userscript-simple-btn,
.userscript-simple-btn:hover,
.userscript-simple-btn:active {
  background-image: none !important;
  box-sizing: border-box !important;
  box-shadow: none !important;
  text-shadow: none !important;
}

.userscript-hoverinv {
  opacity: 0;
}
`);

let videoElem = null

const commands = {
  "1x": () => playbackRate(1),
  "1.5x": () => playbackRate(1.5),
  "2x": () => playbackRate(2),
  "2.5x": () => playbackRate(2.5),
  "2.75x": () => playbackRate(2.75),
  "3x": () => playbackRate(3),
  "3.5x": () => playbackRate(3.5),
  "4x": () => playbackRate(4)
}

function findVideoElement(debug = false) {
  if (!document.body) return;
  if (document.body.contains(videoElem)) return;

  let qs = "video";
  videoElem = document.querySelector(qs);

  if (videoElem !== null) {
    if (debug) console.log("found video elem", videoElem, qs);
  } else {
    // Look for video elements within iframes
    const iframes = document.querySelectorAll("iframe");
    iframes.forEach(iframe => {
      const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
      const iframeVideoElem = iframeDoc.querySelector("video");
      if (iframeVideoElem) {
        videoElem = iframeVideoElem;
        if (debug) console.log("found video elem in iframe", videoElem, iframe.src);
      }
    });
  }
}

function addTopBarToVideos() {
  document.querySelectorAll('video').forEach((video) => {
    const topBar = document.createElement('div');
    topBar.classList.add('userscript-video-top-bar', "userscript-hoverinv");
    for (const cmd of Object.keys(commands)) {
      const btn = document.createElement("button")
      btn.textContent = cmd
      btn.classList = "userscript-simple-btn"
      btn.onclick = (e) => playbackRate(Number(cmd.replace("x", "")), e, video)
      topBar.appendChild(btn)
    }
    topBar.appendChild(Object.assign(document.createElement("button"), {
      onclick: function(e) {
        e.preventDefault(); e.stopPropagation();
        topBar.classList.toggle("userscript-hoverinv");
        this.textContent = topBar.classList.contains("userscript-hoverinv") ? "📌" : "📍"
        this.title = topBar.classList.contains("userscript-hoverinv") ? "pin" : "unpin"
      },
      textContent: "📌",
      title: "pin",
      classList: "userscript-simple-btn",
      style: "postition: relative;right:0;"
    }))
    video.parentElement.insertBefore(topBar, video);
  });
}

function playbackRate(rate, e = null, video = null) {
  if (video == null) {
    findVideoElement()
    video = videoElem
  }
  if (e != null) {
    e?.preventDefault()
    e?.stopPropagation()
  }

  let wasplaying = !video.paused
  if (wasplaying) video.pause()
  video.playbackRate = rate
  if (wasplaying && video.paused) video.play()
}

function registerCommands() {
  Object.keys(commands).forEach(command => {
    try {
      GM_unregisterMenuCommand(command)
    } catch (e) { console.error(e) }
  })
  Object.entries(commands).forEach(command => {
    GM_registerMenuCommand(command[0], command[1])
  })
}

GM_registerMenuCommand("addvideobars", addTopBarToVideos)
addTopBarToVideos()
findVideoElement()

QingJ © 2025

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