Greasy Fork

Greasy Fork is available in English.

按住 ; 键倍速播放(支持音频)

按住 L 键或 ; 键时视频/音频倍速播放,松开恢复原速

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         按住 ; 键倍速播放(支持音频)
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  按住 L 键或 ; 键时视频/音频倍速播放,松开恢复原速
// @author       白鹭 & 优化版
// @match        *://*/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 配置
    const SPEED_KEY = ';';           // 触发键(; 键,通常与 L 键同键位但需 Shift,这里直接匹配按键值)
    const PLAYBACK_RATE = 3.0;       // 倍速
    const DEFAULT_RATE = 1.0;        // 原速

    let activeMedia = null;          // 当前激活的媒体元素(video 或 audio)
    let isHolding = false;           // 是否按住按键

    /**
     * 查找页面上的媒体元素(优先 video,其次 audio)
     * 策略:优先返回当前正在播放或有焦点的元素,否则返回第一个找到的媒体元素
     * @returns {HTMLMediaElement|null}
     */
    function findMediaElement() {
        // 优先检查当前有焦点的元素是否为媒体元素
        const focused = document.activeElement;
        if (focused && (focused.tagName === 'VIDEO' || focused.tagName === 'AUDIO')) {
            return focused;
        }

        // 查找所有视频和音频元素
        const mediaElements = Array.from(document.querySelectorAll('video, audio'));

        // 优先选择正在播放的媒体
        const playing = mediaElements.find(media => !media.paused && !media.ended);
        if (playing) return playing;

        // 返回第一个可用的媒体元素
        return mediaElements[0] || null;
    }

    /**
     * 设置媒体元素的播放速度
     * @param {HTMLMediaElement} media - 媒体元素
     * @param {number} rate - 倍速值
     */
    function setMediaSpeed(media, rate) {
        if (media && media.playbackRate !== rate) {
            media.playbackRate = rate;
            console.log(`[媒体倍速] 元素: ${media.tagName}, 速度: ${rate}x`);
        }
    }

    // 按键按下事件
    function onKeyDown(e) {
        if (e.repeat) return;  // 忽略按住时自动重复触发的事件
        // 检查按下的键是否为配置的键(忽略大小写,并处理实际按键值)
        if (e.key !== SPEED_KEY && e.key !== ';') return; // 兼容某些浏览器返回 ';' 或 ';' 的表示

        // 如果当前焦点在输入框或文本域中,不触发倍速
        const tagName = e.target.tagName;
        if (tagName === 'INPUT' || tagName === 'TEXTAREA' || tagName === 'SELECT') {
            return;
        }

        isHolding = true;
        activeMedia = findMediaElement();

        if (activeMedia) {
            setMediaSpeed(activeMedia, PLAYBACK_RATE);
        }
    }

    // 按键松开事件
    function onKeyUp(e) {
        if (e.key !== SPEED_KEY && e.key !== ';') return;

        isHolding = false;

        if (activeMedia) {
            setMediaSpeed(activeMedia, DEFAULT_RATE);
            activeMedia = null;
        }
    }

    // 页面失去焦点时,如果还按着键,则恢复原速
    function onBlur() {
        if (activeMedia && isHolding) {
            setMediaSpeed(activeMedia, DEFAULT_RATE);
        }
        isHolding = false;
        activeMedia = null;
    }

    // 监听键盘事件和窗口失焦
    document.addEventListener('keydown', onKeyDown);
    document.addEventListener('keyup', onKeyUp);
    window.addEventListener('blur', onBlur);

    // 可选:监听动态添加的媒体元素(无需额外处理,但保留 MutationObserver 以维持原有结构)
    const observer = new MutationObserver(() => {
        // 媒体元素变化时无需特殊操作,因为每次按键都会重新查找
    });
    observer.observe(document.body, { childList: true, subtree: true });

    console.log('[媒体倍速脚本] 已加载 - 按住 ; 键倍速播放(支持视频和音频)');
})();