// ==UserScript== // @name 视频临时倍速控制器 // @namespace http://tampermonkey.net/ // @version 0.1 // @description 通过长按鼠标左键临时加速视频播放 // @author Alonewinds // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @run-at document-start // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 默认配置 const config = { speedRate: GM_getValue('speedRate', 2.0), minPressTime: 200, // 预定义网站特定选择器 selectors: { 'www.bilibili.com': '.bilibili-player-video-control-wrap, .squirtle-controller-wrap', 'www.youtube.com': '.ytp-chrome-bottom, .ytp-progress-bar', 'default': '.video-controls, .progress-bar, [role="slider"]' } }; // 状态变量 let pressStartTime = 0; let originalSpeed = 1.0; let isPressed = false; let activeVideo = null; let isLongPress = false; let preventNextClick = false; // 注册设置菜单 GM_registerMenuCommand('设置倍速值', () => { const newSpeed = prompt('请输入新的倍速值(建议范围:1.1-4):', config.speedRate); if (newSpeed && !isNaN(newSpeed)) { config.speedRate = parseFloat(newSpeed); GM_setValue('speedRate', config.speedRate); } }); // 查找视频元素(优化版本) function findVideoElement(element) { if (!element) return null; // 直接检查是否为视频元素 if (element instanceof HTMLVideoElement) { return element; } // 获取当前网站的域名和控制栏选择器 const domain = window.location.hostname; const controlSelector = config.selectors[domain] || config.selectors.default; if (element.closest(controlSelector)) { return null; } // YouTube 特殊处理 if (domain === 'www.youtube.com') { const ytPlayer = element.closest('.html5-video-player'); return ytPlayer ? ytPlayer.querySelector('video') : null; } // 通用查找 const container = element.closest('*:has(video)'); const video = container?.querySelector('video'); return video && window.getComputedStyle(video).display !== 'none' ? video : null; } // 鼠标按下事件处理 function handleMouseDown(e) { if (e.button !== 0) return; // 只处理左键 const video = findVideoElement(e.target); if (!video) return; pressStartTime = Date.now(); activeVideo = video; // 确保获取正确的原始速度 originalSpeed = window.location.hostname === 'www.youtube.com' ? (video.closest('.html5-video-player').querySelector('.video-stream')?.playbackRate || video.playbackRate) : video.playbackRate; isPressed = true; isLongPress = false; preventNextClick = false; } // 鼠标释放事件处理 function handleMouseUp(e) { if (!isPressed || !activeVideo) return; const pressDuration = Date.now() - pressStartTime; if (pressDuration >= config.minPressTime) { preventNextClick = true; setYouTubeSpeed(activeVideo, originalSpeed); } isPressed = false; isLongPress = false; activeVideo = null; } // 处理长按检测 function handlePressDetection() { if (!isPressed || !activeVideo) return; const pressDuration = Date.now() - pressStartTime; // 只在首次达到长按时间时设置 isLongPress if (pressDuration >= config.minPressTime) { // 确保在长按期间保持加速状态 if (activeVideo.playbackRate !== config.speedRate) { setYouTubeSpeed(activeVideo, config.speedRate); } isLongPress = true; } } // 处理点击事件 function handleClick(e) { if (preventNextClick) { e.stopPropagation(); preventNextClick = false; return; } } // 添加新的辅助函数来处理 YouTube 的播放速度 function setYouTubeSpeed(video, speed) { if (window.location.hostname === 'www.youtube.com') { // 获取 YouTube 播放器实例 const player = video.closest('.html5-video-player'); if (player) { try { // 同时设置 video 元素和 YouTube 播放器的速度 video.playbackRate = speed; const moviePlayer = player.querySelector('.video-stream'); if (moviePlayer) { moviePlayer.playbackRate = speed; } // 强制更新 YouTube 的内部状态 video.dispatchEvent(new Event('ratechange')); } catch (e) { console.error('设置 YouTube 播放速度失败:', e); } } } else { // 非 YouTube 视频直接设置速度 video.playbackRate = speed; } } // 初始化事件监听 function initializeEvents() { document.addEventListener('mousedown', handleMouseDown, true); // 改为捕获阶段 document.addEventListener('mouseup', handleMouseUp, true); // 改为捕获阶段 document.addEventListener('click', handleClick, true); // 添加鼠标移出视频区域的处理 document.addEventListener('mouseleave', handleMouseUp, true); function checkPress() { handlePressDetection(); requestAnimationFrame(checkPress); } checkPress(); } // 启动脚本 initializeEvents(); })();