哔哩哔哩自动画质

自动解锁并更改哔哩哔哩视频的画质和音质,实现自动选择最高画质、无损音频及杜比全景声。

目前为 2024-06-30 提交的版本。查看 最新版本

// ==UserScript==
// @name         哔哩哔哩自动画质
// @namespace    https://github.com/AHCorn/Bilibili-Auto-Quality/
// @version      2.6.1
// @license      GPL-3.0
// @description  自动解锁并更改哔哩哔哩视频的画质和音质,实现自动选择最高画质、无损音频及杜比全景声。
// @author       安和(AHCorn)
// @icon         https://www.bilibili.com/favicon.ico
// @match        *://www.bilibili.com/video/*
// @match        *://www.bilibili.com/list/*
// @match        *://www.bilibili.com/blackboard/*
// @match        *://www.bilibili.com/watchlater/*
// @match        *://www.bilibili.com/bangumi/*
// @match        *://www.bilibili.com/watchroom/*
// @match        *://www.bilibili.com/medialist/*
// @match        *://bangumi.bilibili.com/*
// @match        *://live.bilibili.com/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function () {
    'use strict';

    Object.defineProperty(navigator, 'userAgent', {
        value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15"
    });

    window.localStorage['bilibili_player_force_DolbyAtmos&8K&HDR'] = 1;

    GM_addStyle(`
        #bilibili-quality-selector {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #f8f8f8;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
            display: none;
            z-index: 10000;
            width: 300px;
            text-align: center;
            border: 1px solid #ddd;
        }
        #bilibili-quality-selector button {
            display: block;
            width: 90%;
            margin: 5px auto;
            padding: 10px;
            border: 1px solid #007bff;
            border-radius: 5px;
            background-color: white;
            color: #007bff;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.3s ease;
        }
        #bilibili-quality-selector button.active {
            background-color: #007bff;
            color: white;
        }
        #bilibili-quality-selector button:hover {
            background-color: #0056b3;
            color: white;
        }
        #bilibili-quality-selector button.active:hover {
            background-color: #003f7f;
        }
    `);

    let hiResAudioEnabled = GM_getValue('hiResAudio', false);
    let dolbyAtmosEnabled = GM_getValue('dolbyAtmos', false);
    let userQualitySetting = GM_getValue('qualitySetting', ' 自动选择最高画质 ');
    let userHasChangedQuality = false;
    let takeOverQualityControl = GM_getValue('takeOverQualityControl', false);

    function isVipUser() {
        const vipElement = document.querySelector('.bili-avatar-icon.bili-avatar-right-icon.bili-avatar-icon-big-vip');
        const currentQuality = document.querySelector('.bpx-player-ctrl-quality-menu-item.bpx-state-active .bpx-player-ctrl-quality-text');
        return vipElement !== null || (currentQuality && currentQuality.textContent.includes('大会员'));
    }

    function selectQualityBasedOnSetting() {
        if (userHasChangedQuality) return;

        const isVip = isVipUser();
        console.log(`用户是否为大会员:${isVip ? '是' : '否'}`);
        let currentQuality = document.querySelector('.bpx-player-ctrl-quality-menu-item.bpx-state-active .bpx-player-ctrl-quality-text').textContent;
        console.log(`当前画质:${currentQuality}`);
        console.log(`目标画质:${userQualitySetting}`);

        const qualityItems = document.querySelectorAll('.bpx-player-ctrl-quality-menu .bpx-player-ctrl-quality-menu-item');
        const availableQualities = Array.from(qualityItems)
            .map(item => ({
                name: item.textContent.trim(),
                element: item,
                isVipOnly: !!item.querySelector('.bpx-player-ctrl-quality-badge-bigvip')
            }))
            .filter(quality => isVip || !quality.isVipOnly);

        console.log(`当前视频可用画质:`, availableQualities.map(q => q.name));

        const qualityPreferences = ['8K', '杜比视界', 'HDR', '4K', '1080P 高码率', '1080P 60 帧', '1080P', '720P 60 帧', '720P', '480P', '360P'];

        availableQualities.sort((a, b) => {
            const getQualityIndex = (name) => {
                for (let i = 0; i < qualityPreferences.length; i++) {
                    if (name.includes(qualityPreferences[i])) {
                        return i;
                    }
                }
                return qualityPreferences.length;
            };
            return getQualityIndex(a.name) - getQualityIndex(b.name);
        });

        let targetQuality;
        if (userQualitySetting === ' 自动选择最高画质 ') {
            targetQuality = availableQualities[0];
        } else {
            targetQuality = availableQualities.find(quality => quality.name.includes(userQualitySetting));
            if (!targetQuality) {
                console.log(`未找到目标画质 ${userQualitySetting},将选择最高可用画质`);
                targetQuality = availableQualities[0];
            }
        }

        console.log(`实际目标画质:${targetQuality.name}`);
        targetQuality.element.click();

        setTimeout(() => {
            currentQuality = document.querySelector('.bpx-player-ctrl-quality-menu-item.bpx-state-active .bpx-player-ctrl-quality-text').textContent;

            const getCurrentQualityIndex = (name) => {
                for (let i = 0; i < qualityPreferences.length; i++) {
                    if (name.includes(qualityPreferences[i])) {
                        return i;
                    }
                }
                return qualityPreferences.length;
            };

            const currentQualityIndex = getCurrentQualityIndex(currentQuality);
            const targetQualityIndex = getCurrentQualityIndex(targetQuality.name);

            console.log(`二次切换检查 - 当前画质索引:${currentQualityIndex}, 目标画质索引:${targetQualityIndex}`); // 索引画质,延后10秒比对,不相符就再切换一次
            if (currentQualityIndex === targetQualityIndex) {
                console.log("当前画质和目标画质相符,无需执行二次切换");
            } else {
                console.log("当前画质和目标画质不相符,执行二次切换");
                targetQuality.element.click();
            }
        }, 7000);

            const hiResButton = document.querySelector('.bpx-player-ctrl-flac');
            if (hiResButton) {
                if (isVip) {
                    if (hiResAudioEnabled && !hiResButton.classList.contains('bpx-state-active')) {
                        hiResButton.click();
                    } else if (!hiResAudioEnabled && hiResButton.classList.contains('bpx-state-active')) {
                        hiResButton.click();
                    }
                } else {
                    if (hiResButton.classList.contains('bpx-state-active')) {
                        hiResButton.click();
                    }
                }
            }

            const dolbyButton = document.querySelector('.bpx-player-ctrl-dolby');
            if (dolbyButton) {
                if (isVip) {
                    if (dolbyAtmosEnabled && !dolbyButton.classList.contains('bpx-state-active')) {
                        dolbyButton.click();
                    } else if (!dolbyAtmosEnabled && dolbyButton.classList.contains('bpx-state-active')) {
                        dolbyButton.click();
                    }
                } else {
                    if (dolbyButton.classList.contains('bpx-state-active')) {
                        dolbyButton.click();
                    }
                }
            }

            if (takeOverQualityControl) {
                const qualityControlElement = document.querySelector('.bpx-player-ctrl-btn.bpx-player-ctrl-quality');
                if (qualityControlElement) {
                    qualityControlElement.remove();
                }
            }
        }

        function createSettingsPanel() {
            const panel = document.createElement('div');
            panel.id = 'bilibili-quality-selector';

            const QUALITIES = [' 自动选择最高画质 ', '8K', '杜比视界','HDR', '4K', '1080P 高码率', '1080P 60 帧', '1080P', '720P', '480P', '360P']; // 本次更新:移除 720P 60帧选项,该画质似乎已被B站移除
            QUALITIES.forEach(quality => {
                const button = document.createElement('button');
                button.textContent = quality;
                button.onclick = () => {
                    userQualitySetting = quality;
                    GM_setValue('qualitySetting', quality);
                    userHasChangedQuality = true;
                    updateQualityButtons(panel);
                    selectQualityBasedOnSetting();
                };
                panel.appendChild(button);
            });

            const hiResButton = document.createElement('button');
            hiResButton.textContent = 'Hi-Res 音质';
            hiResButton.onclick = () => {
                hiResAudioEnabled = !hiResAudioEnabled;
                GM_setValue('hiResAudio', hiResAudioEnabled);
                updateQualityButtons(panel);
                selectQualityBasedOnSetting();
            };
            panel.appendChild(hiResButton);

            const dolbyAtmosButton = document.createElement('button');
            dolbyAtmosButton.textContent = '杜比全景声';
            dolbyAtmosButton.onclick = () => {
                dolbyAtmosEnabled = !dolbyAtmosEnabled;
                GM_setValue('dolbyAtmos', dolbyAtmosEnabled);
                updateQualityButtons(panel);
                selectQualityBasedOnSetting();
            };
            panel.appendChild(dolbyAtmosButton);

            const takeOverQualityControlButton = document.createElement('button');
            takeOverQualityControlButton.textContent = '移除清晰度按钮(Beta)';
            takeOverQualityControlButton.onclick = () => {
                takeOverQualityControl = !takeOverQualityControl;
                GM_setValue('takeOverQualityControl', takeOverQualityControl);
                updateQualityButtons(panel);
                selectQualityBasedOnSetting();
            };
            panel.appendChild(takeOverQualityControlButton);

            updateQualityButtons(panel);
            document.body.appendChild(panel);
        }

        function updateQualityButtons(panel) {
            panel.querySelectorAll('button').forEach(button => {
                button.classList.remove('active');
                if (button.textContent === userQualitySetting ||
                    (button.textContent === 'Hi-Res 音质' && hiResAudioEnabled) ||
                    (button.textContent === '杜比全景声' && dolbyAtmosEnabled) ||
                    (button.textContent === '移除清晰度按钮(Beta)' && takeOverQualityControl)) {
                    button.classList.add('active');
                }
            });
        }

        function toggleSettingsPanel() {
            let panel = document.getElementById('bilibili-quality-selector');
            if (!panel) {
                createSettingsPanel();
                panel = document.getElementById('bilibili-quality-selector');
            }
            panel.style.display = panel.style.display === 'block' ? 'none' : 'block';
        }

        document.addEventListener('mousedown', function (event) {
            const panel = document.getElementById('bilibili-quality-selector');
            if (panel && !panel.contains(event.target)) {
                panel.style.display = 'none';
            }
        });

        GM_registerMenuCommand("设置画质和音质", toggleSettingsPanel);

    window.onload = function () {
        let hasElementAppeared = false;
        const observer = new MutationObserver(function (mutations, me) {
            const element = document.querySelector('.v-popover-wrap.header-avatar-wrap');
            if (element) {
                hasElementAppeared = true;
                setTimeout(selectQualityBasedOnSetting, 4000);
                console.log(`脚本开始运行,4秒后切换画质`);
                me.disconnect();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

        setTimeout(function() {
            observer.disconnect();
            if (!hasElementAppeared) {
                console.error("等待超时,尝试执行中...");
                selectQualityBasedOnSetting();
            }
        }, 12000);
    };


        const parentElement = document.body;

        parentElement.addEventListener('click', function(event) {
            const targetElement = event.target;

            if (targetElement.tagName === 'DIV' || targetElement.tagName === 'P') {
                if (targetElement.hasAttribute('title') || targetElement.classList.contains('title')) {
                    setTimeout(selectQualityBasedOnSetting, 6000);
                    console.log('页面发生切换:', targetElement.textContent.trim());
                }
            }
        });

    })();

QingJ © 2025

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