您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
让B站视频进度条始终显示,不随控制栏自动隐藏。
// ==UserScript== // @name Bilibili 恒定显示进度条 // @name:zh-CN Bilibili 恒定显示进度条 // @namespace bilibili.com // @version 1.0 // @description 让B站视频进度条始终显示,不随控制栏自动隐藏。 // @author Jifu // @match https://www.bilibili.com/video/* // @grant none // @license MIT // ==/UserScript== ;(function () { const SCRIPTID = "BilibiliProgressBarPreserver" const BAR_HEIGHT = 4 const BAR_COLOR = "#fa5a5a" const BUFFER_COLOR = "rgba(255,255,255,.4)" // 插入自定义样式 function addStyle() { const style = document.createElement("style") style.id = SCRIPTID + "-style" style.textContent = ` #${SCRIPTID}-bar { position: absolute; left: 0; bottom: 0; width: 100%; height: ${BAR_HEIGHT}px; background: rgba(255,255,255,.15); z-index: 100; pointer-events: none; } #${SCRIPTID}-progress { position: absolute; left: 0; top: 0; height: ${BAR_HEIGHT}px; background: ${BAR_COLOR}; z-index: 101; width: 0; transition: width .2s linear; } #${SCRIPTID}-buffer { position: absolute; left: 0; top: 0; height: ${BAR_HEIGHT}px; background: ${BUFFER_COLOR}; z-index: 100; width: 0; transition: width .2s linear; } ` document.head.appendChild(style) } // 获取播放器容器 function getPlayerContainer() { // B站主播放器 return ( document.querySelector(".bpx-player-video-wrap") || document.querySelector(".bilibili-player-video-wrap") ) } // 获取视频元素 function getVideo() { return document.querySelector("video") } // 插入进度条 function appendBar(container) { if (!container || document.getElementById(SCRIPTID + "-bar")) return const bar = document.createElement("div") bar.id = SCRIPTID + "-bar" bar.innerHTML = ` <div id="${SCRIPTID}-buffer"></div> <div id="${SCRIPTID}-progress"></div> ` container.appendChild(bar) } // 绑定进度逻辑 function bindProgressBar(video) { const bar = document.getElementById(SCRIPTID + "-bar") if (!bar) return const progress = document.getElementById(SCRIPTID + "-progress") const buffer = document.getElementById(SCRIPTID + "-buffer") // 进度 video.addEventListener("timeupdate", () => { const percent = video.duration ? video.currentTime / video.duration : 0 progress.style.width = `${percent * 100}%` }) // 缓冲 video.addEventListener("progress", () => { let end = 0 for (let i = 0; i < video.buffered.length; i++) { if (video.currentTime < video.buffered.start(i)) continue end = video.buffered.end(i) } const percent = video.duration ? end / video.duration : 0 buffer.style.width = `${percent * 100}%` }) // 视频切换时重置 video.addEventListener("durationchange", () => { progress.style.width = "0" buffer.style.width = "0" }) } // 主流程 function main() { addStyle() let lastContainer = null, lastVideo = null // 监听DOM变化(B站页面经常AJAX切换) const observer = new MutationObserver(() => { const container = getPlayerContainer() const video = getVideo() if (container && video && container !== lastContainer) { appendBar(container) bindProgressBar(video) lastContainer = container lastVideo = video } }) observer.observe(document.body, { childList: true, subtree: true }) // 处理路由切换 let lastUrl = location.href setInterval(() => { if (location.href !== lastUrl) { lastUrl = location.href setTimeout(() => { const container = getPlayerContainer() const video = getVideo() if (container && video) { appendBar(container) bindProgressBar(video) lastContainer = container lastVideo = video } }, 500) } }, 1000) } main() })()