Greasy Fork

Greasy Fork is available in English.

黄金右键2

Press and hold the right arrow key (→) to alter the video playback speed or simulate the original key function based on the length of the press.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         黄金右键2
// @description  Press and hold the right arrow key (→) to alter the video playback speed or simulate the original key function based on the length of the press.
// @namespace    http://tampermonkey.net/
// @version      1
// @author        edr1412
// @include      http://*
// @include      https://*
// @grant        none
// ==/UserScript==

(function () {
    "use strict";

    let keyDownTime = 0;
    let timeoutId = null;
    let originalRate = 1;
    const rateMultiplicationFactor = 2;
    const threshold = 100;  // Press duration threshold for distinguishing between short and long press
    let page_video;

    // Utility function to convert a NodeList to an Array
    function makeArray(arr) {
        return Array.prototype.slice.call(arr);
    }

    const init = () => {
        if (location.origin.indexOf("youtube.com") > -1) {
            // Special handling for YouTube
            document.body.addEventListener("keydown", handleKeyDown_YT, true);
            document.body.parentElement.addEventListener("keyup", handleKeyUp_YT, true);
        } else {
            document.addEventListener('keydown', handleKeyDown);
            document.addEventListener('keyup', handleKeyUp);
        }
    };

    // Handle keydown for general video elements
    function handleKeyDown(e) {
        if (e.keyCode !== 39) return;
        if (e.simulated) {
            console.log("Simulated event ignored...");
            return;
        }
        e.stopPropagation();

        if (keyDownTime === 0) {
            keyDownTime = Date.now();
            timeoutId = setTimeout(() => {
                if (Date.now() - keyDownTime >= threshold) {
                    increaseSpeed();
                }
            }, threshold);
        }
    }

    // Handle keyup for general video elements
    function handleKeyUp(e) {
        if (e.keyCode !== 39) return;
        e.stopPropagation();

        clearTimeout(timeoutId);
        let duration = Date.now() - keyDownTime;
        keyDownTime = 0;

        if (duration < threshold) {
            simulateOriginalFunction();
        } else {
            restoreSpeed();
        }
    }

    function increaseSpeed() {
        if (checkPageVideo(page_video) || (page_video = getPageVideo())) {
            relativeEvent.shouldPrevent && relativeEvent.prevent();
            originalRate = page_video.playbackRate;
            page_video.playbackRate = originalRate * rateMultiplicationFactor;
            console.log("加速播放中...");
        }
    }

    function restoreSpeed() {
        if (page_video && page_video.playbackRate !== originalRate) {
            page_video.playbackRate = originalRate;
            relativeEvent.shouldPrevent && relativeEvent.allow();
        }
    }

    function simulateOriginalFunction() {
        // Simulate keydown event
        let simulatedKeyDown = new KeyboardEvent("keydown", {
            bubbles: true,
            cancelable: true,
            keyCode: 39,
            simulated: true
        });
        document.dispatchEvent(simulatedKeyDown);

        // Simulate keyup event
        let simulatedKeyUp = new KeyboardEvent("keyup", {
            bubbles: true,
            cancelable: true,
            keyCode: 39,
            simulated: true
        });
        document.dispatchEvent(simulatedKeyUp);
    }

    /* for others */

    const getPageVideo = () => {
        console.log("Finding available Video Element...");
        const allVideoElementArray = makeArray(
            document.getElementsByTagName("video")
        ).concat(makeArray(document.getElementsByTagName("bwp-video")));
        console.log(allVideoElementArray);
        const page_video = Array.prototype.find.call(
            allVideoElementArray,
            (e) => {
                if (checkPageVideo(e)) return e;
            }
        );

        if (page_video) {
            console.log("Found the Video Element!");
            return page_video;
        } else {
            console.log("找不到正在播放的Video Element");
        }
    };
    const checkPageVideo = (v) => {
        if (v) {
            return v.offsetWidth > 9 && !v.paused;
        } else {
            return false;
        }
    };
    const relativeEvent = {
        _stopper: (e) => e.stopPropagation(),
        // 目前针对腾讯视频
        shouldPrevent:
            location.origin.indexOf("qq.com") > -1 ||
            location.origin.indexOf("wetv.vip") > -1,
        prevent() {
            document.body.addEventListener("ratechange", this._stopper, true);
            document.body.addEventListener("timeupdate", this._stopper, true);
        },
        allow() {
            document.body.removeEventListener(
                "ratechange",
                this._stopper,
                true
            );
            document.body.removeEventListener(
                "timeupdate",
                this._stopper,
                true
            );
        },
    };

    /* for youtube */

    const getPageVideo_YT = () => {
        console.log("Finding available Video Element...");
        let pv;

        if (document.getElementById("ytd-player") && checkPageVideo_YT(document.getElementById("ytd-player").player_))
            pv = document.getElementById("ytd-player").player_

        if (pv) {
            console.log("Found the Video Element!");
            return pv;
        } else {
            console.log("找不到正在播放的Video Element");
        }
    };
    const checkPageVideo_YT = (v) => {
        if (v) {
            return v.getPlayerState() == 1;
        } else {
            return false;
        }
    };


    // Handle keydown for general video elements
    function handleKeyDown_YT(e) {
        if (e.keyCode !== 39) return;
        if (e.simulated) {
            console.log("Simulated event ignored...");
            return;
        }
        e.stopPropagation();

        if (keyDownTime === 0) {
            keyDownTime = Date.now();
            timeoutId = setTimeout(() => {
                if (Date.now() - keyDownTime >= threshold) {
                    increaseSpeed_YT();
                }
            }, threshold);
        }
    }

    // Handle keyup for general video elements
    function handleKeyUp_YT(e) {
        if (e.keyCode !== 39) return;
        e.stopPropagation();

        clearTimeout(timeoutId);
        let duration = Date.now() - keyDownTime;
        keyDownTime = 0;

        if (duration < threshold) {
            simulateOriginalFunction();
        } else {
            restoreSpeed_YT();
        }
    }

    function increaseSpeed_YT() {
        if (checkPageVideo_YT(page_video) || (page_video = getPageVideo_YT())) {
            originalRate = page_video.getPlaybackRate();
            page_video.setPlaybackRate(originalRate * rateMultiplicationFactor);
            console.log("加速播放中...");
        }
    }

    function restoreSpeed_YT() {
        if (page_video && page_video.playbackRate !== originalRate) {
                page_video.setPlaybackRate(originalRate);
        }
    }

    // Initialization
    init();
})();