Greasy Fork

Greasy Fork is available in English.

小叶的视频倍速播放器增强版 - 适配所有网站

适用于所有网站,快捷方便进行速度的控制,一键解除完整视频速度的倍速限速,提供倍速控制面板和快捷键支持,自适应倍速播放功能。

当前为 2025-04-06 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         小叶的视频倍速播放器增强版 - 适配所有网站
// @namespace    https://github.com/YiPort
// @version      1.0.2
// @description  适用于所有网站,快捷方便进行速度的控制,一键解除完整视频速度的倍速限速,提供倍速控制面板和快捷键支持,自适应倍速播放功能。
// @author       小叶
// @match        *://*/*
// @license MIT
// @icon         https://avatars.githubusercontent.com/u/120383087
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==


(function() {
    'use strict';

    // 全局配置
    const CONFIG = {
        UI: {
            ICON_URL: 'https://avatars.githubusercontent.com/u/120383087'
        },
        SPEED_UI: {
            SHOW_SPEED_UI: false // 设置是否显示倍速UI,默认为true
        },
        STYLE: {
            COLORS: {
                PRIMARY: '#00A1D6',
                SECONDARY: '#40E0D0'
            },
            BORDER_RADIUS: {
                SMALL: '4px',
                MEDIUM: '8px',
                LARGE: '16px'
            },
            TRANSITIONS: {
                DEFAULT: 'all 0.3s ease'
            }
        },
        LAYOUT: {
            TRIGGER_WIDTH: {
                DEFAULT: '40px',
                EXPANDED: '80px'
            }
        }
    };

    // 初始化倍速播放器功能
    let currentSpeed = 1.0;
    let originalSpeed = 1.0; // 记录原始倍速

    /**
     * 将页面上所有 <video> 标签的播放速率设置为指定值
     * @param {number} speed 要设定的倍速
     */
    function setAllVideoPlaybackRate(speed) {
        if (!speed || isNaN(speed) || speed <= 0) return;
        currentSpeed = speed;
        const videos = document.querySelectorAll("video");
        videos.forEach(video => {
            try {
                video.playbackRate = speed;
            } catch (e) {
                console.warn("[倍速] 设置视频倍速失败:", e);
            }
        });
        console.log("[倍速] 已将所有视频调节为", speed, "倍速");
        // 显示倍速
        displaySpeedOnVideo(speed);
        //更新倍速UI中的当前倍速
        updateSpeedDisplay(speed);
    }

    //显示倍速
    function displaySpeedOnVideo(speed) {
        const videoElement = document.querySelector('video');
        if (videoElement) {
             // Check if a speed display already exists, if so, remove it
            let existingSpeedDisplay = videoElement.parentElement.querySelector('.speed-display');
            if (existingSpeedDisplay) {
                existingSpeedDisplay.remove();
            }
             // Create new speed display
            const speedDisplay = document.createElement('div');
            speedDisplay.innerText = `倍速:${speed}`;
            speedDisplay.style.position = 'absolute';
            speedDisplay.style.top = '10px';
            speedDisplay.style.left = '10px';
            speedDisplay.style.padding = '5px';
            speedDisplay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
            speedDisplay.style.color = 'white';
            speedDisplay.style.fontSize = '16px';
            speedDisplay.style.fontWeight = 'bold';
            speedDisplay.style.borderRadius = '5px';
            speedDisplay.className = 'speed-display'; // Add class for easy removal

            videoElement.parentElement.appendChild(speedDisplay);

            // Set timeout to remove the speed display after 3 seconds
            setTimeout(() => {
                speedDisplay.remove();
            }, 3000);
        }
    }

    // 更新倍速UI中的当前倍速
    function updateSpeedDisplay(speed) {
        const currentSpeedLabel = document.getElementById("current-speed-label");
        if (currentSpeedLabel) {
            currentSpeedLabel.innerText = `当前倍速:${speed}x`;
        }
    }

    // 新建一个倍速按钮Trigger
    const SPEED_TRIGGER_ID = "speed-trigger-container";
    let isSpeedPopupVisible = false;

    function createSpeedTrigger() {
        // 仅当页面上有视频元素时,才显示倍速UI
        const videos = document.querySelectorAll("video");
        if (videos.length === 0 || !CONFIG.SPEED_UI.SHOW_SPEED_UI) return;

        const existingSpeedTrigger = document.getElementById(SPEED_TRIGGER_ID);
        if (existingSpeedTrigger) existingSpeedTrigger.remove();

        const body = document.body;
        const trigger = document.createElement("div");
        trigger.id = SPEED_TRIGGER_ID;
        trigger.style.cssText = `
            position: fixed;
            right: 0;
            top: 25%;
            transform: translateY(-50%);
            z-index: 999999;
            text-align: center;
            border: 1px solid #FF8C00;
            border-radius: 8px;
            background-color: rgba(255, 255, 255, 0.8);
            padding: 8px;
            width: 40px;
            transition: all 0.3s ease;
            cursor: pointer;
        `;
        const icon = document.createElement("div");
        icon.innerText = "倍速";
        icon.style.cssText = `
            font-size: 14px;
            color: #FF8C00;
            text-align: center;
            user-select: none;
        `;
        trigger.appendChild(icon);

        trigger.addEventListener("click", toggleSpeedPopup);

        // hover时宽度变大
        trigger.onmouseenter = () => {
            trigger.style.width = "80px";
            icon.style.display = "block";
        };
        trigger.onmouseleave = () => {
            if (!isSpeedPopupVisible) {
                trigger.style.width = "40px";
            }
        };

        body.appendChild(trigger);
    }

    function toggleSpeedPopup() {
        isSpeedPopupVisible = !isSpeedPopupVisible;
        if (isSpeedPopupVisible) {
            createSpeedUI();
            const trig = document.getElementById(SPEED_TRIGGER_ID);
            if (trig) {
                trig.style.width = "80px";
            }
        } else {
            closeSpeedUI();
            const trig = document.getElementById(SPEED_TRIGGER_ID);
            if (trig) {
                trig.style.width = "40px";
            }
        }
    }

    // 创建倍速UI
    function createSpeedUI() {
        const body = document.body;
        if (document.getElementById("speed-ui-container")) {
            return;
        }

        const container = document.createElement("div");
        container.id = "speed-ui-container";
        container.style.cssText = `
            padding: 10px;
            background-color: rgba(255, 255, 255, 0.8);
            position: fixed;
            right: 80px;
            top: 25%;
            width: 200px;
            max-width: 60%;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
            border: 1px solid #FF8C00;
            z-index: 999999;
            text-align: center;
            font-size: 14px;
            color: #444;
        `;

        const closeBtn = document.createElement("button");
        closeBtn.innerText = "关闭";
        closeBtn.style.cssText = `
            position: absolute;
            top: 5px;
            right: 5px;
            border: none;
            background-color: #f90;
            color: #FFF;
            padding: 2px 6px;
            cursor: pointer;
            border-radius: 4px;
        `;
        closeBtn.onclick = toggleSpeedPopup;
        container.appendChild(closeBtn);

        const title = document.createElement("h4");
        title.innerText = "视频倍速设置";
        title.style.cssText = `
            margin-bottom: 8px;
            color: #FF8C00;
            font-weight: bold;
        `;
        container.appendChild(title);

        // 倍速输入框
        const label = document.createElement("label");
        label.innerText = "请输入倍速:";
        label.style.cssText = "margin-right: 5px;";
        container.appendChild(label);

        const speedInput = document.createElement("input");
        speedInput.type = "number";
        speedInput.value = currentSpeed;
        speedInput.min = "0.1";
        speedInput.step = "0.1";
        speedInput.style.cssText = `
            width: 60px;
            text-align: center;
            border-radius: 4px;
            border: 1px solid #ccc;
            margin-bottom: 10px;
        `;
        container.appendChild(speedInput);

        const currentSpeedLabel = document.createElement("div");
        currentSpeedLabel.id = "current-speed-label";
        currentSpeedLabel.style.cssText = `
            margin-top: 8px;
            color: #555;
            font-size: 14px;
        `;
        currentSpeedLabel.innerText = `当前倍速:${currentSpeed}x`;
        container.appendChild(currentSpeedLabel);

        const setBtn = document.createElement("button");
        setBtn.innerText = "应用";
        setBtn.style.cssText = `
            margin-left: 8px;
            background-color: #00A1D6;
            color: #FFF;
            border: none;
            padding: 4px 8px;
            cursor: pointer;
            border-radius: 4px;
        `;
        setBtn.onclick = () => {
            const val = parseFloat(speedInput.value) || 1;
            if (val <= 0) {
                alert("非法倍速值!");
                return;
            }
            setAllVideoPlaybackRate(val);
        };
        container.appendChild(setBtn);

        const tips = document.createElement("div");
        tips.style.cssText = `
            margin-top: 10px;
            color: #888;
            font-size: 12px;
        `;
        tips.innerText = "使用数字键1-4进行倍速播放\n按 C 增加倍速\n按 X 减少倍速\n按 Z 切换倍速";
        container.appendChild(tips);

        body.appendChild(container);
    }

    function closeSpeedUI() {
        const speedUI = document.getElementById("speed-ui-container");
        if (speedUI) speedUI.remove();
    }

    // 按键监听:Shift + ↑/↓ 加减速0.1; Shift+0 -> 1倍速
    window.addEventListener("keydown", (e) => {
        const activeTag = document.activeElement.tagName.toLowerCase();
        if (activeTag === 'input' || activeTag === 'textarea') {
            return;
        }

        if (e.shiftKey && !e.ctrlKey && !e.altKey) {
            if (e.key === "ArrowUp") {
                //e.preventDefault();
                currentSpeed = parseFloat((currentSpeed + 0.1).toFixed(2));
                setAllVideoPlaybackRate(currentSpeed);
            } else if (e.key === "ArrowDown") {
                //e.preventDefault();
                let newSpeed = parseFloat((currentSpeed - 0.1).toFixed(2));
                if (newSpeed < 0.1) newSpeed = 0.1;
                currentSpeed = newSpeed;
                setAllVideoPlaybackRate(currentSpeed);
            } else if (e.key === "0") {
                //e.preventDefault();
                currentSpeed = 1.0;
                setAllVideoPlaybackRate(1.0);
            }
        }

        if (e.key >= '1' && e.key <= '4') {
            //e.preventDefault();
            const speedMap = { '1': 1.0, '2': 2.0, '3': 3.0, '4': 4.0 };
            setAllVideoPlaybackRate(speedMap[e.key]);
        }

        if (e.key === 'c' || e.key === 'C') {
            //e.preventDefault();
            currentSpeed = parseFloat((currentSpeed + 0.1).toFixed(2));
            setAllVideoPlaybackRate(currentSpeed);
        }

        if (e.key === 'x' || e.key === 'X') {
            //e.preventDefault();
            currentSpeed = parseFloat((currentSpeed - 0.1).toFixed(2));
            if (currentSpeed < 0.1) currentSpeed = 0.1;
            setAllVideoPlaybackRate(currentSpeed);
        }

        if (e.key === 'z' || e.key === 'Z') {
            //e.preventDefault();
            if (currentSpeed === 1.0) {
                setAllVideoPlaybackRate(originalSpeed);
            } else {
                originalSpeed = currentSpeed;
                setAllVideoPlaybackRate(1.0);
            }
        }
    });

    createSpeedTrigger(); // 初始化倍速按钮触发器

})();