Greasy Fork

Greasy Fork is available in English.

Plyr Video Controller Pro

带浮动控制面板的Plyr视频控制器(播放时触发跳转)

当前为 2025-05-14 提交的版本,查看 最新版本

// ==UserScript==
// @name         Plyr Video Controller Pro
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  带浮动控制面板的Plyr视频控制器(播放时触发跳转)
// @author       glenn
// @match        http://dxzx.ouc.edu.cn/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 配置存储
    const config = {
        autoSkip: GM_getValue('autoSkip', true),
        enableSeek: GM_getValue('enableSeek', true),
        playbackSpeed: GM_getValue('speed', 2.0),
        skipDelay: GM_getValue('delay', 100),
        debugMode: GM_getValue('debug', true)
    };

    // 添加浮动面板样式(保持原图简洁风格)
    GM_addStyle(`
        #plyr-control-panel {
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 9999;
            background: white;
            color: black;
            padding: 10px;
            border-radius: 5px;
            font-family: monospace;
            box-shadow: 0 0 5px rgba(0,0,0,0.3);
            border: 1px solid #ddd;
            font-size: 13px;
        }
        #plyr-control-panel h3 {
            margin: 0 0 8px 0;
            color: #333;
            font-size: 14px;
        }
        .control-row {
            margin-bottom: 8px;
            display: flex;
            align-items: center;
        }
        .control-label {
            margin-right: 10px;
            min-width: 100px;
        }
        .control-btn {
            background: #f0f0f0;
            border: 1px solid #ccc;
            color: #333;
            padding: 3px 8px;
            border-radius: 3px;
            cursor: pointer;
            font-size: 12px;
            margin-left: 5px;
        }
        .control-btn:hover {
            background: #e0e0e0;
        }
        .control-checkbox {
            margin-right: 5px;
        }
        .speed-input {
            width: 40px;
            margin-left: 5px;
        }
    `);

    // 创建浮动控制面板(保持原图风格)
    function createControlPanel() {
        const panel = document.createElement('div');
        panel.id = 'plyr-control-panel';
        panel.innerHTML = `
            <h3>Plyr Controller</h3>
            <div class="control-row">
                <label class="control-label">
                    <input type="checkbox" class="control-checkbox" id="auto-skip" ${config.autoSkip ? 'checked' : ''}>
                    Auto Skip
                </label>
            </div>
            <div class="control-row">
                <label class="control-label">
                    <input type="checkbox" class="control-checkbox" id="enable-seek" ${config.enableSeek ? 'checked' : ''}>
                    Enable Seek
                </label>
            </div>
            <div class="control-row">
                <span class="control-label">Speed:</span>
                <input type="number" class="speed-input" id="speed-control" min="0.5" max="4" step="0.5" value="${config.playbackSpeed}">
            </div>
            <div class="control-row">
                <button class="control-btn" id="apply-btn">Apply</button>
                <button class="control-btn" id="reset-btn">Reset</button>
            </div>
        `;
        document.body.appendChild(panel);

        // 事件监听
        $('#apply-btn').click(applySettings);
        $('#reset-btn').click(resetVideo);
    }

    // 应用设置
    function applySettings() {
        config.autoSkip = $('#auto-skip').is(':checked');
        config.enableSeek = $('#enable-seek').is(':checked');
        config.playbackSpeed = parseFloat($('#speed-control').val());

        GM_setValue('autoSkip', config.autoSkip);
        GM_setValue('enableSeek', config.enableSeek);
        GM_setValue('speed', config.playbackSpeed);

        if (window.currentPlayer) {
            setupPlayerHooks(window.currentPlayer);
        }
    }

    // 重置视频
    function resetVideo() {
        if (window.currentPlayer) {
            window.currentPlayer.currentTime = 0;
            window.currentPlayer.play();
        }
    }

    // 核心跳转逻辑(修改为播放时触发)
    function setupPlayerHooks(player) {
        // 1. 移除原有限制
        player.off('ended');
        player.off('timeupdate');

        // 2. 设置播放速度
        player.speed = config.playbackSpeed;

        // 3. 启用进度条
        if (config.enableSeek) {
            player.media.controls = true;
            player.media.removeAttribute('controlslist');
            $('.plyr__progress').css('display', 'block');
        }

        // 4. 播放时跳转逻辑(新增)
        player.on('play', () => {
            if (config.autoSkip) {
                setTimeout(() => {
                    if (player.duration > 0) {
                        player.currentTime = player.duration - 1;
                        log('Triggered auto-skip at play event');
                    } else {
                        player.on('loadedmetadata', () => {
                            player.currentTime = player.duration - 1;
                        });
                    }
                }, config.skipDelay);
            }
        });

        log('Player hooks initialized');
    }

    // 检测播放器
    function detectPlayer() {
        const video = document.querySelector('video');
        if (video) {
            const checkInterval = setInterval(() => {
                if (video.plyr) {
                    clearInterval(checkInterval);
                    window.currentPlayer = video.plyr;
                    setupPlayerHooks(video.plyr);
                }
            }, 500);
        }
    }

    // 初始化
    function init() {
        createControlPanel();
        detectPlayer();

        // 监听动态加载
        new MutationObserver(detectPlayer).observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    // 启动
    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
    }

    // 工具函数
    function log(message) {
        if (config.debugMode) console.log(`[PlyrCtrl] ${message}`);
    }
})();