视频加速器

网页中有视频时,右下角显示倍速操作界面,可隐藏为一个淡色圆形图标并显示倍速数字,显示操作界面时圆形图标隐藏。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         视频加速器
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  网页中有视频时,右下角显示倍速操作界面,可隐藏为一个淡色圆形图标并显示倍速数字,显示操作界面时圆形图标隐藏。
// @license     MIT
// @author      失辛向南
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    let speedControlContainer;
    let speedSelect;
    let isVisible = false;
    let iconContainer;

    function createSpeedControlUI() {
        speedControlContainer = document.createElement('div');
        speedControlContainer.style.position = 'fixed';
        speedControlContainer.style.bottom = '20px';
        speedControlContainer.style.right = '20px';
        speedControlContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
        speedControlContainer.style.padding = '10px';
        speedControlContainer.style.borderRadius = '5px';
        speedControlContainer.style.color = 'white';
        speedControlContainer.style.zIndex = '9999';
        speedControlContainer.style.display = 'none';

        const speedLabel = document.createElement('span');
        speedLabel.textContent = 'Speed: ';
        speedControlContainer.appendChild(speedLabel);

        speedSelect = document.createElement('select');
        for (let i = 0.25; i <= 5; i += 0.25) {
            const option = document.createElement('option');
            option.value = i;
            option.textContent = i + 'x';
            speedSelect.appendChild(option);
        }
        speedSelect.value = '1';
        speedControlContainer.appendChild(speedSelect);

        document.body.appendChild(speedControlContainer);

        speedSelect.addEventListener('change', updateVideoSpeeds);

        // 创建图标容器
        iconContainer = document.createElement('div');
        iconContainer.style.position = 'fixed';
        iconContainer.style.bottom = '20px';
        iconContainer.style.right = '20px';
        iconContainer.style.width = '30px';
        iconContainer.style.height = '30px';
        iconContainer.style.backgroundColor = 'rgba(200, 200, 200, 0.5)';
        iconContainer.style.borderRadius = '50%';
        iconContainer.style.textAlign = 'center';
        iconContainer.style.lineHeight = '30px';
        iconContainer.style.cursor = 'pointer';
        iconContainer.style.zIndex = '9999';
        document.body.appendChild(iconContainer);

        iconContainer.addEventListener('click', toggleVisibility);

        document.addEventListener('mousemove', handleMouseMove);
    }

    function updateVideoSpeeds() {
        const videos = document.getElementsByTagName('video');
        for (let video of videos) {
            video.playbackRate = parseFloat(speedSelect.value);
        }
        updateIconText();
    }

    function checkForVideos() {
        const videos = document.getElementsByTagName('video');
        if (videos.length > 0) {
            if (!speedControlContainer) {
                createSpeedControlUI();
            }
            updateVideoSpeeds();
        } else {
            if (speedControlContainer) {
                speedControlContainer.remove();
                speedControlContainer = null;
                speedSelect = null;
                iconContainer.remove();
                iconContainer = null;
            }
        }
    }

    function isVideoPage() {
        const videoElements = document.getElementsByTagName('video');
        const videoTagsInHTML = document.documentElement.innerHTML.includes('<video');
        return videoElements.length > 0 || videoTagsInHTML;
    }

    function handleMouseMove(event) {
        if (!isVisible && isInsideIcon(event.clientX, event.clientY)) {
            showContainer();
        } else if (isVisible &&!isInsideContainer(event.clientX, event.clientY)) {
            hideContainer();
        }
    }

    function isInsideIcon(x, y) {
        const iconRect = iconContainer.getBoundingClientRect();
        return x >= iconRect.left && x <= iconRect.right && y >= iconRect.top && y <= iconRect.bottom;
    }

    function isInsideContainer(x, y) {
        const containerRect = speedControlContainer.getBoundingClientRect();
        return x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
    }

    function showContainer() {
        speedControlContainer.style.display = 'block';
        iconContainer.style.display = 'none';
        isVisible = true;
    }

    function hideContainer() {
        speedControlContainer.style.display = 'none';
        iconContainer.style.display = 'block';
        isVisible = false;
    }

    function toggleVisibility() {
        if (isVisible) {
            hideContainer();
        } else {
            showContainer();
        }
    }

    function updateIconText() {
        iconContainer.textContent = speedSelect.value + 'x';
    }

    window.addEventListener('load', () => {
        if (isVideoPage()) {
            checkForVideos();
        }
    });
    window.addEventListener('DOMContentLoaded', () => {
        if (isVideoPage()) {
            checkForVideos();
        }
    });
})();