版本 | 更新内容 |
0.1 | 初步实现倍速功能 |
0.2 | 对playbackRate 进行了四舍五入处理,使用toFixed(1) 方法来限制播放速度只保留一位小数。增加了 z-index: 10000; 到提示框的样式中,确保提示框能够覆盖在网页的所有内容之上。确保每次更新提示信息后,提示框会立即显示出来,并在一秒钟后自动隐藏。 |
0.3 | 将提示框的显示时间从原来的1秒延长到了3秒,以便用户有足够的时间查看当前的播放速度。 将提示框的 z-index 设置为JavaScript中允许的最大值(2147483647),这应该足以保证它在大多数情况下都能覆盖其他元素,包括视频全屏时的情况。添加了 pointer-events: none; 样式规则,允许用户点击穿透提示框,避免影响视频或其他页面元素的操作。 |
0.4 | 更新了updateSpeedIndicator 函数:这个函数用于更新并显示当前的播放速度。如果播放速度不等于默认值(即1),则显示当前的速度倍数;否则,隐藏显示。添加了对 ratechange 事件的监听:这样可以在用户通过其他方式改变播放速度时(例如使用浏览器原生控件或其它快捷键),也能正确更新显示的速度倍数。增强了全屏模式下的兼容性:虽然主要的样式和逻辑没有变,但通过确保 z-index 足够高,并且允许点击穿透(pointer-events: none ),提高了在全屏模式下显示提示框的可靠性。 |
0.5 | 使用!important 来强制应用样式规则 |
0.6 | 通过监听fullscreenchange 事件,检测用户何时进入或退出全屏模式,并据此调整提示框的显示逻辑,以确保在全屏模式下也能正确显示速度提示框 |
0.7 | 更新了#speedIndicator 的CSS样式,将其位置固定在屏幕的左上角,并且在更新速度指示器内容时使用了toFixed(1) 方法来保证倍速显示只有一位小数 |
0.8 | 扩展适用范围至所有包含视频标签(<video> )的网页增加功能:按 Z 键恢复至1倍速。实现视频倍速记忆功能,即当用户调整播放速度后,关闭页面或刷新时能记住这个速度设置。 |
0.9 | 倍速记忆功能:我们将使用localStorage 来存储用户设置的播放速度,这样即使关闭浏览器或刷新页面后也能记住用户的设置。Z键恢复至1倍速时显示提示框:确保在按下 Z 键将视频播放速度恢复到1倍速时,同样更新并显示提示框。 |
1.0 | 修复按下任意键提示框都会显示的问题 |
// ==UserScript==
// @name Universal Video Speed Controller with Memory
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Control video speed universally across all websites, with speed memory and reset to 1x speed.
// @author Your Name
// @match *://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const defaultSpeed = 1; // 默认播放速度
let currentSpeed = parseFloat(localStorage.getItem('videoSpeed')) || defaultSpeed;
function updateSpeedIndicator(video) {
const indicator = document.getElementById('speedIndicator');
if (indicator) {
indicator.textContent = `Speed: ${video.playbackRate.toFixed(1)}x`;
indicator.style.display = 'block'; // 显示当前播放速度
setTimeout(() => indicator.style.display = 'none', 3000); // 3秒后自动隐藏提示框
}
}
function setupVideoControls(video) {
video.playbackRate = currentSpeed; // 设置播放速度为最后的记忆值
document.addEventListener('keydown', function(event) {
// 确保只处理特定的快捷键,并且焦点不在可编辑元素上
if (!['c', 'x', 'z'].includes(event.key) || ['INPUT', 'TEXTAREA', 'SELECT'].includes(event.target.tagName.toUpperCase())) {
return;
}
if (event.key === 'c') {
video.playbackRate += 0.1;
} else if (event.key === 'x') {
video.playbackRate -= 0.1;
} else if (event.key === 'z') {
video.playbackRate = defaultSpeed;
}
localStorage.setItem('videoSpeed', video.playbackRate); // 更新速度记忆
updateSpeedIndicator(video);
});
video.addEventListener('ratechange', function() {
updateSpeedIndicator(this);
});
}
function createSpeedIndicator() {
const style = document.createElement('style');
style.innerHTML = `
#speedIndicator {
position: fixed;
top: 10px;
left: 10px;
background-color: rgba(0,0,0,0.7);
color: white;
padding: 5px;
border-radius: 3px;
font-size: 14px;
display: none;
z-index: 2147483647;
pointer-events: none;
}
`;
document.head.appendChild(style);
const speedIndicator = document.createElement('div');
speedIndicator.id = 'speedIndicator';
document.body.appendChild(speedIndicator);
}
window.addEventListener('load', () => {
createSpeedIndicator();
const videos = document.querySelectorAll('video');
videos.forEach(video => setupVideoControls(video));
});
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.tagName === 'VIDEO') {
setupVideoControls(node);
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
})();