您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
在B站(bilibili)网页播放器上增加一些额外的倍速按钮
当前为
// ==UserScript== // @name bilibili网页播放器增加倍速按钮 // @namespace voeoc // @version 0.0.4 // @description 在B站(bilibili)网页播放器上增加一些额外的倍速按钮 // @author voeoc // @include https://www.bilibili.com/video/* // @icon https://www.google.com/s2/favicons?domain=bilibili.com // @grant GM_getValue // @grant GM_setValue // @run-at document-idle // ==/UserScript== (function() { // 加入的按钮 const DEFAULT_SPEED_LIST_BUTTON = [0.5, 0.75, 1.0, 1.25, 1.5, 2.0, 3, 4, 5, 10, 100]; // 存储上一页面倍速的键 const GMKEY_LAST_SPEED_VALUE = "VOEOC_GMKEY_LAST_SPEED_VALUE"; // 存储倍速列表的键 const GMKEY_SPEED_LIST = "VOEOC_GMKEY_SPEED_LIST"; // 设置是否自动保存倍速 const GMKEY_AUTO_SAVE_SPEED = "VOEOC_GMKEY_AUTO_SAVE_SPEED"; function formatSpeedValue(speedValue) { if (Number.isInteger(speedValue)) { return `${speedValue.toString()}.0`; } else { return speedValue.toString(); } } function setSpeedButtonHighlight(btnSpeed) { let nowHighlightButton = document.querySelector('.bilibili-player-active'); if (nowHighlightButton != null) { nowHighlightButton.classList.remove("bilibili-player-active"); } btnSpeed.classList.add("bilibili-player-active"); } function setSpeed(speedValue) { document.querySelector('video').playbackRate = speedValue; // 修改显示的文字 let btnShowSpeed = document.querySelector('.bilibili-player-video-btn-speed-name'); if (speedValue != 1) { btnShowSpeed.innerHTML = `${formatSpeedValue(speedValue)}x`; } else { btnShowSpeed.innerHTML = "倍速"; } console.log(`voeoc: 成功设定倍速${speedValue}`) } function createThatButton(text) { let btn = document.createElement("li"); btn.classList.add("bilibili-player-video-btn-speed-menu-list"); btn.classList.add("voeoc-virtual-button"); btn.innerHTML = text; return btn; } function createSpeedButton(speedValue) { let btnSpeed = createThatButton(`${formatSpeedValue(speedValue)}x`); btnSpeed.setAttribute("data-value", `${speedValue}`); btnSpeed.onclick = function() { // 设定视频的倍速 setSpeed(speedValue); console.log(`voeoc: 用户设置倍速${speedValue}`) // 刷新高亮 setSpeedButtonHighlight(btnSpeed); // 储存当前倍速 GM_setValue(GMKEY_LAST_SPEED_VALUE, speedValue); // 隐藏弹出菜单 document.querySelector(".bilibili-player-video-btn.bilibili-player-video-btn-speed").classList.remove("bilibili-player-speed-show"); }; return btnSpeed; } function getIsAutoSaveSpeed() { return GM_getValue(GMKEY_AUTO_SAVE_SPEED, false); } function appendSettingsUI() { let isTheFirstRun = true; waitElementLoaded(".bilibili-player-video-danmaku-setting", (bilibiliPlayerSettingsPanelButton) => { bilibiliPlayerSettingsPanelButton.addEventListener("mouseover", function() { if (!isTheFirstRun) { return; } waitElementLoaded(".bilibili-player-video-danmaku-setting-right", (bilibiliPlayerSettingsPanel) => { let btnSpeedSettings = document.createElement("div"); btnSpeedSettings.className = "voeoc-button-speed-settings"; btnSpeedSettings.innerHTML = ` 修改倍速表... <div id="voeoc-speed-list-settings-panel" class="voeoc-speed-list-settings-panel"> <div style="margin: 5px;"> <input id="voeoc-text-speed-list" class="voeoc-text-speed-list" style=""></input> <label style="float:left; "> <input type="checkbox" id="voeoc-cbox-auto-save-speed" style="vertical-align:middle;background-color: red;"> 自动播放倍速 </label> <div id="voeoc-button-speed-settings-cancel"class="bui bui-button bui-button-transparent voeoc-button-speed-settings-apply">取消</div> <div id="voeoc-button-speed-settings-apply" class="bui bui-button bui-button-transparent voeoc-button-speed-settings-apply">确定</div> </div> </div> `; function showSettingPanel(isShow) { let settingsPanel = bilibiliPlayerSettingsPanel.querySelector("#voeoc-speed-list-settings-panel"); if (isShow) { let inputBoxSpeedList = bilibiliPlayerSettingsPanel.querySelector("#voeoc-text-speed-list"); let cboxAutoSaveSpeed = bilibiliPlayerSettingsPanel.querySelector("#voeoc-cbox-auto-save-speed"); // 载入倍速表,格式为数组 inputBoxSpeedList.value = GM_getValue(GMKEY_SPEED_LIST, DEFAULT_SPEED_LIST_BUTTON).toString(); // 载入是否自动保存的选项 cboxAutoSaveSpeed.checked = getIsAutoSaveSpeed(); settingsPanel.classList.add("voeoc-speed-list-settings-panel-show"); } else { settingsPanel.classList.remove("voeoc-speed-list-settings-panel-show"); } } waitElementLoaded("#voeoc-button-speed-settings-apply", (btnOk) => { btnOk.onclick = function() { let inputBoxSpeedList = bilibiliPlayerSettingsPanel.querySelector("#voeoc-text-speed-list"); // 储存输入的倍速表 GM_setValue(GMKEY_SPEED_LIST, inputBoxSpeedList.value.split(" ").join("").replace(",", ",").split(",")); // 修改成功 // 隐藏设置面板 showSettingPanel(false); // 刷新当前网页倍速表 reloadSpeedList(); }; }); waitElementLoaded("#voeoc-button-speed-settings-cancel", (btnCancel) => { btnCancel.onclick = function() { showSettingPanel(false); }; }); waitElementLoaded("#voeoc-cbox-auto-save-speed", (cboxAutoSaveSpeed) => { cboxAutoSaveSpeed.onclick = function() { GM_setValue(GMKEY_AUTO_SAVE_SPEED, cboxAutoSaveSpeed.checked); }; }); btnSpeedSettings.onmouseenter = function() { showSettingPanel(true); }; btnSpeedSettings.onmouseleave = function() { let inputBoxSpeedList = bilibiliPlayerSettingsPanel.querySelector("#voeoc-text-speed-list"); if (inputBoxSpeedList != document.activeElement) { // 如果倍速表输入框未获得焦点,取消显示设置面板 showSettingPanel(false); } }; bilibiliPlayerSettingsPanel.appendChild(btnSpeedSettings); }); isTheFirstRun = false; }); }); } function reloadSpeedList() { let btnMenu = document.querySelector(".bilibili-player-video-btn-speed-menu"); // 读取倍速表 let oldSpeedList = GM_getValue(GMKEY_SPEED_LIST, DEFAULT_SPEED_LIST_BUTTON); // 读取上一页面的倍速设置 let lastSpeedValue = GM_getValue(GMKEY_LAST_SPEED_VALUE, 1); // 清除冗余按钮 btnMenu.innerHTML = ""; // 添加按钮节点 for (let i = 0; i < oldSpeedList.length; ++i) { let btnSpeed = createSpeedButton(Number(oldSpeedList[i])); // 在最前面插入按钮 btnMenu.insertBefore(btnSpeed, btnMenu.childNodes[0]); // 根据上一页面刷新倍速 if (getIsAutoSaveSpeed() && Math.abs(oldSpeedList[i] - lastSpeedValue) < 0.001) { btnSpeed.click(); } } // 第一次加载页面,延时检测视频速度是否正确修改 if (getIsAutoSaveSpeed()) { (function() { const TIME_OUT = 10; // 10次放弃 let findTimeNum = 0; // 记录查找的次数 let timer = setInterval(() => { if (lastSpeedValue != document.querySelector('video').playbackRate) { // 清除定时器 clearInterval(timer); setSpeed(lastSpeedValue); } else { findTimeNum++; if (TIME_OUT < findTimeNum) { // 清除定时器,并且不执行回调 clearInterval(timer); } } }, 100); })(); } } function waitElementLoaded(selector, func) { const TIME_OUT = 100; // 找100次没有找到就放弃 let findTimeNum = 0; // 记录查找的次数 let timer = setInterval(() => { let element = document.querySelector(selector); console.log(`voeoc: 查找${selector}:${element}`) if (element != null) { // 清除定时器 clearInterval(timer); func(element); } else { findTimeNum++; if (TIME_OUT < findTimeNum) { // 清除定时器,并且不执行回调 clearInterval(timer); console.log(`voeoc: 查找${selector}失败`) } } }, 200); } // 等待视频组件加载完毕 waitElementLoaded('video', (bilibiliPlayer) => { // 注入自定义样式 (function() { let style = document.createElement("style"); let cssText = ` .voeoc-virtual-button {} .voeoc-button-speed-settings { margin-top: 9px; float: right; width: 80px; z-index: 999px; transform: translateZ(0); } .voeoc-speed-list-settings-panel { height: 90px; width: 240px; overflow: hidden; top: -90px; left: -150px; float: right; position: absolute; visibility: hidden; opacity: 0; background-color: rgb(59, 59, 59); margin: 0 -110px 0 0; border-radius: 2px; } .voeoc-speed-list-settings-panel.voeoc-speed-list-settings-panel-show { visibility: visible; opacity: 1; } .voeoc-button-speed-settings-apply { float: right; position: relative; top: 25px; margin-right: 2px; } .voeoc-text-speed-list { width: 225px; background-color: transparent; border-color: white; border-width: 0; border-bottom-width: 1px; border-style: solid; line-height: 22px; } `; style.appendChild(document.createTextNode(cssText)); document.getElementsByTagName("head")[0].appendChild(style); }()); let isFristLoad = true; function loadData() { // 等待视频速率控制组件加载完毕 waitElementLoaded(".bilibili-player-video-btn-speed-menu", (btnMenu) => { // 载入倍速表 reloadSpeedList(); // 载入设置界面 appendSettingsUI(); }); }; loadData(); bilibiliPlayer.addEventListener("loadedmetadata", function() { if (isFristLoad) { isFristLoad = false; return; } loadData(); }); }); })();