// ==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(); // 初始化倍速按钮触发器
})();