我关于某些视频网站缓存不会自动加载的问题的解决方案
当观看网站的在线视频的时候, 底下进度条后面还有一个半透明的缓冲条,当进度条达到透明条的地方,视频就会卡一下,然后半透明进度条会往前一下 ,也就是说看视频的时候每过一分钟就会个几秒.
根据我的观察,b站的几分钟的短视频,20分钟左右的番剧的缓冲条都是会自动加载的,正常播放不会有卡顿,而我在看一些时间较长的音乐视频的时候,我希望在后台自动播放,但是他会每分钟卡个几秒,这就很影响体验。这应该也是b站的单宽策略所致。
那如何解决呢?经过手动测试,当在进度条上点击任意时间的时候,缓冲时间就会填满到1分钟左右的时间,于是我让ai写了脚本
// ==UserScript==
// @name B站精准阈值缓冲器
// @namespace http://tampermonkey.net/
// @version 5.1
// @description 当剩余缓冲不足指定秒数时触发无感加载
// @match *://*.bilibili.com/*
// @grant unsafeWindow // 需要特殊权限访问页面音频系统
// @run-at document-idle // 等页面完全加载后执行
// ==/UserScript==
(function() {
'use strict';
// ================= 配置参数 =================
const BUFFER_THRESHOLD = 5; // 当剩余缓冲时间少于5秒时触发预加载
const CHECK_INTERVAL = 2000; // 每2秒检查一次缓冲状态(毫秒)
const MICRO_SEEK = 0.00001; // 10微秒的极小跳转量(人耳不可感知)
// ================= 状态控制 =================
let isOperating = false; // 防止重复触发锁
const audioContext = new (window.AudioContext || window.webkitAudioContext)(); // 创建独立音频上下文
let mediaElementSource = null; // 音频管道连接器
/**
* 计算当前播放位置之后的剩余缓冲时间
* @param {HTMLVideoElement} video - 视频元素
* @return {number} 剩余缓冲秒数
*
* 原理:遍历video.buffered对象,找到包含当前播放时间的缓冲区间,
* 然后用区间结束时间减去当前时间得到剩余缓冲
*/
function getRemainingBuffer(video) {
for (let i = 0; i < video.buffered.length; i++) {
if (video.buffered.start(i) <= video.currentTime &&
video.buffered.end(i) >= video.currentTime) {
return video.buffered.end(i) - video.currentTime;
}
}
return 0; // 没有找到有效缓冲区间
}
/**
* 核心缓冲触发函数(完全无感知实现)
*
* 实现原理:
* 1. 极微小地调整播放位置(10微秒)
* 2. 通过Web Audio API保持音频连续性
* 3. 1毫秒内立即恢复原位置
*
* 这样触发了浏览器的缓冲机制,但用户完全感知不到
*/
function triggerStealthBuffer() {
if (isOperating) return; // 防止重复执行
// 兼容新旧版B站播放器(含Shadow DOM情况)
const video = document.querySelector('.bpx-player-container')?.shadowRoot?.querySelector('video')
|| document.querySelector('video');
if (!video || video.paused || video.readyState < 3) return; // 视频未就绪时跳过
const remainingBuffer = getRemainingBuffer(video);
if (remainingBuffer > BUFFER_THRESHOLD) return; // 缓冲充足时不操作
isOperating = true; // 加锁
// 初始化音频管道(防止操作导致音频卡顿)
if (!mediaElementSource) {
mediaElementSource = audioContext.createMediaElementSource(video);
mediaElementSource.connect(audioContext.destination);
}
const originalTime = video.currentTime;
// 量子级操作(核心技巧)
video.currentTime = originalTime + MICRO_SEEK; // 极小幅度跳转
setTimeout(() => {
video.currentTime = originalTime; // 极速恢复原位
isOperating = false; // 解锁
console.debug(`[幽灵缓冲] 已触发 | 剩余缓冲: ${remainingBuffer.toFixed(2)}秒`);
}, 1); // 1毫秒延迟确保稳定性
}
/**
* 智能初始化系统
*
* 等待播放器加载完成后再启动检测循环
* 采用轮询方式确保兼容动态加载的播放器
*/
function init() {
const video = document.querySelector('video, .bpx-player-container');
if (video) {
setInterval(triggerStealthBuffer, CHECK_INTERVAL); // 启动定时检测
console.log('✅ 精准缓冲系统已激活 | 配置:', {
触发阈值: `${BUFFER_THRESHOLD}秒`,
检测频率: `${CHECK_INTERVAL}ms`,
跳转幅度: `${MICRO_SEEK}秒`
});
} else {
setTimeout(init, 1000); // 未找到播放器则1秒后重试
}
}
// ================= 启动逻辑 =================
if (document.readyState === 'complete') {
init(); // 页面已加载完成直接启动
} else {
window.addEventListener('load', init); // 否则等待页面加载
}
})();
使用油猴运行
会在缓冲区即将到头的时候小小的卡一下下,但是相比原先好太多了
