独播库专用视频快捷键倍速控制器

独播库专用视频快捷键倍速播放器快进、快退、音量调节、倍速播放、暂停控制添加自定义网址等功能。可以自定义设置控制按键,快进快退秒数,倍速播放倍速等。并显示通知

// ==UserScript==
// @name         独播库专用视频快捷键倍速控制器
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  独播库专用视频快捷键倍速播放器快进、快退、音量调节、倍速播放、暂停控制添加自定义网址等功能。可以自定义设置控制按键,快进快退秒数,倍速播放倍速等。并显示通知
// @author       NB888
// @match        https://www.duboku.tv/*
// @match        https://w.duboku.io/*
// @match        https://v.duboku.io/*
// @match        https://tv.gboku.com/*
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        unsafeWindow
// @license      Proprietary - Only for personal use, no modifications or redistributions allowed. 
//               The code may not be modified, copied, distributed, or used for derivative works without explicit permission.
// ==/UserScript==

(function() {
    'use strict';

    // 获取并设置默认值
    const defaults = {
        fastForwardSeconds: 10, // 快进秒数
        fastRewindSeconds: 10, // 快退秒数
        volumeChange: 5, // 音量增量
        pauseKey: "Space", // 暂停和恢复的键
        forwardKey: "ArrowRight", // 快进的键
        rewindKey: "ArrowLeft", // 快退的键
        volumeUpKey: "ArrowUp", // 音量增加的键
        volumeDownKey: "ArrowDown", // 音量减少的键
        playbackRate: 2.0, // 倍速播放默认值
        enabledSites: "u.duboku.io", // 默认生效的网站
    };

    // 从存储中读取自定义设置
    const getSettings = () => {
        return {
            fastForwardSeconds: GM_getValue('fastForwardSeconds', defaults.fastForwardSeconds),
            fastRewindSeconds: GM_getValue('fastRewindSeconds', defaults.fastRewindSeconds),
            volumeChange: GM_getValue('volumeChange', defaults.volumeChange),
            pauseKey: GM_getValue('pauseKey', defaults.pauseKey),
            forwardKey: GM_getValue('forwardKey', defaults.forwardKey),
            rewindKey: GM_getValue('rewindKey', defaults.rewindKey),
            volumeUpKey: GM_getValue('volumeUpKey', defaults.volumeUpKey),
            volumeDownKey: GM_getValue('volumeDownKey', defaults.volumeDownKey),
            playbackRate: GM_getValue('playbackRate', defaults.playbackRate),
            enabledSites: GM_getValue('enabledSites', defaults.enabledSites),
        };
    };

    // 保存设置到存储
    const saveSettings = (key, value) => {
        GM_setValue(key, value);
    };

    // 显示快进/快退/倍速播放提示
    const showPlaybackHint = (message, direction = 'forward') => {
        const video = document.querySelector('video');
        if (!video) return;

        const hint = document.createElement('div');
        hint.style.position = 'absolute';
        hint.style.top = '50%';
        hint.style.left = '50%';
        hint.style.transform = 'translate(-50%, -50%)';
        hint.style.width = direction === 'playbackRate' || direction === 'playbackRateRewind' ? '72px' : '88px'; // 快进快退提示增大 10%
        hint.style.height = direction === 'playbackRate' || direction === 'playbackRateRewind' ? '72px' : '88px'; // 快进快退提示增大 10%
        hint.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // 半透明背景
        hint.style.borderRadius = '50%';
        hint.style.display = 'flex';
        hint.style.flexDirection = 'column';
        hint.style.alignItems = 'center';
        hint.style.justifyContent = 'center';
        hint.style.zIndex = '10000';

        // 添加 3 个三角形
        const triangles = document.createElement('div');
        triangles.style.display = 'flex';
        triangles.style.gap = '5px';
        for (let i = 0; i < 3; i++) {
            const triangle = document.createElement('div');
            triangle.style.width = '0';
            triangle.style.height = '0';
            triangle.style.borderTop = '8px solid transparent';
            triangle.style.borderBottom = '8px solid transparent';
            if (direction === 'rewind' || direction === 'playbackRateRewind') {
                triangle.style.borderRight = '12px solid white'; // 向左倒的三角形
            } else {
                triangle.style.borderLeft = '12px solid white'; // 向右倒的三角形
            }
            triangles.appendChild(triangle);
        }
        hint.appendChild(triangles);

        // 添加秒数提示
        const text = document.createElement('div');
        text.style.color = 'white';
        text.style.fontSize = '14px';
        text.style.marginTop = '5px';
        text.innerText = message;
        hint.appendChild(text);

        video.parentElement.appendChild(hint);

        // 如果是倍速播放提示,设置闪烁效果
        if (direction === 'playbackRate' || direction === 'playbackRateRewind') {
            let isVisible = true;
            const blinkInterval = setInterval(() => {
                hint.style.opacity = isVisible ? '0' : '1';
                isVisible = !isVisible;
            }, 200); // 0.2秒闪烁一次

            // 返回提示元素和闪烁间隔,以便在按键松开时清除
            return { hint, blinkInterval };
        } else {
            // 0.5秒后消失
            setTimeout(() => {
                hint.remove();
            }, 500);
            return null;
        }
    };

    // 显示保存成功提示
    const showSaveSuccessHint = () => {
        const video = document.querySelector('video');
        if (!video) return;

        const hint = document.createElement('div');
        hint.style.position = 'absolute';
        hint.style.top = '50%';
        hint.style.left = '50%';
        hint.style.transform = 'translate(-50%, -50%)';
        hint.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // 半透明背景
        hint.style.color = 'white';
        hint.style.padding = '10px';
        hint.style.borderRadius = '5px';
        hint.style.fontSize = '16px';
        hint.style.zIndex = '10000';
        hint.innerText = '保存成功';

        video.parentElement.appendChild(hint);

        // 0.5秒后消失
        setTimeout(() => {
            hint.remove();
        }, 500);
    };

    // 显示音量提示
    const showVolumeHint = (volume) => {
        const video = document.querySelector('video');
        if (!video) return;

        const hint = document.createElement('div');
        hint.style.position = 'absolute';
        hint.style.top = '50%';
        hint.style.left = '50%';
        hint.style.transform = 'translate(-50%, -50%)';
        hint.style.width = '60px';
        hint.style.height = '40px';
        hint.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // 半透明背景
        hint.style.borderRadius = '5px';
        hint.style.display = 'flex';
        hint.style.alignItems = 'center';
        hint.style.justifyContent = 'center';
        hint.style.zIndex = '10000';

        const text = document.createElement('div');
        text.style.color = 'white';
        text.style.fontSize = '16px';
        text.innerText = `${Math.round(volume * 100)}%`;
        hint.appendChild(text);

        video.parentElement.appendChild(hint);

        // 0.5秒后消失
        setTimeout(() => {
            hint.remove();
        }, 500);
    };

    // 显示暂停图标
    const showPauseIcon = () => {
        const video = document.querySelector('video');
        if (!video) return;

        const pauseIcon = document.createElement('div');
        pauseIcon.style.position = 'absolute';
        pauseIcon.style.top = '50%';
        pauseIcon.style.left = '50%';
        pauseIcon.style.transform = 'translate(-50%, -50%)';
        pauseIcon.style.width = '60px';
        pauseIcon.style.height = '60px';
        pauseIcon.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // 半透明背景
        pauseIcon.style.borderRadius = '50%';
        pauseIcon.style.display = 'flex';
        pauseIcon.style.alignItems = 'center';
        pauseIcon.style.justifyContent = 'center';
        pauseIcon.style.zIndex = '10000';

        const triangle = document.createElement('div');
        triangle.style.width = '0';
        triangle.style.height = '0';
        triangle.style.borderTop = '15px solid transparent';
        triangle.style.borderBottom = '15px solid transparent';
        triangle.style.borderLeft = '25px solid white';
        triangle.style.transform = 'translateX(3px)'; // 向右偏移

        pauseIcon.appendChild(triangle);
        video.parentElement.appendChild(pauseIcon);

        // 监听播放事件,移除图标
        const onPlay = () => {
            pauseIcon.remove();
            video.removeEventListener('play', onPlay);
        };
        video.addEventListener('play', onPlay);
    };

    // 长按快进/快退倍速播放
    let isKeyHeld = false;
    let playbackHint = null; // 存储倍速播放提示

    const startKeyHold = (video, direction, settings) => {
        if (isKeyHeld) return;
        isKeyHeld = true;

        // 设置播放速度
        video.playbackRate = settings.playbackRate;
        playbackHint = showPlaybackHint(`${settings.playbackRate}倍速`, direction === 'rewind' ? 'playbackRateRewind' : 'playbackRate');
    };

    const stopKeyHold = (video) => {
        if (!isKeyHeld) return;
        isKeyHeld = false;
        video.playbackRate = 1.0; // 恢复默认播放速度

        // 清除倍速播放提示
        if (playbackHint) {
            clearInterval(playbackHint.blinkInterval);
            playbackHint.hint.remove();
            playbackHint = null;
        }
    };

    // 事件监听器:绑定快捷键事件
    let currentKeyListener = null; // 用于存储当前的事件监听器
    const bindKeys = (settings) => {
        // 移除旧的事件监听器
        if (currentKeyListener) {
            document.removeEventListener('keydown', currentKeyListener);
            document.removeEventListener('keyup', currentKeyListener);
        }

        // 创建新的事件监听器
        currentKeyListener = (event) => {
            const video = document.querySelector('video');
            if (!video) return;

            // 阻止页面滚动行为
            if (event.key === settings.volumeUpKey || event.key === settings.volumeDownKey) {
                event.preventDefault();
            }

            switch (event.key) {
                case settings.pauseKey: // 空格键暂停/恢复
                    if (event.type === 'keydown') {
                        if (video.paused) {
                            video.play();
                        } else {
                            video.pause();
                            showPauseIcon(); // 显示暂停图标
                        }
                    }
                    break;
                case settings.forwardKey: // 快进
                    if (event.type === 'keydown') {
                        if (event.repeat) {
                            startKeyHold(video, 'forward', settings);
                        } else {
                            video.currentTime += settings.fastForwardSeconds;
                            showPlaybackHint(`快进 ${settings.fastForwardSeconds} 秒`, 'forward');
                        }
                    } else if (event.type === 'keyup') {
                        stopKeyHold(video);
                    }
                    break;
                case settings.rewindKey: // 快退
                    if (event.type === 'keydown') {
                        if (event.repeat) {
                            startKeyHold(video, 'rewind', settings);
                        } else {
                            video.currentTime -= settings.fastRewindSeconds;
                            showPlaybackHint(`快退 ${settings.fastRewindSeconds} 秒`, 'rewind');
                        }
                    } else if (event.type === 'keyup') {
                        stopKeyHold(video);
                    }
                    break;
                case settings.volumeUpKey: // 音量增加
                    if (event.type === 'keydown') {
                        video.volume = Math.min(1, video.volume + settings.volumeChange / 100);
                        showVolumeHint(video.volume);
                    }
                    break;
                case settings.volumeDownKey: // 音量减少
                    if (event.type === 'keydown') {
                        video.volume = Math.max(0, video.volume - settings.volumeChange / 100);
                        showVolumeHint(video.volume);
                    }
                    break;
            }
        };

        // 绑定新的事件监听器
        document.addEventListener('keydown', currentKeyListener);
        document.addEventListener('keyup', currentKeyListener);
    };

    // 监听全屏状态变化
    document.addEventListener('fullscreenchange', () => {
        const isFullscreen = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement;
        if (isFullscreen) {
            console.log('进入全屏模式');
        } else {
            console.log('退出全屏模式');
        }
    });

    // 创建设置面板
    const createSettingsPanel = () => {
        const settings = getSettings();
        const panel = document.createElement('div');
        panel.style.position = 'absolute';
        panel.style.top = '10px';
        panel.style.left = '10px';
        panel.style.background = 'rgba(0, 0, 0, 0.7)';
        panel.style.color = '#fff';
        panel.style.padding = '10px';
        panel.style.borderRadius = '5px';
        panel.style.zIndex = '10000';
        panel.innerHTML = `
            <h3>自定义视频控制</h3>
            <label>快进秒数: <input type="number" id="fastForwardSeconds" value="${settings.fastForwardSeconds}" /></label><br>
            <label>快退秒数: <input type="number" id="fastRewindSeconds" value="${settings.fastRewindSeconds}" /></label><br>
            <label>音量增量: <input type="number" id="volumeChange" value="${settings.volumeChange}" /></label><br>
            <label>倍速播放: <input type="number" id="playbackRate" value="${settings.playbackRate}" step="0.1" /></label><br>
            <label>暂停/恢复键: <input type="text" id="pauseKey" value="${settings.pauseKey}" readonly /></label><br>
            <label>快进键: <input type="text" id="forwardKey" value="${settings.forwardKey}" readonly /></label><br>
            <label>快退键: <input type="text" id="rewindKey" value="${settings.rewindKey}" readonly /></label><br>
            <label>音量加键: <input type="text" id="volumeUpKey" value="${settings.volumeUpKey}" readonly /></label><br>
            <label>音量减键: <input type="text" id="volumeDownKey" value="${settings.volumeDownKey}" readonly /></label><br>
            <label>生效网站: <textarea id="enabledSites" rows="3">${settings.enabledSites}</textarea></label><br>
            <div style="display: flex; gap: 10px; margin-top: 10px;">
                <button id="saveSettings" style="background-color: green; color: white; padding: 5px 10px; border: none; border-radius: 3px; cursor: pointer;">保存设置</button>
                <button id="exitSettings" style="background-color: red; color: white; padding: 5px 10px; border: none; border-radius: 3px; cursor: pointer;">退出设置</button>
            </div>
        `;

        // 只在视频区域显示面板
        const videoArea = document.querySelector('video');
        if (videoArea) {
            videoArea.parentElement.appendChild(panel);
        }

        // 为输入框绑定按键监听
        const keyInputs = panel.querySelectorAll('input[type="text"]');
        keyInputs.forEach(input => {
            input.addEventListener('click', () => {
                input.value = '按下按键...';
                const keyListener = (event) => {
                    event.preventDefault();
                    input.value = event.key;
                    document.removeEventListener('keydown', keyListener);
                };
                document.addEventListener('keydown', keyListener);
            });
        });

        // 保存设置
        document.getElementById('saveSettings').addEventListener('click', () => {
            // 保存用户设置
            saveSettings('fastForwardSeconds', parseInt(document.getElementById('fastForwardSeconds').value));
            saveSettings('fastRewindSeconds', parseInt(document.getElementById('fastRewindSeconds').value));
            saveSettings('volumeChange', parseInt(document.getElementById('volumeChange').value));
            saveSettings('playbackRate', parseFloat(document.getElementById('playbackRate').value));
            saveSettings('pauseKey', document.getElementById('pauseKey').value);
            saveSettings('forwardKey', document.getElementById('forwardKey').value);
            saveSettings('rewindKey', document.getElementById('rewindKey').value);
            saveSettings('volumeUpKey', document.getElementById('volumeUpKey').value);
            saveSettings('volumeDownKey', document.getElementById('volumeDownKey').value);
            saveSettings('enabledSites', document.getElementById('enabledSites').value);

            // 显示保存成功提示
            showSaveSuccessHint();

            // 重新绑定事件监听器
            const updatedSettings = getSettings();
            bindKeys(updatedSettings);

            // 关闭设置面板
            panel.remove();
        });

        // 退出设置
        document.getElementById('exitSettings').addEventListener('click', () => {
            panel.remove(); // 关闭设置面板
        });
    };

    // 在 Tampermonkey 扩展菜单中注册(不可用)设置按钮
    GM_registerMenuCommand("打开设置", () => {
        createSettingsPanel();
    });

    // 检查当前网站是否在生效网站列表中
    const settings = getSettings();
    const enabledSites = settings.enabledSites.split('\n').map(site => site.trim());
    const currentSite = window.location.hostname;

    if (enabledSites.includes(currentSite)) {
        bindKeys(settings);
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址