您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
解限B站播放器缓冲时长,将缓冲状态集成到播放器统计信息中。
// ==UserScript== // @name B站缓冲解限 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 解限B站播放器缓冲时长,将缓冲状态集成到播放器统计信息中。 // @author \7. with GPT-5 // @match *://*.bilibili.com/* // @match *://bilibili.com/* // @grant none // @run-at document-end // @license MIT // ==/UserScript== (function() { 'use strict'; // 配置:缓冲时间设置(秒),以及检查间隔(秒) const BUFFER_TIME = 300; const SETTING_RECHECK_INTERVAL = 10; // 设置检查间隔 const MONITOR_RECHECK_INTERVAL = 1; // 监控更新间隔 // 状态标记 let isRunning = false; let isMonitoring = false; // 日志函数 function log(message) { const timestamp = new Date().toLocaleTimeString(); console.log(`[B站缓冲解限] [${timestamp}] ${message}`); } // 获取播放器实例的核心函数 function getPlayer() { try { if (window.player && typeof window.player.__core === 'function') { const core = window.player.__core(); if (typeof core.setStableBufferTime === 'function') { return core; } } } catch (e) {} return null; } // 应用缓冲优化(此函数现在会定期被调用) function applyBufferOptimization(player) { if (isRunning) { return; } isRunning = true; if (!player) { isRunning = false; return; } try { const currentBuffer = player.getStableBufferTime(); if (currentBuffer < BUFFER_TIME) { player.setStableBufferTime(BUFFER_TIME); log(`✅ 缓冲设置已更新: ${currentBuffer}s → ${BUFFER_TIME}s`); } else { // log(`✅ 缓冲时间已是目标值: ${currentBuffer}s`); } } catch (e) { log(`❌ 应用优化失败: ${e.message}`); } finally { isRunning = false; } } // 监听统计面板的显示/隐藏,并注入信息 function monitorStatsPanelVisibility(player) { if (isMonitoring) return; isMonitoring = true; const containerSelector = '#bilibili-player .bpx-player-info-container'; try { if (window.__biliBufferInfoVisibilityPoll) clearInterval(window.__biliBufferInfoVisibilityPoll); } catch (e) {} window.__biliBufferInfoVisibilityPoll = setInterval(() => { try { const container = document.querySelector(containerSelector); if (!container) return; const panelLikelyVisible = !!container.querySelector('.info-line .info-title'); const overlay = container.querySelector('.bilibili-buffer-info-overlay'); if (panelLikelyVisible) { if (!overlay) { injectBufferInfo(container, player); } else if (overlay.style.display === 'none') { overlay.style.display = 'block'; } } else if (overlay) { overlay.style.display = 'none'; } } catch (e) {} }, MONITOR_RECHECK_INTERVAL * 1000); } // 注入缓冲信息到统计面板容器 function injectBufferInfo(statsPanel, player) { try { log('🔍 开始注入缓冲信息...'); const container = statsPanel.closest('#bilibili-player .bpx-player-info-container') || statsPanel.parentElement; if (!container) { log('❌ 未找到统计面板容器,放弃注入'); return; } let bufferLayer = container.querySelector('.bilibili-buffer-info-overlay'); if (!bufferLayer) { bufferLayer = document.createElement('div'); bufferLayer.className = 'bilibili-buffer-info-overlay'; bufferLayer.style.cssText = [ 'margin: 0', 'padding: 8px 12px', 'border-top: 1px solid rgba(255,255,255,0.2)', 'font-size: 12px', 'color: #fff', 'display: block' ].join(';'); container.appendChild(bufferLayer); log('✅ 已创建缓冲信息覆盖层'); } else { log('ℹ️ 缓冲信息覆盖层已存在,复用'); bufferLayer.style.display = 'block'; } const updateBufferInfo = () => { try { const currentBufferTarget = (() => { try { const val = Number(player.getStableBufferTime ? player.getStableBufferTime() : NaN); return Number.isFinite(val) && val > 0 ? val : BUFFER_TIME; } catch (_) { return BUFFER_TIME; } })(); const bufferedTime = player.getBufferLength("video"); const formatTime = (seconds) => { if (!Number.isFinite(seconds) || seconds < 0) return '0s'; if (seconds < 60) return Math.floor(seconds) + 's'; const minutes = Math.floor(seconds / 60); const remainingSeconds = Math.floor(seconds % 60); return minutes + 'm' + remainingSeconds + 's'; }; const percentRaw = currentBufferTarget > 0 ? (bufferedTime / currentBufferTarget) * 100 : 0; const percentClamped = Math.max(0, Math.min(100, percentRaw)); const percentText = (Number.isFinite(percentClamped) ? (percentClamped < 10 ? percentClamped.toFixed(1) : Math.round(percentClamped)) : 0) + '%'; bufferLayer.innerHTML = '<div class="info-line">\n <span class="info-title">缓冲状态:</span>\n <span class="info-data" style="color: #52c41a; font-weight: bold;">' + formatTime(bufferedTime) + ' / ' + formatTime(currentBufferTarget) + ' [' + percentText + ']' + '</span>\n </div>'; } catch (e) { bufferLayer.innerHTML = '<div class="info-line">\n <span class="info-title">缓冲状态:</span>\n <span class="info-data" style="color: #faad14;">获取失败</span>\n </div>'; } }; if (bufferLayer.dataset.bufferUpdater === 'active') { updateBufferInfo(); return; } updateBufferInfo(); const updateInterval = setInterval(updateBufferInfo, 1000); bufferLayer.dataset.bufferUpdater = 'active'; const gcObserver = new MutationObserver(() => { if (!document.body.contains(container)) { clearInterval(updateInterval); delete bufferLayer.dataset.bufferUpdater; gcObserver.disconnect(); log('📊 统计面板容器已移除,停止缓冲信息更新'); } }); gcObserver.observe(document.body, { childList: true, subtree: true }); } catch (e) { log(`❌ 注入缓冲信息失败: ${e.message}`); } } // 页面加载完成后执行 function main() { log('🚀 脚本启动,启动定时任务...'); let player = getPlayer(); // 定期检查并应用缓冲设置 applyBufferOptimization(player); setInterval(() => { if (!player) { player = getPlayer(); } if (player) { applyBufferOptimization(player); } }, SETTING_RECHECK_INTERVAL * 1000); // 定期监控并注入面板信息 setInterval(() => { if (!player) { player = getPlayer(); } if (player) { monitorStatsPanelVisibility(player); } }, MONITOR_RECHECK_INTERVAL * 1000); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', main); } else { main(); } // 监听页面变化(SPA应用) let lastUrl = location.href; new MutationObserver(() => { if (location.href !== lastUrl) { lastUrl = location.href; log('🔄 页面变化,重新启动任务...'); main(); } }).observe(document, {subtree: true, childList: true}); })();