// ==UserScript== // @name 哔哩哔哩自动画质 // @namespace https://github.com/AHCorn/Bilibili-Auto-Quality/ // @version 3.0.3 // @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 // @downloadURL none // ==/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.5 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: linear-gradient(135deg, #f6f8fa, #e9ecef); border-radius: 24px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1), 0 1px 8px rgba(0, 0, 0, 0.06); padding: 30px; width: 90%; max-width: 400px; display: none; z-index: 10000; font-family: 'Segoe UI', 'Roboto', sans-serif; transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); } #bilibili-quality-selector h2 { margin: 0 0 20px; color: #00a1d6; font-size: 28px; text-align: center; font-weight: 700; } #bilibili-quality-selector p { margin: 0 0 25px; color: #5f6368; font-size: 14px; text-align: center; } .quality-group { display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 12px; margin-bottom: 25px; } .quality-button { background-color: #ffffff; border: 2px solid #dadce0; border-radius: 12px; padding: 12px 8px; font-size: 14px; color: #3c4043; cursor: pointer; transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); font-weight: 600; } .quality-button:hover { background-color: #f1f3f4; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .quality-button.active { background-color: #00a1d6; color: white; border-color: #00a1d6; box-shadow: 0 6px 12px rgba(0, 161, 214, 0.3); } .quality-button.active.vip-quality { background-color: #f25d8e; color: white; border-color: #f25d8e; box-shadow: 0 6px 12px rgba(242, 93, 142, 0.3); } .quality-button.unavailable { opacity: 0.5; cursor: not-allowed; } .toggle-switch { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; padding: 10px 15px; background-color: #f1f3f4; border-radius: 12px; transition: all 0.3s ease; } .toggle-switch:hover { background-color: #e8eaed; } .toggle-switch label { font-size: 16px; color: #3c4043; font-weight: 600; } .switch { position: relative; display: inline-block; width: 52px; height: 28px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 34px; } .slider:before { position: absolute; content: ""; height: 20px; width: 20px; left: 4px; bottom: 4px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .slider { background-color: #00a1d6; } input:checked + .slider.vip-audio { background-color: #f25d8e; } input:checked + .slider:before { transform: translateX(24px); } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes slideIn { from { transform: translate(-50%, -60%); } to { transform: translate(-50%, -50%); } } #bilibili-quality-selector.show { display: block; animation: fadeIn 0.3s ease-out, slideIn 0.3s ease-out; } @media (max-width: 480px) { #bilibili-quality-selector { width: 95%; padding: 25px; } .quality-group { grid-template-columns: repeat(2, 1fr); } } .status-bar { padding: 10px; border-radius: 8px; margin-bottom: 15px; text-align: center; font-weight: bold; transition: all 0.5s ease; } .status-bar.non-vip { background-color: #f0f0f0; color: #666666; } .status-bar.vip { background-color: #fff1f5; color: #f25d8e; } .warning { background-color: #fce8e6; color: #d93025; padding: 10px; border-radius: 8px; margin-top: 12px; margin-bottom: 12px; text-align: center; font-weight: bold; transition: all 0.3s ease; } .warning::before { content: ""; margin-right: 10px; } `); 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); let isVipUser = false; let vipStatusChecked = false; let isLoading = true; function checkVipStatus() { 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'); isVipUser = vipElement !== null || (currentQuality && currentQuality.textContent.includes('大会员')); vipStatusChecked = true; console.log(`用户是否为大会员: ${isVipUser ? '是' : '否'}`); updateQualityButtons(document.getElementById('bilibili-quality-selector')); } function selectQualityBasedOnSetting() { if (!vipStatusChecked) { checkVipStatus(); } 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') })); 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 === '最高画质') { if (isVipUser) { targetQuality = availableQualities.find(quality => quality.isVipOnly) || availableQualities[0]; } else { targetQuality = availableQualities.find(quality => !quality.isVipOnly); } } else if (userQualitySetting === '默认') { console.log('使用默认画质'); return; } else { targetQuality = availableQualities.find(quality => quality.name.includes(userQualitySetting)); if (!targetQuality) { console.log(`未找到目标画质 ${userQualitySetting}, 将选择最高可用画质`); targetQuality = isVipUser ? (availableQualities.find(quality => quality.isVipOnly) || availableQualities[0]) : availableQualities.find(quality => !quality.isVipOnly); } } console.log(`实际目标画质: ${targetQuality.name}`); targetQuality.element.click(); const hiResButton = document.querySelector('.bpx-player-ctrl-flac'); if (hiResButton) { if (isVipUser) { 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 (isVipUser) { 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.style.display = 'none'; } } else { const qualityControlElement = document.querySelector('.bpx-player-ctrl-btn.bpx-player-ctrl-quality'); if (qualityControlElement) { qualityControlElement.style.display = ''; } } updateWarnings(); } function createSettingsPanel() { const panel = document.createElement('div'); panel.id = 'bilibili-quality-selector'; const QUALITIES = ['最高画质', '8K', '杜比视界', 'HDR', '4K', '1080P 高码率', '1080P 60 帧', '1080P 高清', '720P', '480P', '360P', '默认']; panel.innerHTML = `

画质设置

${QUALITIES.map(quality => `` ).join('')}
`; panel.querySelectorAll('.quality-button').forEach(button => { button.addEventListener('click', () => { if (!isLoading) { userQualitySetting = button.dataset.quality; GM_setValue('qualitySetting', userQualitySetting); userHasChangedQuality = true; updateQualityButtons(panel); selectQualityBasedOnSetting(); } }); }); panel.querySelector('#hi-res-audio').addEventListener('change', (e) => { if (!isLoading) { hiResAudioEnabled = e.target.checked; GM_setValue('hiResAudio', hiResAudioEnabled); updateQualityButtons(panel); selectQualityBasedOnSetting(); } }); panel.querySelector('#dolby-atmos').addEventListener('change', (e) => { if (!isLoading) { dolbyAtmosEnabled = e.target.checked; GM_setValue('dolbyAtmos', dolbyAtmosEnabled); updateQualityButtons(panel); selectQualityBasedOnSetting(); } }); panel.querySelector('#remove-quality-button').addEventListener('change', (e) => { if (!isLoading) { takeOverQualityControl = e.target.checked; GM_setValue('takeOverQualityControl', takeOverQualityControl); selectQualityBasedOnSetting(); const warningElement = panel.querySelector('#quality-warning'); if (takeOverQualityControl) { warningElement.textContent = '若启用该选项,画质设置将由本脚本接管。'; warningElement.style.display = 'block'; } else { warningElement.style.display = 'none'; } } }); document.body.appendChild(panel); updateQualityButtons(panel); } function updateQualityButtons(panel) { if (!panel) return; const statusBar = panel.querySelector('.status-bar'); if (isLoading) { statusBar.textContent = '加载中,请稍候...'; statusBar.className = 'status-bar'; panel.querySelectorAll('.quality-button, .toggle-switch').forEach(el => el.style.opacity = '0.5'); } else { panel.querySelectorAll('.quality-button, .toggle-switch').forEach(el => el.style.opacity = '1'); if (vipStatusChecked) { statusBar.textContent = isVipUser ? '您是大会员用户,可正常使用所有选项。' : '您不是大会员用户,部分会员选项不可用。'; statusBar.className = `status-bar ${isVipUser ? 'vip' : 'non-vip'}`; } } panel.querySelectorAll('.quality-button').forEach(button => { button.classList.remove('active', 'vip-quality'); if (button.dataset.quality === userQualitySetting) { button.classList.add('active'); if (['8K', '杜比视界', 'HDR', '4K', '1080P 高码率', '1080P 60 帧'].includes(userQualitySetting)) { button.classList.add('vip-quality'); } } }); const hiResAudioSwitch = panel.querySelector('#hi-res-audio'); hiResAudioSwitch.checked = hiResAudioEnabled; const dolbyAtmosSwitch = panel.querySelector('#dolby-atmos'); dolbyAtmosSwitch.checked = dolbyAtmosEnabled; panel.querySelector('#remove-quality-button').checked = takeOverQualityControl; updateWarnings(panel); } function updateWarnings(panel) { if (!panel || isLoading || !vipStatusChecked) return; const nonVipWarning = panel.querySelector('#non-vip-warning'); const qualityWarning = panel.querySelector('#quality-warning'); const audioWarning = panel.querySelector('#audio-warning'); if (!isVipUser && ['8K', '杜比视界', 'HDR', '4K', '1080P 高码率', '1080P 60 帧'].includes(userQualitySetting)) { nonVipWarning.textContent = '无法使用此会员画质。已自动选择最高可用画质。'; nonVipWarning.style.display = 'block'; } else { nonVipWarning.style.display = 'none'; } if (takeOverQualityControl) { qualityWarning.textContent = '若启用该选项,画质设置将由本脚本接管。'; qualityWarning.style.display = 'block'; } else { qualityWarning.style.display = 'none'; } if (!isVipUser && (hiResAudioEnabled || dolbyAtmosEnabled)) { audioWarning.textContent = '非大会员用户不能使用高级音频选项。'; audioWarning.style.display = 'block'; } else { audioWarning.style.display = 'none'; } } function toggleSettingsPanel() { let panel = document.getElementById('bilibili-quality-selector'); if (!panel) { createSettingsPanel(); panel = document.getElementById('bilibili-quality-selector'); } panel.classList.toggle('show'); updateQualityButtons(panel); } document.addEventListener('mousedown', function (event) { const panel = document.getElementById('bilibili-quality-selector'); if (panel && !panel.contains(event.target) && panel.classList.contains('show')) { panel.classList.remove('show'); } }); GM_registerMenuCommand("设置画质和音质", toggleSettingsPanel); window.onload = function () { let hasElementAppeared = false; isLoading = true; const observer = new MutationObserver(function (mutations, me) { const element = document.querySelector('.v-popover-wrap.header-avatar-wrap'); if (element) { hasElementAppeared = true; console.log("正在判断用户是否为会员..."); setTimeout(() => { isLoading = false; checkVipStatus(); selectQualityBasedOnSetting(); updateQualityButtons(document.getElementById('bilibili-quality-selector')); }, 4000); console.log("脚本开始运行,4秒后切换画质"); me.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(function() { observer.disconnect(); if (!hasElementAppeared) { console.error("等待超时,尝试执行中..."); isLoading = false; checkVipStatus(); selectQualityBasedOnSetting(); updateQualityButtons(document.getElementById('bilibili-quality-selector')); } }, 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')) { isLoading = true; updateQualityButtons(document.getElementById('bilibili-quality-selector')); setTimeout(() => { isLoading = false; checkVipStatus(); selectQualityBasedOnSetting(); updateQualityButtons(document.getElementById('bilibili-quality-selector')); }, 5000); console.log('视频标题点击事件,页面发生切换:', targetElement.textContent.trim()); } } if (targetElement.classList.contains('b-img')) { isLoading = true; updateQualityButtons(document.getElementById('bilibili-quality-selector')); setTimeout(() => { isLoading = false; checkVipStatus(); selectQualityBasedOnSetting(); updateQualityButtons(document.getElementById('bilibili-quality-selector')); }, 5000); console.log('封面点击事件,页面发生切换'); } }); })();