全能视频播放器速度控制(最大16倍速)

支持【B站】【爱奇艺】【腾讯视频】【优酷】...等网站

目前为 2025-05-17 提交的版本。查看 最新版本

// ==UserScript==
// @name         全能视频播放器速度控制(最大16倍速)
// @namespace    http://tampermonkey.net/
// @version      4.0.1
// @author       不会起名
// @description  支持【B站】【爱奇艺】【腾讯视频】【优酷】...等网站
// @license      MIT
// @icon         https://vitejs.dev/logo.svg
// @match        *://*.youtube.com/watch*
// @match        *://*.bilibili.com/video/*
// @match        *://v.qq.com/x/cover/*
// @match        *://www.youku.com/video?*
// @match        *://*.netflix.com/watch/*
// @match        *://*.dailymotion.com/video/*
// @match        *://*.twitch.tv/*/videos/*
// @match        *://*.vimeo.com/*
// @match        *://*.huya.com/*
// @match        *://*.douyu.com/*
// @match        *://*.tudou.com/listplay/*
// @match        *://*.tudou.com/albumplay/*
// @match        *://*.tudou.com/programs/view/*
// @match        *://*.tudou.com/v*
// @match        *://*.bilibili.com/anime/*
// @match        *://*.bilibili.com/bangumi/play/*
// @match        *://m.youku.com/v*
// @match        *://m.youku.com/a*
// @match        *://v.youku.com/v_*
// @match        *://v.youku.com/pad_show*
// @match        *://*.iqiyi.com/v_*
// @match        *://*.iqiyi.com/w_*
// @match        *://*.iqiyi.com/a_*
// @match        *://*.iqiyi.com/adv*
// @match        *://*.iq.com/play/*
// @match        *://v.yinyuetai.com/video/*
// @match        *://v.yinyuetai.com/playlist/*
// @match        *://*.pptv.com/show/*
// @match        *://www.yuque.com/r/goto*
// @match        *://*.xiaohongshu.com/explore*
// @match        *://tv.wandhi.com/go.html*
// @match        *://tv.wandhi.com/check.html
// @match        *://*.zhihu.com/question*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const o=document.createElement("style");o.textContent=e,document.head.append(o)})(" #speed-control.light[data-v-088b3c4e]{--bg-color: #e4ebf5;--text-color: #9baacf;--Shadow-color1: #c8d0e7;--Shadow-color2: #ffffff}#speed-control.dark[data-v-088b3c4e]{--bg-color: #696969;--text-color: #ffffff;--Shadow-color1: #595959;--Shadow-color2: #797979}#speed-control.fold[data-v-088b3c4e]{--width: 200px;--height: 147px}#speed-control.unfold[data-v-088b3c4e]{--width: 140px;--height: 22px}#speed-control[data-v-088b3c4e]{position:fixed;top:20px;left:20px;z-index:9999;border-radius:5px;padding:10px;width:var(--width);height:var(--height);font-size:12px;line-height:1.5;background-color:var(--bg-color);color:var(--text-color);border:1px solid rgb(221,221,221);transition:width .3s,height .3s,background-color .3s,color .3s;overflow:hidden;-webkit-user-select:none;user-select:none;box-sizing:content-box}#speed-control .header[data-v-088b3c4e]{display:flex;justify-content:space-between;align-items:center;cursor:move}#speed-control .headerBtn[data-v-088b3c4e]{display:flex;justify-content:space-between;align-items:center;gap:10px}#speed-control .headerBtn button[data-v-088b3c4e]{width:35px;line-height:22px}#speed-control button[data-v-088b3c4e]{border-radius:3px;background-color:none;border:none;line-height:22px;box-shadow:3px 3px 6px var(--Shadow-color1),-2px -2px 5px var(--Shadow-color2);color:var(--text-color);cursor:pointer}#speed-control button[data-v-088b3c4e] :focus{outline:none}#speed-control button[data-v-088b3c4e]:focus,#speed-control button[data-v-088b3c4e]:focus-visible{outline:none}#speed-control button[data-v-088b3c4e]:active,#speed-control .numInputSpeed[data-v-088b3c4e]{box-shadow:inset 2px 2px 5px var(--Shadow-color1),inset -2px -2px 5px var(--Shadow-color2)!important}#speed-control .speedBtnList[data-v-088b3c4e]{display:flex;flex-wrap:wrap;margin:15px 0;justify-content:space-between;row-gap:10px}.speedBtnList button[data-v-088b3c4e]{width:30%}#speed-control .slider[data-v-088b3c4e]{--slider-width: 100%;--slider-height: 6px;--slider-border-radius: 999px;--level-transition-duration: .1s;--level-color: var(--bg-color)}#speed-control .slider[data-v-088b3c4e]{display:flex;align-items:center;cursor:pointer}#speed-control .slider .level[data-v-088b3c4e]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:var(--slider-width);height:var(--slider-height);background-color:var(--text-color);overflow:hidden;border-radius:var(--slider-border-radius);-webkit-transition:height var(--level-transition-duration);-o-transition:height var(--level-transition-duration);transition:height var(--level-transition-duration);cursor:pointer}#speed-control .level[data-v-088b3c4e]::-webkit-slider-thumb{-webkit-appearance:none;width:0;height:0;-webkit-box-shadow:-200px 0 0 200px var(--level-color);box-shadow:-200px 0 0 200px var(--level-color)}#speed-control .slider:hover .level[data-v-088b3c4e]{height:calc(var(--slider-height) * 2)}#speed-control .numInputSpeed[data-v-088b3c4e]{position:relative;width:42px;height:22px;margin-left:10px;padding:3px 6px;text-align:center;border-radius:4px;border:none;color:var(--text-color);background-color:transparent}#speed-control .numInputSpeed[data-v-088b3c4e]::-webkit-inner-spin-button,#speed-control .numInputSpeed[data-v-088b3c4e]::-webkit-outer-spin-button{-webkit-appearance:none;display:none;margin:0}#speed-control .number-input[data-v-088b3c4e]{display:flex;align-items:center;gap:5px}#speed-control .controls[data-v-088b3c4e]{display:flex;flex-direction:column;gap:5px}#speed-control .controls button[data-v-088b3c4e]{border:none;cursor:pointer;padding:0 5px;font-size:10px;line-height:1.2}#speed-control .controls button[data-v-088b3c4e]:hover{color:#000} ");

(function (vue) {
  'use strict';

  var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  const _export_sfc = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
      target[key] = val;
    }
    return target;
  };
  const _hoisted_1 = { class: "headerBtn" };
  const _hoisted_2 = ["textContent"];
  const _hoisted_3 = ["textContent"];
  const _hoisted_4 = { class: "speedBtnList" };
  const _hoisted_5 = ["onClick", "textContent"];
  const _hoisted_6 = { class: "slider" };
  const _hoisted_7 = ["min", "max", "step"];
  const _hoisted_8 = { class: "number-input" };
  const _hoisted_9 = ["min", "max", "step"];
  const _hoisted_10 = { class: "controls" };
  const _sfc_main = {
    __name: "App",
    setup(__props) {
      const SPEED = {
        MIN: 0.1,
        MAX: 16,
        STEP: 0.05
      };
      const PRESET = [0.5, 0.65, 0.85, 1, 1.15, 1.25];
      const theme = vue.ref(_GM_getValue("theme", "light"));
      const isFold = vue.ref(_GM_getValue("isFold", "fold"));
      const position = vue.ref(_GM_getValue("savedPosition", { x: 20, y: 20 }));
      const speed = vue.ref(1);
      const numInputSpeed = vue.ref(null);
      const mediaElements = vue.ref([]);
      const updatePlaybackRate = () => {
        mediaElements.value = [...document.querySelectorAll("video, audio")];
        mediaElements.value.forEach((media) => {
          console.log("mediaElements.value");
          try {
            media.playbackRate = speed.value;
          } catch (e) {
            console.error("Error setting playback rate:", e);
          }
        });
      };
      const toggleTheme = () => {
        theme.value = theme.value === "light" ? "dark" : "light";
        _GM_setValue("theme", theme.value);
      };
      const toggleFold = () => {
        isFold.value = isFold.value === "fold" ? "unfold" : "fold";
        _GM_setValue("isFold", isFold.value);
      };
      const toggleSpeed = (speedVal) => {
        speed.value = speedVal;
        updatePlaybackRate();
      };
      const onMousedown = (e) => {
        const offsetX = e.clientX - position.value.x;
        const offsetY = e.clientY - position.value.y;
        const onMousemove = (e2) => {
          position.value.x = e2.clientX - offsetX;
          position.value.y = e2.clientY - offsetY;
        };
        const onMouseup = () => {
          document.removeEventListener("mousemove", onMousemove);
          document.removeEventListener("mouseup", onMouseup);
          _GM_setValue("savedPosition", { ...position.value });
        };
        document.addEventListener("mousemove", onMousemove);
        document.addEventListener("mouseup", onMouseup);
      };
      const increment = () => {
        speed.value = Math.min(SPEED.MAX, Math.round((speed.value + SPEED.STEP) * 100) / 100);
        updatePlaybackRate();
      };
      const decrement = () => {
        speed.value = Math.max(SPEED.MIN, Math.round((speed.value - SPEED.STEP) * 100) / 100);
        updatePlaybackRate();
      };
      const handleWheel = (event) => {
        requestAnimationFrame(() => {
          if (event.deltaY < 0) {
            increment();
          } else {
            decrement();
          }
        });
      };
      return (_ctx, _cache) => {
        return vue.openBlock(), vue.createElementBlock("div", {
          id: "speed-control",
          ref: "dragElement",
          class: vue.normalizeClass([vue.unref(theme), vue.unref(isFold)]),
          style: vue.normalizeStyle({ transform: `translate(${vue.unref(position).x}px, ${vue.unref(position).y}px)` })
        }, [
          vue.createElementVNode("div", {
            class: "header",
            onMousedown
          }, [
            _cache[8] || (_cache[8] = vue.createElementVNode("div", null, "播放控制", -1)),
            vue.createElementVNode("div", _hoisted_1, [
              vue.createElementVNode("button", {
                type: "button",
                onClick: _cache[0] || (_cache[0] = ($event) => toggleFold()),
                textContent: vue.toDisplayString(vue.unref(isFold) === "unfold" ? "▶" : "▼")
              }, null, 8, _hoisted_2),
              vue.createElementVNode("button", {
                type: "button",
                onClick: _cache[1] || (_cache[1] = ($event) => toggleTheme()),
                textContent: vue.toDisplayString(vue.unref(theme) === "dark" ? "🌞" : "🌙")
              }, null, 8, _hoisted_3)
            ])
          ], 32),
          vue.createElementVNode("div", _hoisted_4, [
            (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(PRESET, (item) => {
              return vue.createElementVNode("button", {
                type: "button",
                onClick: ($event) => toggleSpeed(item),
                key: item,
                textContent: vue.toDisplayString(item)
              }, null, 8, _hoisted_5);
            }), 64))
          ]),
          vue.createElementVNode("div", null, "当前速度:" + vue.toDisplayString(vue.unref(speed)) + "x", 1),
          vue.createElementVNode("div", _hoisted_6, [
            vue.withDirectives(vue.createElementVNode("input", {
              type: "range",
              min: SPEED.MIN,
              max: SPEED.MAX,
              step: SPEED.STEP,
              class: "level",
              onChange: _cache[2] || (_cache[2] = ($event) => {
                updatePlaybackRate();
              }),
              "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.isRef(speed) ? speed.value = $event : null)
            }, null, 40, _hoisted_7), [
              [
                vue.vModelText,
                vue.unref(speed),
                void 0,
                { number: true }
              ]
            ]),
            vue.createElementVNode("div", _hoisted_8, [
              vue.withDirectives(vue.createElementVNode("input", {
                type: "number",
                min: SPEED.MIN,
                max: SPEED.MAX,
                step: SPEED.STEP,
                ref_key: "numInputSpeed",
                ref: numInputSpeed,
                class: "numInputSpeed",
                onWheel: _cache[4] || (_cache[4] = vue.withModifiers(($event) => handleWheel($event), ["prevent"])),
                "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => vue.isRef(speed) ? speed.value = $event : null)
              }, null, 40, _hoisted_9), [
                [
                  vue.vModelText,
                  vue.unref(speed),
                  void 0,
                  { number: true }
                ]
              ]),
              vue.createElementVNode("div", _hoisted_10, [
                vue.createElementVNode("button", {
                  class: "increment",
                  onClick: _cache[6] || (_cache[6] = ($event) => increment())
                }, "▲"),
                vue.createElementVNode("button", {
                  class: "decrement",
                  onClick: _cache[7] || (_cache[7] = ($event) => decrement())
                }, "▼")
              ])
            ])
          ])
        ], 6);
      };
    }
  };
  const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-088b3c4e"]]);
  vue.createApp(App).mount(
    (() => {
      const app = document.createElement("div");
      document.body.append(app);
      return app;
    })()
  );

})(Vue);

QingJ © 2025

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