哔站倍速插件

哔站播放视频倍速,支持按钮、键盘X,C及滚轮控制

// ==UserScript==
// @name         哔站倍速插件
// @namespace    github/roo12589
// @version      1.5
// @author       roo12589
// @description  哔站播放视频倍速,支持按钮、键盘X,C及滚轮控制
// @icon         https://github.com/roo12589/my-monkey-scripts/blob/master/assets/bili-favicon.ico?raw=true
// @match        *://*.bilibili.com/video/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/umd/react.production.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/umd/react-dom.production.min.js
// @grant        GM_registerMenuCommand
// ==/UserScript==

(t=>{const e=document.createElement("style");e.dataset.source="vite-plugin-monkey",e.textContent=t,document.head.append(e)})(" #bili-speed-app button{outline:0;padding:2px;margin-left:5px;background-color:#f4f4f4;border:0;color:#222;cursor:pointer;border-radius:10%}#current-speed-btn{transition:all .2s ease-in-out;border:0!important;background-color:#ffafc9!important;color:#fff!important;width:40px}.video-speed-box{width:100%;height:28px;display:flex;justify-content:flex-end;align-items:flex-start}#current-speed-btn:hover{transform:scale(1.5);transform-origin:50% 100%;border-radius:6px}.plugin-notification{min-width:100px;height:50px;line-height:50px;border-radius:10px;background:rgba(31,14,14,.452);color:#e9e8e8e8;font-size:24px;position:absolute;left:10%;top:10%;text-align:center;display:none;justify-content:center;align-items:center}.plugin-notification.show{display:block} ");

(function (require$$0, require$$0$1) {
  'use strict';

  var jsxRuntime = { exports: {} };
  var reactJsxRuntime_production_min = {};
  /**
   * @license React
   * react-jsx-runtime.production.min.js
   *
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   */
  var f = require$$0, k = Symbol.for("react.element"), l = Symbol.for("react.fragment"), m$1 = Object.prototype.hasOwnProperty, n = f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner, p = { key: true, ref: true, __self: true, __source: true };
  function q(c, a, g) {
    var b, d = {}, e = null, h = null;
    void 0 !== g && (e = "" + g);
    void 0 !== a.key && (e = "" + a.key);
    void 0 !== a.ref && (h = a.ref);
    for (b in a)
      m$1.call(a, b) && !p.hasOwnProperty(b) && (d[b] = a[b]);
    if (c && c.defaultProps)
      for (b in a = c.defaultProps, a)
        void 0 === d[b] && (d[b] = a[b]);
    return { $$typeof: k, type: c, key: e, ref: h, props: d, _owner: n.current };
  }
  reactJsxRuntime_production_min.Fragment = l;
  reactJsxRuntime_production_min.jsx = q;
  reactJsxRuntime_production_min.jsxs = q;
  {
    jsxRuntime.exports = reactJsxRuntime_production_min;
  }
  var jsxRuntimeExports = jsxRuntime.exports;
  const jsx = jsxRuntimeExports.jsx;
  const jsxs = jsxRuntimeExports.jsxs;
  var client = {};
  var m = require$$0$1;
  {
    client.createRoot = m.createRoot;
    client.hydrateRoot = m.hydrateRoot;
  }
  var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  function App() {
    var _a, _b, _c;
    initStorage();
    const bindHistoryEvent = function(type) {
      const historyEvent = history[type];
      return function() {
        const newEvent = historyEvent.apply(this, arguments);
        const e = new Event(type);
        e.arguments = arguments;
        window.dispatchEvent(e);
        return newEvent;
      };
    };
    history.pushState = bindHistoryEvent("pushState");
    history.replaceState = bindHistoryEvent("replaceState");
    window.addEventListener("pushState", () => {
      resetVideoSpeed();
    });
    const videoSpeedList = ((_a = localStorage.getItem("bsw-speed-list")) == null ? void 0 : _a.split(",").filter((i) => i !== "").map(parseFloat)) || [1, 2, 3, 1.2, 1.3, 1.5, 1.8, 2.3, 2.5, 2.8];
    const length = videoSpeedList.length;
    let splitIndex;
    if (length % 2 === 0)
      splitIndex = Math.floor(length / 2) - 1;
    else
      splitIndex = Math.floor(length / 2);
    const videoSpeedListTop = videoSpeedList.slice(0, splitIndex);
    const videoSpeedListBottom = videoSpeedList.slice(splitIndex);
    _GM_registerMenuCommand("倍速列表", function() {
      var value = prompt("请输入倍速:(英文逗号隔开)", videoSpeedList.toString());
      if (value !== null) {
        localStorage.setItem("bsw-speed-list", value);
        createNoti(`已添加,刷新后生效`);
      }
    });
    const nameWhiteList = ((_b = localStorage.getItem("bsw-name-white-list")) == null ? void 0 : _b.split(",")) || [];
    _GM_registerMenuCommand("白名单列表", function() {
      var value = prompt("播放白名单up主的视频时,不自动倍速:(英文逗号隔开)", nameWhiteList.toString());
      if (value !== null) {
        localStorage.setItem("bsw-name-white-list", value);
        createNoti(`已添加,目前共${value.split(",").length}个,刷新后生效`);
      }
    });
    var videoSpeedBack;
    var isOpen = true;
    const username = (_c = document.querySelector(".up-info_right .username")) == null ? void 0 : _c.innerText;
    const usernameCombined = new Array().concat(document.querySelectorAll(".up-card .name-text")).map((el) => el.innerText).toString();
    for (const name of nameWhiteList) {
      if ((username == null ? void 0 : username.match(name)) || (usernameCombined == null ? void 0 : usernameCombined.match(name))) {
        isOpen = false;
        break;
      }
    }
    document.onkeydown = function(e) {
      if (e.target.type === "text" || e.target.type === "textarea")
        return;
      let speed = getSpeed() || 1;
      let ev = e || window.event;
      if (ev.key === "z") {
        if (isOpen) {
          isOpen = false;
          videoSpeedBack = getSpeed();
          changeVideoSpeed(1, false);
        } else {
          isOpen = true;
          changeVideoSpeed(videoSpeedBack);
          videoSpeedBack = void 0;
        }
      }
      if (ev.key === "c") {
        changeVideoSpeed((speed * 10 + 1) / 10);
        return false;
      } else if (ev.key === "x") {
        changeVideoSpeed((speed * 10 - 1) / 10);
        return false;
      }
    };
    window.onload = function() {
      resetVideoSpeed();
    };
    function changeVideoSpeed(x, save = true) {
      const min = 0.1, max = 16;
      if (x > max || x < min)
        return;
      const playerSpeedButton = document.querySelector(".bilibili-player-video-btn-speed-name");
      let speed;
      if (typeof x == "number") {
        speed = x;
      } else if (typeof x == "string") {
        speed = parseFloat(x);
      } else {
        speed = parseFloat(x.target.innerHTML.replace("x", ""));
      }
      if (save) {
        localStorage.setItem("bsw-current-speed", speed);
      }
      document.querySelector("#current-speed-btn").innerHTML = save ? "x" + speed : "关闭";
      let videoObj = document.querySelector("video");
      if (!videoObj)
        videoObj = document.querySelector("bwp-video");
      if (videoObj) {
        videoObj.playbackRate = speed;
        console.log(videoObj.playbackRate);
        playerSpeedButton && (playerSpeedButton.innerText = save ? speed + "x" : "关闭");
      }
      createNoti(save ? getSpeed().toFixed(1) : "关闭");
    }
    function resetVideoSpeed() {
      let count = 0;
      const timer2 = setInterval(() => {
        let videoObj = document.querySelector("video") || document.querySelector("bwp-video");
        console.log("等待加载播放器...");
        if (videoObj) {
          if (isOpen) {
            videoObj.playbackRate = getSpeed();
          } else {
            videoSpeedBack = getSpeed();
            changeVideoSpeed(1, false);
          }
          console.log("已加载", videoObj.playbackRate);
          coverTitle();
          clearInterval(timer2);
        }
        count++;
        if (count >= 10) {
          clearInterval(timer2);
          createNoti("获取播放器组件超时");
        }
      }, 1e3);
    }
    let timer;
    function createNoti(message) {
      if (timer)
        clearTimeout(timer);
      if (!window.pluginNotification) {
        let div = document.createElement("div");
        div.className = "plugin-notification";
        window.pluginNotification = div;
        div.appendChild(document.createTextNode(message));
        const ele = document.querySelector(".bpx-player-video-wrap") || document.querySelector("#playerWrap") || document.body;
        ele && ele.appendChild(div);
      } else {
        window.pluginNotification.className = "plugin-notification show";
        window.pluginNotification.innerText = message;
      }
      timer = setTimeout(function() {
        window.pluginNotification.className = "plugin-notification";
      }, 1300);
    }
    function coverTitle() {
      let OnP = document.querySelector(".list-box>.on>a");
      let Title = document.querySelector(".video-info .video-title .tit");
      if (OnP && OnP.getAttribute("title")) {
        let OnPName = OnP.getAttribute("title");
        let docTitle = document.querySelector("head>title");
        docTitle.innerHTML = OnPName;
        Title.innerHTML = OnPName;
      }
      let progresses = document.querySelectorAll(".bui-bar-wrap>.bui-bar-normal");
      progresses.forEach((ele) => ele.style.background = "#FFAFC9");
    }
    function getSpeed() {
      return parseFloat(parseFloat(localStorage.getItem("bsw-current-speed") || "1").toFixed(1));
    }
    function initStorage() {
      if (!localStorage.getItem("bsw-name-white-list")) {
        localStorage.setItem("bsw-name-white-list", ["戒社", "罗翔"].toString());
      }
    }
    const switchStatus = () => {
      if (isOpen) {
        isOpen = false;
        videoSpeedBack = getSpeed();
        changeVideoSpeed(1, false);
      } else {
        isOpen = true;
        changeVideoSpeed(videoSpeedBack);
        videoSpeedBack = void 0;
      }
    };
    const changeSpeedByMouse = (e) => {
      let speed = getSpeed();
      const playerSpeedButton = document.querySelector(".bilibili-player-video-btn-speed-name");
      e.preventDefault();
      if (e.deltaY) {
        if (e.deltaY > 0) {
          playerSpeedButton && (playerSpeedButton.innerText = speed + "x");
          changeVideoSpeed((speed * 10 - 1) / 10);
        } else {
          playerSpeedButton && (playerSpeedButton.innerText = speed + "x");
          changeVideoSpeed((speed * 10 + 1) / 10);
        }
      }
    };
    let currentSpeedBtn = /* @__PURE__ */ jsx(
      "button",
      {
        id: "current-speed-btn",
        onClick: switchStatus,
        ref: (el) => {
          if (el) {
            el.addEventListener(
              "wheel",
              (e) => {
                changeSpeedByMouse(e);
              },
              { passive: false }
            );
          }
        },
        children: "x" + getSpeed()
      }
    );
    let videoTop = /* @__PURE__ */ jsxs("div", { className: "video-speed-box", id: "video-speed-box-top", children: [
      /* @__PURE__ */ jsxs("div", { children: [
        " ",
        currentSpeedBtn,
        " "
      ] }),
      videoSpeedListTop.map((speed) => /* @__PURE__ */ jsx("button", { id: "btn-" + speed, style: { width: "40px" }, onClick: changeVideoSpeed, children: "x" + speed }, "btn-" + speed))
    ] });
    let videoBottom = /* @__PURE__ */ jsx("div", { className: "video-speed-box", id: "video-speed-box-bottom", children: videoSpeedListBottom.map((speed) => /* @__PURE__ */ jsx("button", { id: "btn-" + speed, style: { width: "40px" }, onClick: changeVideoSpeed, children: "x" + speed }, "btn-" + speed)) });
    const app = /* @__PURE__ */ jsxs(
      "div",
      {
        id: "bili-speed-app",
        style: {
          position: "relative",
          top: "-13.5px",
          right: 0,
          width: "1000px"
        },
        children: [
          videoTop,
          videoBottom
        ]
      }
    );
    return app;
  }
  client.createRoot(
    (() => {
      var _a;
      const app = document.createElement("div");
      const viewReportDiv = ((_a = document == null ? void 0 : document.querySelector("#viewbox_report")) == null ? void 0 : _a.querySelector(".video-data:last-child")) || document.querySelector(".s_form_wrapper");
      viewReportDiv && viewReportDiv.appendChild(app);
      return app;
    })()
  ).render(
    /* @__PURE__ */ jsx(require$$0.StrictMode, { children: /* @__PURE__ */ jsx(App, {}) })
  );

})(React, ReactDOM);

QingJ © 2025

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