您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
这一款专为B站用户打造的实用小工具,包含了B站视频的倍速播放(支持快捷键和控制面板设置),以及视频时间查询器(够便捷地计算视频的总时长,并根据不同的倍速计算实际的观看时间)。这款工具除了提供精确的时间统计,还具备窗口拖动、动态样式调整等功能,非常适合在B站学习课程的用户使用;2.x版本将“倍速功能”单独拆分到独立UI和单独热键监听中,并且原来的“时间计算”功能保持不变。
// ==UserScript== // @name 小叶的b站学习助手(视频时间查询器+视频倍速播放) // @namespace http://tampermonkey.net/ // @version 2.1.2 // @description 这一款专为B站用户打造的实用小工具,包含了B站视频的倍速播放(支持快捷键和控制面板设置),以及视频时间查询器(够便捷地计算视频的总时长,并根据不同的倍速计算实际的观看时间)。这款工具除了提供精确的时间统计,还具备窗口拖动、动态样式调整等功能,非常适合在B站学习课程的用户使用;2.x版本将“倍速功能”单独拆分到独立UI和单独热键监听中,并且原来的“时间计算”功能保持不变。 // @author 小叶 // @license AGPL License // @match *://*.bilibili.com/video/* // @icon https://www.bilibili.com/favicon.ico // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; // ===============【 一、原有的“视频时长计算”逻辑 】================ // 全局配置对象 const CONFIG = { // UI 配置 UI: { TRIGGER_ID: 'popup-trigger-container', CONTAINER_ID: 'time-calculator-container', RESULT_DIV_ID: 'resultDiv', DEFAULT_OPACITY: 0.8, Z_INDEX: 999999, ICON_URL: 'https://www.bilibili.com/favicon.ico' }, // 倍速配置 SPEED_UI: { SHOW_SPEED_UI: true // 设置是否显示倍速UI,默认为true }, // 样式配置 STYLE: { COLORS: { // 主色调(B站蓝) PRIMARY: '#00A1D6', // 次要色调 SECONDARY: '#40E0D0', // 警告色 WARNING: '#FF6347', // 悬停色 HOVER: '#008BB5', TEXT: { // 主要文本色 PRIMARY: '#333', // 次要文本色 SECONDARY: '#888' } }, BORDER_RADIUS: { SMALL: '4px', MEDIUM: '8px', LARGE: '16px' }, TRANSITIONS: { DEFAULT: 'all 0.3s ease' } }, // 功能配置 FEATURES: { RESULT_DISPLAY_TIME: 15000, // 结果显示时间(毫秒) // 最小集数 MIN_EPISODE: 1, // 最小倍速 MIN_SPEED: 0.5, // 倍速调整步长(不用于本脚本功能了) SPEED_STEP: 0.1, // 默认倍速(不用于本脚本功能了) DEFAULT_SPEED: 1, TIME_FORMATS: ["时分秒", "仅小时", "仅分钟", "仅秒"] }, // 布局配置 LAYOUT: { SNAP_PADDING: 20, CONTAINER_WIDTH: '280px', TRIGGER_WIDTH: { DEFAULT: '40px', EXPANDED: '80px' } }, // 文本配置 TEXT: { TRIGGER_TEXT: "小叶计时器", CLOSE_TEXT: "关闭计时器", TITLE: "小叶的B站时间查询器", FOOTER: "小叶计时器", MESSAGES: { INVALID_INPUT: "请输入有效的数值。", MIN_EPISODE: "最小为第1集", INVALID_RANGE: "输入的集数范围不正确。", NO_DURATION: "无法获取视频时长,请确保已加载视频列表。", MAX_EPISODE: "最大为第{count}集" } }, // 元素类名配置 CLASSES: { DURATION: 'duration', STATS: 'stats' } }; // 读取存储的透明度或使用默认值 let containerOpacity = GM_getValue('containerOpacity', CONFIG.UI.DEFAULT_OPACITY); let isPopupVisible = false; // 计时器ID let resultTimeoutId = null; // 创建触发器 const createPopupTrigger = () => { // 检查页面上是否存在指定的类名 if (!document.querySelector(`.${CONFIG.CLASSES.STATS}`)) { console.log('没有找到视频元素,触发器不会显示。'); return; // 如果没有找到,直接返回不创建触发器 } // 删除现有的触发器(如果存在) const existingTrigger = document.getElementById(CONFIG.UI.TRIGGER_ID); if (existingTrigger) { existingTrigger.remove(); } const body = document.body; const triggerContainer = document.createElement("div"); triggerContainer.id = CONFIG.UI.TRIGGER_ID; // 修改了容器的样式 triggerContainer.style.cssText = ` position: fixed; right: 0; top: 12%; transform: translateY(-50%); z-index: ${CONFIG.UI.Z_INDEX}; text-align: center; border: 1px solid ${CONFIG.STYLE.COLORS.PRIMARY}; border-radius: ${CONFIG.STYLE.BORDER_RADIUS.MEDIUM}; background-color: rgba(255, 255, 255, ${containerOpacity}); padding: 8px; width: ${CONFIG.LAYOUT.TRIGGER_WIDTH.DEFAULT}; transition: ${CONFIG.STYLE.TRANSITIONS.DEFAULT}; cursor: pointer; margin-left: 5px; `; // 创建并设置图标 const icon = document.createElement("img"); icon.src = CONFIG.UI.ICON_URL; icon.alt = "B站图标"; icon.style.cssText = ` width: 24px; height: 24px; display: block; margin: 0 auto; transition: ${CONFIG.STYLE.TRANSITIONS.DEFAULT}; `; // 创建文本容器 const textContainer = document.createElement("div"); textContainer.style.cssText = ` font-size: 12px; color: ${CONFIG.STYLE.COLORS.PRIMARY}; margin-top: 4px; white-space: nowrap; overflow: hidden; display: none; `; textContainer.innerText = CONFIG.TEXT.TRIGGER_TEXT; // 添加hover效果 triggerContainer.onmouseenter = () => { triggerContainer.style.width = CONFIG.LAYOUT.TRIGGER_WIDTH.EXPANDED; textContainer.style.display = 'block'; }; triggerContainer.onmouseleave = () => { if (!isPopupVisible) { triggerContainer.style.width = CONFIG.LAYOUT.TRIGGER_WIDTH.DEFAULT; textContainer.style.display = 'none'; } }; // 添加点击事件 triggerContainer.onclick = togglePopup; // 组装触发器 triggerContainer.appendChild(icon); triggerContainer.appendChild(textContainer); body.appendChild(triggerContainer); return triggerContainer; }; //切换弹出框 const togglePopup = () => { isPopupVisible = !isPopupVisible; const triggerContainer = document.getElementById(CONFIG.UI.TRIGGER_ID); const textContainer = triggerContainer.querySelector('div'); // 获取文本容器 if (isPopupVisible) { createTimeCalcUI(); triggerContainer.style.width = '80px'; textContainer.style.display = 'block'; textContainer.style.color = '#FF0000'; textContainer.innerText = '关闭计时器'; } else { closeTimeCalcUI(); triggerContainer.style.width = '40px'; textContainer.style.color = '#00A1D6'; textContainer.innerText = '小叶计时器'; // 恢复hover效果 triggerContainer.onmouseenter = () => { triggerContainer.style.width = '80px'; textContainer.style.display = 'block'; }; triggerContainer.onmouseleave = () => { triggerContainer.style.width = '40px'; textContainer.style.display = 'none'; }; } }; //创建计时器UI const createTimeCalcUI = () => { const existingDiv = document.getElementById(CONFIG.UI.CONTAINER_ID); if (existingDiv) { existingDiv.remove(); } const body = document.body; const container = document.createElement("div"); container.id = CONFIG.UI.CONTAINER_ID; container.style.cssText = ` padding: 20px; background-color: rgba(255, 255, 255, ${containerOpacity}); position: fixed; right: 20px; top: 20%; width: 280px; max-width: 90%; border-radius: 16px; box-shadow: 0 8px 16px rgba(0,0,0,0.2); border: 1px solid #40E0D0; z-index: 999; text-align: center; font-size: 14px; color: #333; `; makeElementDraggable(container); const closeButton = document.createElement("button"); closeButton.innerText = "关闭"; closeButton.style.cssText = ` position: absolute; top: 5px; right: 5px; border: none; background-color: #FF6347; color: #FFF; padding: 5px 10px; cursor: pointer; border-radius: 4px; `; closeButton.onclick = togglePopup; container.appendChild(closeButton); const title = document.createElement("h4"); title.innerText = CONFIG.TEXT.TITLE; title.style.cssText = ` margin-bottom: 20px; color: #00A1D6; font-weight: bold; text-align: center; `; container.appendChild(title); const inputDiv = document.createElement("div"); inputDiv.style.cssText = "margin-bottom: 15px; display: flex; justify-content: center; align-items: center;"; const label1 = document.createElement("label"); label1.innerText = "从第"; label1.style.cssText = "margin-right: 5px;"; inputDiv.appendChild(label1); const input1 = document.createElement('input'); input1.type = "number"; input1.style.cssText = ` border: 1px solid deepskyblue; width: 50px; text-align: center; margin-right: 5px; padding: 5px; border-radius: 4px; `; input1.min = 1; inputDiv.appendChild(input1); const label2 = document.createElement("label"); label2.innerText = "集 到"; label2.style.cssText = "margin-right: 5px;"; inputDiv.appendChild(label2); const input2 = document.createElement('input'); input2.type = "number"; input2.style.cssText = ` border: 1px solid deepskyblue; width: 50px; text-align: center; padding: 5px; border-radius: 4px; `; input2.min = 1; inputDiv.appendChild(input2); container.appendChild(inputDiv); const formatDiv = document.createElement("div"); formatDiv.style.cssText = "margin-bottom: 20px; display: flex; justify-content: center; align-items: center;"; const formatLabel = document.createElement("label"); formatLabel.innerText = "显示格式:"; formatLabel.style.cssText = "margin-right: 5px;"; formatDiv.appendChild(formatLabel); const formatSelect = document.createElement('select'); formatSelect.style.cssText = ` padding: 5px; border-radius: 4px; border: 1px solid deepskyblue; `; const options = CONFIG.FEATURES.TIME_FORMATS; // ["时分秒", "仅小时", "仅分钟", "仅秒"] options.forEach(optionText => { const option = document.createElement('option'); option.value = optionText; option.innerText = optionText; formatSelect.appendChild(option); }); formatDiv.appendChild(formatSelect); container.appendChild(formatDiv); const transparencyDiv = document.createElement("div"); transparencyDiv.style.cssText = "margin-bottom: 20px; text-align: center;"; const transparencyLabel = document.createElement("label"); transparencyLabel.innerText = "调整透明度:"; transparencyDiv.appendChild(transparencyLabel); const transparencySlider = document.createElement('input'); transparencySlider.type = "range"; transparencySlider.min = 0.1; transparencySlider.max = 1; transparencySlider.step = 0.1; transparencySlider.value = containerOpacity; transparencySlider.style.cssText = "margin-left: 10px;"; transparencySlider.oninput = (e) => { containerOpacity = e.target.value; container.style.backgroundColor = `rgba(255, 255, 255, ${containerOpacity})`; const triggerContainer = document.getElementById(CONFIG.UI.TRIGGER_ID); if (triggerContainer) { triggerContainer.style.backgroundColor = `rgba(255, 255, 255, ${containerOpacity})`; } GM_setValue('containerOpacity', containerOpacity); }; transparencyDiv.appendChild(transparencySlider); container.appendChild(transparencyDiv); const btn = document.createElement('button'); btn.innerText = "计算时间"; btn.style.cssText = ` width: 100%; padding: 12px; border: none; background-color: #00A1D6; color: #FFFFFF; cursor: pointer; border-radius: 8px; font-size: 16px; margin-bottom: 20px; `; btn.onmouseover = () => { btn.style.backgroundColor = "#008BB5"; }; btn.onmouseout = () => { btn.style.backgroundColor = "#00A1D6"; }; btn.onclick = () => { calculateTime(formatSelect.value, input1.value, input2.value); }; container.appendChild(btn); const resultDiv = document.createElement("div"); resultDiv.id = CONFIG.UI.RESULT_DIV_ID; resultDiv.style.cssText = ` margin-top: 15px; color: #333; font-weight: bold; text-align: center; `; container.appendChild(resultDiv); const footer = document.createElement("div"); footer.innerText = CONFIG.TEXT.FOOTER; footer.style.cssText = ` margin-top: 20px; color: #888; font-size: 12px; text-align: center; `; container.appendChild(footer); body.appendChild(container); }; //关闭UI const closeTimeCalcUI = () => { const existingDiv = document.getElementById(CONFIG.UI.CONTAINER_ID); if (existingDiv) { existingDiv.remove(); } }; // 计算时间函数 (已经移除倍速相关逻辑) const calculateTime = (format, startStr, endStr) => { // 获取所有duration元素 const allDurations = document.getElementsByClassName(CONFIG.CLASSES.DURATION); // 只筛选父元素className包含stats的元素 const durations = Array.from(allDurations).filter(el => el.parentElement.className.includes(CONFIG.CLASSES.STATS) ); const input1Value = parseInt(startStr, 10); const input2Value = parseInt(endStr, 10); // 输入验证 if (isNaN(input1Value) || isNaN(input2Value)) { updateResult(CONFIG.TEXT.MESSAGES.INVALID_INPUT); return; } // 验证最小集数 if (input1Value < CONFIG.FEATURES.MIN_EPISODE) { updateResult(CONFIG.TEXT.MESSAGES.MIN_EPISODE); return; } // 验证集数范围 if (input2Value < input1Value) { updateResult(CONFIG.TEXT.MESSAGES.INVALID_RANGE); return; } // 验证是否获取到视频时长 if (durations.length === 0) { updateResult(CONFIG.TEXT.MESSAGES.NO_DURATION); return; } // 验证最大集数 if (input2Value > durations.length) { const message = CONFIG.TEXT.MESSAGES.MAX_EPISODE.replace('{count}', durations.length); updateResult(message); return; } // 计算总时长 let totalSeconds = 0; for (let i = input1Value - 1; i < input2Value; i++) { const duration = durations[i].innerText; const timeParts = duration.split(':').map(Number); let seconds = timeParts.pop(); let minutes = timeParts.pop() || 0; let hours = timeParts.pop() || 0; totalSeconds += hours * 3600 + minutes * 60 + seconds; } // 转换时间格式 const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = Math.floor(totalSeconds % 60); // 根据选择的格式生成结果文本 let resultText; switch (format) { case "时分秒": resultText = `总时长:${hours}时${minutes}分${seconds}秒`; break; case "仅小时": resultText = `总时长:${(totalSeconds / 3600).toFixed(2)} 小时`; break; case "仅分钟": resultText = `总时长:${(totalSeconds / 60).toFixed(2)} 分钟`; break; case "仅秒": resultText = `总时长:${Math.round(totalSeconds)} 秒`; break; } // 显示结果 updateResult(resultText); }; // 更新结果显示 const updateResult = (text) => { const resultDiv = document.getElementById(CONFIG.UI.RESULT_DIV_ID); if (!resultDiv) return; resultDiv.innerText = text; // 如果已经存在计时器,先清除它 if (resultTimeoutId) { clearTimeout(resultTimeoutId); } // 设置新的计时器并保存ID resultTimeoutId = setTimeout(() => { if (resultDiv) { // 检查元素是否还存在 resultDiv.innerText = ''; } resultTimeoutId = null; }, CONFIG.FEATURES.RESULT_DISPLAY_TIME); }; // 拖动逻辑 const makeElementDraggable = (element) => { let offsetX = 0, offsetY = 0, isDragging = false; element.addEventListener('mousedown', (e) => { if (e.target.tagName.toLowerCase() === 'input' || e.target.tagName.toLowerCase() === 'textarea') { return; } isDragging = true; offsetX = e.clientX - element.getBoundingClientRect().left; offsetY = e.clientY - element.getBoundingClientRect().top; element.style.transition = "none"; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; element.style.left = `${e.clientX - offsetX}px`; element.style.top = `${e.clientY - offsetY}px`; }); document.addEventListener('mouseup', () => { isDragging = false; element.style.transition = "all 0.3s ease"; }); }; // 初始化时间查询触发器 createPopupTrigger(); // ===============【 二、全新“倍速调节”UI与按键监听 】================ /** * 存储本脚本内部的倍速值 * 如需记忆上次倍速,可以使用 GM_getValue/GM_setValue 来持久化 */ let currentSpeed = 1.0; let originalSpeed = 1.0; // 记录原始倍速 /** * 将页面上所有 <video> 标签的播放速率设置为指定值 * @param {number} speed 要设定的倍速 */ function setAllVideoPlaybackRate(speed) { if (!speed || isNaN(speed) || speed <= 0) return; currentSpeed = speed; const videos = document.querySelectorAll("video"); videos.forEach(video => { try { video.playbackRate = speed; } catch (e) { console.warn("[小叶-倍速] 设置视频倍速失败:", e); } }); console.log("[小叶-倍速] 已将所有视频调节为", speed, "倍速"); // 显示倍速 displaySpeedOnVideo(speed); // 更新UI中的当前倍速显示 updateSpeedDisplay(speed); } function displaySpeedOnVideo(speed) { const videoElement = document.querySelector('video'); if (videoElement) { // Check if a speed display already exists, if so, remove it let existingSpeedDisplay = videoElement.parentElement.querySelector('.speed-display'); if (existingSpeedDisplay) { existingSpeedDisplay.remove(); } // Create new speed display const speedDisplay = document.createElement('div'); speedDisplay.innerText = `倍速:${speed}`; speedDisplay.style.position = 'absolute'; speedDisplay.style.top = '10px'; speedDisplay.style.left = '10px'; speedDisplay.style.padding = '5px'; speedDisplay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; speedDisplay.style.color = 'white'; speedDisplay.style.fontSize = '16px'; speedDisplay.style.fontWeight = 'bold'; speedDisplay.style.borderRadius = '5px'; speedDisplay.className = 'speed-display'; // Add class for easy removal videoElement.parentElement.appendChild(speedDisplay); // Set timeout to remove the speed display after 3 seconds setTimeout(() => { speedDisplay.remove(); }, 3000); } } // 更新倍速UI中的当前倍速 function updateSpeedDisplay(speed) { const currentSpeedLabel = document.getElementById("current-speed-label"); if (currentSpeedLabel) { // 更新倍速显示 currentSpeedLabel.innerText = `当前倍速:${speed}x`; } } // 新建一个倍速按钮Trigger const SPEED_TRIGGER_ID = "speed-trigger-container"; let isSpeedPopupVisible = false; function createSpeedTrigger() { // 如果倍速UI被禁用,则不创建倍速触发器 if (!CONFIG.SPEED_UI.SHOW_SPEED_UI) return; const existingSpeedTrigger = document.getElementById(SPEED_TRIGGER_ID); if (existingSpeedTrigger) existingSpeedTrigger.remove(); const body = document.body; const trigger = document.createElement("div"); trigger.id = SPEED_TRIGGER_ID; trigger.style.cssText = ` position: fixed; right: 0; top: 25%; transform: translateY(-50%); z-index: 999999; text-align: center; border: 1px solid #FF8C00; border-radius: 8px; background-color: rgba(255, 255, 255, ${containerOpacity}); padding: 8px; width: 40px; transition: all 0.3s ease; cursor: pointer; `; const icon = document.createElement("div"); icon.innerText = "倍速"; icon.style.cssText = ` font-size: 14px; color: #FF8C00; text-align: center; user-select: none; `; trigger.appendChild(icon); trigger.addEventListener("click", toggleSpeedPopup); // hover时宽度变大 trigger.onmouseenter = () => { trigger.style.width = "80px"; icon.style.display = "block"; }; trigger.onmouseleave = () => { if (!isSpeedPopupVisible) { trigger.style.width = "40px"; } }; body.appendChild(trigger); } function toggleSpeedPopup() { isSpeedPopupVisible = !isSpeedPopupVisible; if (isSpeedPopupVisible) { createSpeedUI(); const trig = document.getElementById(SPEED_TRIGGER_ID); if (trig) { trig.style.width = "80px"; } } else { closeSpeedUI(); const trig = document.getElementById(SPEED_TRIGGER_ID); if (trig) { trig.style.width = "40px"; } } } // 创建倍速UI // 创建倍速UI function createSpeedUI() { const body = document.body; if (document.getElementById("speed-ui-container")) { return; // 已存在则不重复创建 } const container = document.createElement("div"); container.id = "speed-ui-container"; container.style.cssText = ` padding: 10px; background-color: rgba(255, 255, 255, ${containerOpacity}); position: fixed; right: 80px; top: 25%; width: 200px; max-width: 60%; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.2); border: 1px solid #FF8C00; z-index: 999999; text-align: center; font-size: 14px; color: #444; `; makeElementDraggable(container); const closeBtn = document.createElement("button"); closeBtn.innerText = "关闭"; closeBtn.style.cssText = ` position: absolute; top: 5px; right: 5px; border: none; background-color: #f90; color: #FFF; padding: 2px 6px; cursor: pointer; border-radius: 4px; `; closeBtn.onclick = toggleSpeedPopup; container.appendChild(closeBtn); const title = document.createElement("h4"); title.innerText = "视频倍速设置"; title.style.cssText = ` margin-bottom: 8px; color: #FF8C00; font-weight: bold; `; container.appendChild(title); // 倍速输入框 const label = document.createElement("label"); label.innerText = "请输入倍速:"; label.style.cssText = "margin-right: 5px;"; container.appendChild(label); const speedInput = document.createElement("input"); speedInput.type = "number"; speedInput.value = currentSpeed; speedInput.min = "0.1"; speedInput.step = "0.1"; speedInput.style.cssText = ` width: 60px; text-align: center; border-radius: 4px; border: 1px solid #ccc; margin-bottom: 10px; `; container.appendChild(speedInput); // Add a label to show the current speed dynamically const currentSpeedLabel = document.createElement("div"); currentSpeedLabel.id = "current-speed-label"; currentSpeedLabel.style.cssText = ` margin-top: 8px; color: #555; font-size: 14px; `; currentSpeedLabel.innerText = `当前倍速:${currentSpeed}x`; container.appendChild(currentSpeedLabel); const setBtn = document.createElement("button"); setBtn.innerText = "应用"; setBtn.style.cssText = ` margin-left: 8px; background-color: #00A1D6; color: #FFF; border: none; padding: 4px 8px; cursor: pointer; border-radius: 4px; `; setBtn.onclick = () => { const val = parseFloat(speedInput.value) || 1; if (val <= 0) { alert("非法倍速值!"); return; } setAllVideoPlaybackRate(val); // Update the current speed label currentSpeedLabel.innerText = `当前倍速:${val}x`; }; container.appendChild(setBtn); const tips = document.createElement("div"); tips.style.cssText = ` margin-top: 10px; color: #888; font-size: 12px; `; tips.innerText = "预设了数字1-4进行倍速播放\n按 C键 / X键 加减速\n按 Z 键切换当前倍速和原始倍速\n也可用 Shift+↑/Shift+↓加减速\n Shift+0复位1.0倍\n在配置文件中可以关闭视频加速UI"; container.appendChild(tips); body.appendChild(container); } function closeSpeedUI() { const speedUI = document.getElementById("speed-ui-container"); if (speedUI) speedUI.remove(); } // 按键监听:Shift + ↑/↓ 加减速0.1; Shift+0 -> 1倍速 window.addEventListener("keydown", (e) => { const activeTag = document.activeElement.tagName.toLowerCase(); if (activeTag === 'input' || activeTag === 'textarea') { return; } if (e.shiftKey && !e.ctrlKey && !e.altKey) { if (e.key === "ArrowUp") { //e.preventDefault(); currentSpeed = parseFloat((currentSpeed + 0.1).toFixed(2)); setAllVideoPlaybackRate(currentSpeed); } else if (e.key === "ArrowDown") { //e.preventDefault(); let newSpeed = parseFloat((currentSpeed - 0.1).toFixed(2)); if (newSpeed < 0.1) newSpeed = 0.1; currentSpeed = newSpeed; setAllVideoPlaybackRate(currentSpeed); } else if (e.key === "0") { //e.preventDefault(); currentSpeed = 1.0; setAllVideoPlaybackRate(1.0); } } // 数字键 1 到 4 设置倍速 if (e.key >= '1' && e.key <= '4') { //e.preventDefault(); const speedMap = { '1': 1.0, '2': 2.0, '3': 3.0, '4': 4.0 }; setAllVideoPlaybackRate(speedMap[e.key]); } // 按 C 增加倍速 if (e.key === 'c' || e.key === 'C') { //e.preventDefault(); currentSpeed = parseFloat((currentSpeed + 0.1).toFixed(2)); setAllVideoPlaybackRate(currentSpeed); } // 按 X 减少倍速 if (e.key === 'x' || e.key === 'X') { //e.preventDefault(); currentSpeed = parseFloat((currentSpeed - 0.1).toFixed(2)); if (currentSpeed < 0.1) currentSpeed = 0.1; setAllVideoPlaybackRate(currentSpeed); } // 按 Z 切换倍速与原倍速 if (e.key === 'z' || e.key === 'Z') { //e.preventDefault(); if (currentSpeed === 1.0) { setAllVideoPlaybackRate(originalSpeed); } else { originalSpeed = currentSpeed; setAllVideoPlaybackRate(1.0); } } }); createSpeedTrigger(); // 初始化倍速按钮触发器 })();