Speed Adjustment

Video Speed Adjustment

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Speed Adjustment
// @namespace    http://tampermonkey.net/
// @version      2025-02-27 V1.0.1
// @description  Video Speed Adjustment
// @author       SMK
// @include      *
// @license     MIT
// @icon         https://bkimg.cdn.bcebos.com/pic/d043ad4bd11373f0b4cbf3e2ab0f4bfbfaed04d2?x-bce-process=image/format,f_auto/quality,Q_70/resize,m_lfit,limit_1,w_536
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 等待页面加载完成
    window.addEventListener('load', function() {
        const targetSelector = '#ad-pic,.ad-pic,#ad-overlay';

        // 隐藏广告元素
        function hideElement() {
            const element = document.querySelector(targetSelector);
            if (element) {
                element.style.display = 'none';
            }
        }

        // 监听页面变化,确保广告及时移除
        const observer = new MutationObserver(hideElement);
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

        // 初始执行一次
        hideElement();

        // 保存位置到 localStorage
        function savePosition(position) {
            localStorage.setItem('speedControlPosition', JSON.stringify(position));
        }

        // 获取保存的位置,默认为右上角
        function getSavedPosition() {
            const savedPosition = localStorage.getItem('speedControlPosition');
            return savedPosition ? JSON.parse(savedPosition) : { top: '30px', right: '5px' };
        }

        // 选择页面上的所有视频元素
        function addSpeedControlsToVideos() {
            var videos = document.querySelectorAll('video');
            videos.forEach(function(video) {
                if (!video.hasAttribute('data-speed-controls')) { // 防止重复添加
                    var speedContainer = document.createElement('div');
                    speedContainer.style.position = 'absolute';
                    const position = getSavedPosition();
                    speedContainer.style.top = position.top;
                    speedContainer.style.right = position.right;
                    speedContainer.style.zIndex = '1000';
                    speedContainer.style.backgroundColor = 'rgba(0,0,0,0.5)';
                    speedContainer.style.color = 'white';
                    speedContainer.style.padding = '3px';
                    speedContainer.style.borderRadius = '5px';
                    speedContainer.style.display = 'flex';
                    speedContainer.style.flexWrap = 'wrap'; // 使按钮换行
                    speedContainer.style.alignItems = 'center'; // 垂直居中
                    speedContainer.style.overflow = 'hidden'; // 确保容器不会超出范围
                    speedContainer.style.width = '45px'; // 设置容器宽度,以便让按钮能够换行
                    speedContainer.style.transition = 'width 0.3s ease'; // 宽度动画过渡效果
                    speedContainer.style.whiteSpace = 'nowrap'; // 防止按钮换行

                    // 通用按钮样式
                    const buttonStyle = {
                        backgroundColor: 'rgba(0, 0, 0, 0.7)',
                        color: 'white',
                        border: 'none',
                        padding: '3px 6px',
                        borderRadius: '5px',
                        cursor: 'pointer',
                        fontSize: '14px',
                        margin: '3px',
                        fontFamily: 'Arial, sans-serif', // 统一字体
                    };

                    // 创建当前倍速按钮
                    var currentSpeedButton = document.createElement('button');
                    currentSpeedButton.innerText = `${video.playbackRate}x`;
                    Object.assign(currentSpeedButton.style, buttonStyle);

                    // 点击当前倍速按钮时,切换到其他倍速
                    currentSpeedButton.addEventListener('click', function() {
                        const speeds = [0.5, 1.0, 2.0, 2.5, 3.0, 5.0];
                        let currentIndex = speeds.indexOf(video.playbackRate);
                        if (currentIndex === -1) currentIndex = 1; // 默认到1倍速

                        // 循环倍速
                        const nextSpeed = speeds[(currentIndex + 1) % speeds.length];
                        video.playbackRate = nextSpeed;
                        currentSpeedButton.innerText = `${nextSpeed}x`; // 更新按钮显示的倍速
                    });
                    // 添加当前倍速按钮到容器
                    speedContainer.appendChild(currentSpeedButton);

                    // 播放速度选项按钮
                    const speeds = [0.5, 1.0, 2.0, 2.5, 3.0, 5.0];
                    speeds.forEach(function(speed) {
                        var speedButton = document.createElement('button');
                        speedButton.innerText = `${speed}x`;
                        Object.assign(speedButton.style, buttonStyle); // 使用统一的样式

                        // 点击按钮时改变播放速度
                        speedButton.addEventListener('click', function() {
                            const wasPaused = video.paused; // 记录视频是否暂停
                            const wasPlaying = !wasPaused;

                            // 设置播放速度
                            video.playbackRate = speed;
                            currentSpeedButton.innerText = `${speed}x`; // 更新当前倍速按钮显示的倍速

                            // 通过 requestAnimationFrame 确保播放不会中断
                            requestAnimationFrame(() => {
                                if (wasPlaying) {
                                    video.play();
                                }
                            });
                        });

                        // 初始时隐藏其他按钮
                        speedButton.style.display = 'none'; // 关键修改:初始时隐藏
                        speedContainer.appendChild(speedButton); // 将按钮添加到容器中
                    });

                    // 鼠标悬停时展开按钮,鼠标移开时收缩
                    speedContainer.addEventListener('mouseenter', function() {
                        const buttons = speedContainer.querySelectorAll('button');
                        buttons.forEach(button => button.style.display = 'block'); // 显示所有按钮
                        speedContainer.style.width = '270px'; // 扩展容器宽度,显示更多按钮
                    });

                    speedContainer.addEventListener('mouseleave', function() {
                        const buttons = speedContainer.querySelectorAll('button');
                        buttons.forEach((button, index) => {
                            if (index !== 0) button.style.display = 'none'; // 只保留第一个按钮(当前倍速)
                        });
                        speedContainer.style.width = '45px'; // 恢复容器宽度
                    });
                     /**
                    // 创建悬浮窗)

                    **/

                    const floatingWindow = document.createElement('div');
                    floatingWindow.style.position = 'absolute';
                    floatingWindow.style.top = '150px';
                    floatingWindow.style.right = '-10px';
                    floatingWindow.style.zIndex = '1000';
                    floatingWindow.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
                    floatingWindow.style.padding = '15px';
                    floatingWindow.style.borderRadius = '15px';
                    floatingWindow.style.transition = 'opacity 0.3s ease';
                    floatingWindow.style.opacity = '0.3';



                    // 鼠标悬停显示按钮
                    floatingWindow.addEventListener('mouseenter', function() {
                        floatingWindow.style.opacity = '1';
                        positionButtons.forEach(button => button.style.display = 'block');
                    });

                    // 鼠标移出隐藏按钮
                    floatingWindow.addEventListener('mouseleave', function() {
                        floatingWindow.style.opacity = '0.3';
                        positionButtons.forEach(button => button.style.display = 'none');
                    });

                    const positions = [
                        { label: '左上', top: '10px', left: '10px' },
                        { label: '右上', top: '10px', right: '10px' },
                        { label: '左下', bottom: '10px', left: '10px' },
                        { label: '右下', bottom: '10px', right: '10px' }
                    ];

                    const positionButtons = [];
                    positions.forEach(position => {
                        const positionButton = document.createElement('button');
                        positionButton.innerText = position.label;
                        Object.assign(positionButton.style, buttonStyle);
                        positionButton.style.display = 'none';
                        positionButton.style.marginBottom = '5px';

                        positionButton.addEventListener('click', function() {
                            speedContainer.style.top = position.top || '';
                            speedContainer.style.right = position.right || '';
                            speedContainer.style.bottom = position.bottom || '';
                            speedContainer.style.left = position.left || '';
                            savePosition(position);
                        });

                        floatingWindow.appendChild(positionButton);
                        positionButtons.push(positionButton);
                    });



                    // 将按钮容器插入到视频元素之前
                    video.parentNode.insertBefore(speedContainer, video);
                    video.parentNode.insertBefore(floatingWindow, video);
                    video.setAttribute('data-speed-controls', 'true'); // 防止重复添加
                }
            });
        }

        // 创建 MutationObserver 监听 video 元素的变化
        const videoObserver = new MutationObserver(addSpeedControlsToVideos);
        videoObserver.observe(document.body, {
            childList: true,
            subtree: true
        });

        // 初始执行一次
        addSpeedControlsToVideos();
    });
})();