Greasy Fork is available in English.
适用于所有网站,快捷方便进行速度的控制,一键解除完整视频速度的倍速限速,提供倍速控制面板和快捷键支持,自适应倍速播放功能。
// ==UserScript==
// @name 小叶的视频倍速播放器增强版 - 适配所有网站
// @namespace https://github.com/YiPort
// @version 1.0.2
// @description 适用于所有网站,快捷方便进行速度的控制,一键解除完整视频速度的倍速限速,提供倍速控制面板和快捷键支持,自适应倍速播放功能。
// @author 小叶
// @match *://*/*
// @license MIT
// @icon https://avatars.githubusercontent.com/u/120383087
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
// 全局配置
const CONFIG = {
UI: {
ICON_URL: 'https://avatars.githubusercontent.com/u/120383087'
},
SPEED_UI: {
SHOW_SPEED_UI: false // 设置是否显示倍速UI,默认为true
},
STYLE: {
COLORS: {
PRIMARY: '#00A1D6',
SECONDARY: '#40E0D0'
},
BORDER_RADIUS: {
SMALL: '4px',
MEDIUM: '8px',
LARGE: '16px'
},
TRANSITIONS: {
DEFAULT: 'all 0.3s ease'
}
},
LAYOUT: {
TRIGGER_WIDTH: {
DEFAULT: '40px',
EXPANDED: '80px'
}
}
};
// 初始化倍速播放器功能
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
const videos = document.querySelectorAll("video");
if (videos.length === 0 || !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, 0.8);
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
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, 0.8);
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;
`;
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);
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);
};
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 增加倍速\n按 X 减少倍速\n按 Z 切换倍速";
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);
}
}
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]);
}
if (e.key === 'c' || e.key === 'C') {
//e.preventDefault();
currentSpeed = parseFloat((currentSpeed + 0.1).toFixed(2));
setAllVideoPlaybackRate(currentSpeed);
}
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);
}
if (e.key === 'z' || e.key === 'Z') {
//e.preventDefault();
if (currentSpeed === 1.0) {
setAllVideoPlaybackRate(originalSpeed);
} else {
originalSpeed = currentSpeed;
setAllVideoPlaybackRate(1.0);
}
}
});
createSpeedTrigger(); // 初始化倍速按钮触发器
})();