YouTube 快速倍速與音量控制介面

在YouTube的中下部區域添加一個快速速度和音量界面,而不干擾現有控件。

// ==UserScript==
// @name         YouTube Quick Speed & Volume Interface
// @name:zh-TW   YouTube 快速倍速與音量控制介面
// @name:zh-CN   YouTube 快速倍速与音量控制界面
// @namespace    https://twitter.com/CobleeH
// @version      1.17
// @description  Add a quick speed and volume interface to YouTube's middle-bottom area without interfering with existing controls.
// @description:zh-TW  在YouTube的中下部區域添加一個快速速度和音量界面,而不干擾現有控件。
// @description:zh-CN  在YouTube的中下部区域添加一个快速速度和音量界面,而不干扰现有控件。
// @author       CobleeH
// @match        https://www.youtube.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const speeds = [0.5, 1, 1.5, 2, 3];
    const volumes = [0, 0.15, 0.35, 0.65, 1];

    // 創建整體容器
    function createControlContainer() {
        const container = document.createElement('div');
        container.classList.add('ytp-control-container');
        container.style.display = 'flex';
        container.style.flexDirection = 'column';
        container.style.alignItems = 'center';
        container.style.position = 'absolute';
        container.style.right = '15px';
        container.style.bottom = '62px';
        container.style.zIndex = '9999';
        container.style.background = 'rgba(0, 0, 0, 0.7)';
        container.style.borderRadius = '5px';
        container.style.padding = '3px 6px'; // 縮小內邊距
        container.style.color = '#fff';
        container.style.fontSize = '12px'; // 字體縮小
        container.style.lineHeight = '1.2';

        const volumeOptions = createVolumeOptions();
        const speedOptions = createSpeedOptions();

        container.appendChild(volumeOptions);
        container.appendChild(speedOptions);
        return container;
    }

    // 創建音量控件
    function createVolumeOptions() {
        const volumeContainer = document.createElement('div');
        volumeContainer.classList.add('ytp-volume-options');
        volumeContainer.style.display = 'flex';
        volumeContainer.style.alignItems = 'center';
        volumeContainer.style.marginBottom = '4px'; // 縮小上下間距

        const label = document.createElement('span');
        label.innerText = 'Vol';
        label.style.marginRight = '6px';
        volumeContainer.appendChild(label);

        volumes.forEach(volume => {
            const option = document.createElement('div');
            option.innerText = (volume * 100) + '%';
            option.style.cursor = 'pointer';
            option.style.margin = '0 3px'; // 縮小選項間距
            option.style.padding = '2px 4px'; // 縮小內邊距

            option.addEventListener('click', () => {
                const video = document.querySelector('video');
                if (video) {
                    video.volume = volume;
                    highlightOption(option, '.ytp-volume-options div');
                }
            });

            volumeContainer.appendChild(option);
        });

        return volumeContainer;
    }

    // 創建速度控件
    function createSpeedOptions() {
        const speedContainer = document.createElement('div');
        speedContainer.classList.add('ytp-speed-options');
        speedContainer.style.display = 'flex';
        speedContainer.style.alignItems = 'center';

        const label = document.createElement('span');
        label.innerText = 'Spd';
        label.style.marginRight = '6px';
        speedContainer.appendChild(label);

        speeds.forEach(speed => {
            const option = document.createElement('div');
            option.innerText = speed + 'x';
            option.style.cursor = 'pointer';
            option.style.margin = '0 3px'; // 縮小選項間距
            option.style.padding = '2px 4px'; // 縮小內邊距

            option.addEventListener('click', () => {
                const video = document.querySelector('video');
                if (video) {
                    video.playbackRate = speed;
                    highlightOption(option, '.ytp-speed-options div');
                }
            });

            speedContainer.appendChild(option);
        });

        return speedContainer;
    }

    // 高亮所選選項
    function highlightOption(selectedOption, selector) {
        const options = document.querySelectorAll(selector);
        options.forEach(option => {
            option.style.color = '#fff';
            option.style.fontWeight = 'normal';
        });
        selectedOption.style.color = '#ff0';
        selectedOption.style.fontWeight = 'bold';
    }

    // 插入控件到播放器
    function insertControls() {
        const chromeBottom = document.querySelector('.ytp-chrome-bottom');
        if (!chromeBottom || document.querySelector('.ytp-control-container')) return;

        const controlContainer = createControlContainer();
        chromeBottom.appendChild(controlContainer);

        setInitialHighlight();
    }

    // 初始化高亮選項
    function setInitialHighlight() {
        const video = document.querySelector('video');
        if (!video) return;

        const currentSpeed = video.playbackRate || 1;
        const speedOptions = document.querySelectorAll('.ytp-speed-options div');
        speedOptions.forEach(option => {
            if (option.innerText === currentSpeed + 'x') {
                highlightOption(option, '.ytp-speed-options div');
            }
        });

        const currentVolume = video.volume || 1;
        const volumeOptions = document.querySelectorAll('.ytp-volume-options div');
        volumeOptions.forEach(option => {
            if (option.innerText === (currentVolume * 100) + '%') {
                highlightOption(option, '.ytp-volume-options div');
            }
        });
    }

    const observer = new MutationObserver(() => {
        insertControls();
    });

    observer.observe(document.body, { childList: true, subtree: true });
    window.addEventListener('load', insertControls);
})();

QingJ © 2025

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