B站视频观看总进度

给B站多P视频下方添加一个总进度

// ==UserScript==
// @name         B站视频观看总进度
// @namespace    http://tampermonkey.net/
// @version      1.2.1
// @description  给B站多P视频下方添加一个总进度
// @author       汐涌及岸
// @match        https://www.bilibili.com/video/*
// @icon         https://www.bilibili.com/favicon.ico
// @grant        none
// ==/UserScript==

const bvid = isBiliPlayer.bvid;
//格式化
const HHmmss = second => [Math.floor(second/3600),Math.floor(second/60)%60,second%60].map(n=>n.toString().padStart(2,0)).join(':')
//进度解析
const durationHelper = {
  async request(){
    const data = app.__vue__.videoData
    return data.ugc_season ? durationHelper.episodesAdapte(data) : durationHelper.pagesAdapte(data)
  },
  //分P
  pagesAdapte(data) {
    if (data.pages.length <= 1) return null
    const p = parseInt(new URLSearchParams(location.search).get('p')) || 1
    const multi = data.pages.map(p => p.duration)
    const before = p > 1 ? multi.slice(0, p - 1).reduce((t, d) => t + d) : 0
    return { total: data.duration, multi, before}
  },
  //合集
  episodesAdapte(data) {
    const eps = data.ugc_season.sections[0].episodes
    if (eps.length <= 1) return null
    let multi = []
    let total = 0, before = 0
    let isBefore = true
    for (const ep of eps) {
      if (ep.bvid == bvid) isBefore = false
      const duration = ep.page.duration
      multi.push(duration)
      total += duration
      if (isBefore) {
        before += duration
      }
    }
    return { multi, total, before }
  },
}
//进度条管理
const totalProgress = {
  data:null,
  el:null,
  async init(){
    totalProgress.createEl()
    totalProgress.data = await durationHelper.request()
    totalProgress.setContent()
    //进度条刷新
    window.player.on("Player_TimeUpdate", totalProgress.setContent)
    //分P列表点击时重新获取数据
    document.getElementById('multi_page').addEventListener('click',totalProgress.init)
  },
  //创建标签
  createEl(){
    if (document.getElementById('video-total-progress')) return
    const el = document.createElement('span')
    el.id = 'video-total-progress'
    el.style.color = '#eee'
    el.style.paddingLeft = '12px'

    let ctrlTimeLabelEl = document.querySelector('.bpx-player-ctrl-time-label')
    ctrlTimeLabelEl.style.display = "inline-block"
    ctrlTimeLabelEl.style.width = "unset"
    ctrlTimeLabelEl.insertAdjacentElement('beforeend',el)
    ctrlTimeLabelEl.parentElement.style.minWidth = "max-content"
    
    totalProgress.el = el
  },
  //设置内容
  setContent(){
    const { before,total } = totalProgress.data
    const now = parseInt(window.player.getCurrentTime())+before
    totalProgress.el.innerHTML = `<b>总进度</b> ${HHmmss(now)} / ${HHmmss(total)} (${((now/total)*100).toFixed(2)}%)`
  }
}
//等待播放器加载完成
let waitPlayerLoad = setInterval(() => { if(!window.player || !document.querySelector('.bpx-player-ctrl-time-label') || !app.__vue__) return; totalProgress.init(); clearInterval(waitPlayerLoad)}, 1000);