Video Control with Reload

为指定视频添加可移动的进度条、音量控制器和重新加载按钮

当前为 2024-06-29 提交的版本,查看 最新版本

// ==UserScript==
// @name         Video Control with Reload
// @namespace    http://tampermonkey.net/
// @version      0.6
// @description  为指定视频添加可移动的进度条、音量控制器和重新加载按钮
// @match        https://app.kosmi.io/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    let videoElement = null;
    let isCompacted = false; // 控制器是否缩小为一个小方块

    // 创建控制器
    // 创建控制器
function createController() {
    const controller = document.createElement('div');
    controller.id = 'video-controller';
    controller.style.cssText = `
        position: fixed;
        bottom: 20px;
        left: 50%;
        transform: translateX(-50%);
        background-color: rgba(0, 0, 0, 0.7);
        color: white;
        padding: 10px;
        border-radius: 5px;
        z-index: 9999;
        cursor: move;
        user-select: none;
        width: 300px;
        transition: width 0.3s, height 0.3s;
    `;
    controller.innerHTML = `
        <div id="progress-container" style="width: 100%; height: 10px; background-color: #444; position: relative; cursor: pointer;">
            <div id="progress-indicator" style="width: 0%; height: 100%; background-color: #fff; position: absolute;"></div>
        </div>
        <div id="time-display" style="text-align: center; margin-top: 5px;">0:00 / 0:00</div>
        <div id="volume-container" style="display: flex; align-items: center; margin-top: 10px;">
            <span id="volume-icon" style="margin-right: 10px;">🔊</span>
            <input type="range" id="volume-slider" min="0" max="1" step="0.1" value="1" style="flex-grow: 1;">
        </div>
        <button id="reload-button" style="width: 100%; margin-top: 10px; padding: 5px; background-color: #4CAF50; border: none; color: white; cursor: pointer;">重新加载视频控制</button>
        <button id="compact-button" style="width: 100%; margin-top: 10px; padding: 5px; background-color: #2196F3; border: none; color: white; cursor: pointer;">缩小控制器</button>
    `;
    document.body.appendChild(controller);
    return controller;
}

    // 使控制器可拖动
    function makeDraggable(element) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        element.onmousedown = dragMouseDown;

        function dragMouseDown(e) {
            if (e.target.id === 'progress-container' || e.target.id === 'progress-indicator' || e.target.id === 'volume-slider' || e.target.id === 'reload-button') return;
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            element.style.top = (element.offsetTop - pos2) + "px";
            element.style.left = (element.offsetLeft - pos1) + "px";
            element.style.bottom = 'auto';
            element.style.transform = 'none';
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    }

    // 格式化时间
    function formatTime(seconds) {
        const minutes = Math.floor(seconds / 60);
        seconds = Math.floor(seconds % 60);
        return `${minutes}:${seconds.toString().padStart(2, '0')}`;
    }

    // 主函数
    function main() {
        // 先移除已存在的控制器元素
        const existingController = document.getElementById('video-controller');
        if (existingController) {
            existingController.remove();
        }

        videoElement = document.querySelector('video[src^="blob:https://app.kosmi.io/"]');
        if (!videoElement) {
            console.log('未找到指定视频');
            return;
        }

        const controller = createController();
        makeDraggable(controller);

        const progressContainer = document.getElementById('progress-container');
        const progressIndicator = document.getElementById('progress-indicator');
        const timeDisplay = document.getElementById('time-display');
        const volumeSlider = document.getElementById('volume-slider');
        const volumeIcon = document.getElementById('volume-icon');
        const reloadButton = document.getElementById('reload-button');

        // 更新进度
        function updateProgress() {
            const progress = (videoElement.currentTime / videoElement.duration) * 100;
            progressIndicator.style.width = `${progress}%`;
            const current = formatTime(videoElement.currentTime);
            const total = formatTime(videoElement.duration);
            timeDisplay.textContent = `${current} / ${total}`;
        }

        // 点击进度条更新视频位置
        progressContainer.addEventListener('click', function(e) {
            const rect = progressContainer.getBoundingClientRect();
            const pos = (e.clientX - rect.left) / rect.width;
            videoElement.currentTime = pos * videoElement.duration;
        });

        // 更新音量
        volumeSlider.addEventListener('input', function() {
            videoElement.volume = this.value;
            updateVolumeIcon(this.value);
        });

        // 更新音量图标
        function updateVolumeIcon(volume) {
            if (volume > 0.5) {
                volumeIcon.textContent = '🔊';
            } else if (volume > 0) {
                volumeIcon.textContent = '🔉';
            } else {
                volumeIcon.textContent = '🔇';
            }
        }

        // 初始化音量
        volumeSlider.value = videoElement.volume;
        updateVolumeIcon(videoElement.volume);

        // 重新加载按钮事件
        reloadButton.addEventListener('click', function() {
            // 移除旧的事件监听器
            videoElement.removeEventListener('timeupdate', updateProgress);
            videoElement.removeEventListener('loadedmetadata', updateProgress);

            // 重新执行主函数
            main();

            // 重新绑定事件监听器
            videoElement.addEventListener('timeupdate', updateProgress);
            videoElement.addEventListener('loadedmetadata', updateProgress);
        });

        videoElement.addEventListener('timeupdate', updateProgress);
        videoElement.addEventListener('loadedmetadata', updateProgress);
            const compactButton = document.getElementById('compact-button');

    // 缩小/展开控制器
    compactButton.addEventListener('click', function() {
        isCompacted = !isCompacted;
        if (isCompacted) {
            controller.style.width = '50px';
            controller.style.height = '50px';
            controller.style.overflow = 'hidden';
            compactButton.textContent = '展开控制器';
        } else {
            controller.style.width = '300px';
            controller.style.height = 'auto';
            controller.style.overflow = 'visible';
            compactButton.textContent = '缩小控制器';
        }
    });
    }

    // 等待视频加载完成
    function waitForVideo() {
        const video = document.querySelector('video[src^="blob:https://app.kosmi.io/"]');
        if (video) {
            main();
        } else {
            setTimeout(waitForVideo, 1000);
        }
    }

    waitForVideo();
})();