bilibili 倍速

按钮倍速

// ==UserScript==
// @name         bilibili 倍速
// @license MIT
// @version      0.5.0.0
// @description  按钮倍速
// @author       dfdy-yyc
// @match           https://www.bilibili.com/video/*
// @match           https://www.bilibili.com/list/*
// @match           https://www.bilibili.com/bangumi/play/*
// @match           https://www.bilibili.com/cheese/play/*
// @match           https://www.bilibili.com/festival/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant        none
// @namespace https://greasyfork.org/users/1276921
// ==/UserScript==

(function() {
    'use strict';

    // 配置项
    const config = {
        speeds: ['3.0', '4.0'],
        customItems: [
            {
                value: '设置',
                text: '设置',
                position: 'bottom' // 插入位置:top/bottom
            }
        ]
    };

    // 创建菜单项元素
    function createMenuItem(item) {
        const li = document.createElement('li');
        li.className = 'bpx-player-ctrl-playbackrate-menu-item';
        li.dataset.value = item.value;
        li.textContent = item.text;

        if (item.value === '设置') {
            li.addEventListener('click', (e) => {
                e.preventDefault();
                    const speed = prompt('请输入自定义倍速(最高16.0)');
                if (speed && parseFloat(speed) <= 16.0) {
                    document.querySelector('video').playbackRate = speed;
    }
            });
        }
        return li;
    }

    // 添加自定义菜单项
    function addCustomItems(menu) {
        // 添加倍速选项到顶部
        config.speeds.forEach(speed => {
            if (!menu.querySelector(`[data-value="${speed}"]`)) {
                const li = createMenuItem({
                    value: speed,
                    text: `${speed}x`
                });
                menu.insertBefore(li, menu.firstChild);
            }
        });

        // 添加自定义项到底部
        config.customItems.forEach(item => {
            if (!menu.querySelector(`[data-value="${item.value}"]`)) {
                const li = createMenuItem(item);
                if (item.position === 'bottom') {
                    menu.appendChild(li);
                } else {
                    menu.insertBefore(li, menu.firstChild);
                }
            }
        });
    }

    // 主处理函数
    function handlePlaybackRateMenu() {
        const rateMenu = document.querySelector('.bpx-player-ctrl-playbackrate-menu');
        if (rateMenu && !rateMenu.dataset.enhanced) {
            addCustomItems(rateMenu);
            rateMenu.dataset.enhanced = 'true'; // 标记已处理
            console.log('成功增强倍速菜单');
        }
    }

    // 使用MutationObserver监听DOM变化
    const observer = new MutationObserver(() => {
        handlePlaybackRateMenu();
    });

    // 初始化
    function init() {
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        handlePlaybackRateMenu(); // 立即尝试一次

        // 处理SPA页面切换
        window.addEventListener('popstate', () => {
            setTimeout(handlePlaybackRateMenu, 500);
        });
    }

    // 延迟初始化以确保播放器加载
    window.addEventListener('load', init, { once: true });
})();