Greasy Fork

来自缓存

Greasy Fork is available in English.

视频临时倍速控制器

通过长按鼠标左键临时加速视频播放

当前为 2024-12-27 提交的版本,查看 最新版本

// ==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
// ==/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();
})();