显示 AV/BV

在视频页显示 AV/BV 号

// ==UserScript==
// @name         显示 AV/BV
// @namespace    im.outv.userscript.bvav
// @version      1.0
// @description  在视频页显示 AV/BV 号
// @author       Outvi V
// @match        *://www.bilibili.com/*
// @match        *://bilibili.com/*
// @license      MIT
// @grant        none
// ==/UserScript==

;(function () {
  'use strict'

  const VBR_TRY_COUNT = 12
  const AV_SPAN_ID = '__bvav__span_av'
  const BV_SPAN_ID = '__bvav__span_bv'

  const Log = (...args) => console.log('[bvav]', ...args)

  function nowOrReady(cb) {
    if (document.readyState !== 'loading') {
      cb()
    } else {
      document.addEventListener('DOMContentLoaded', () => {
        cb()
      })
    }
  }

  function sleep(ms) {
    return new Promise((r) => {
      setTimeout(() => {
        r()
      }, ms)
    })
  }

  function findOrCreateAndUpdateText(id, value) {
    let elem = document.querySelector('#' + id)
    if (!elem) {
      elem = document.createElement('span')
      elem.id = id
      elem.classList.add('a-crumbs')
      const ih = document.querySelector('.video-data')
      ih.appendChild(elem)
    }
    elem.innerText = value
  }

  function appendAvBv() {
    document
      .querySelector('.video-data')
      .lastElementChild.classList.add('a-crumbs')
    findOrCreateAndUpdateText(AV_SPAN_ID, 'av' + window.aid)
    findOrCreateAndUpdateText(BV_SPAN_ID, window.bvid)
  }

  // Monitor on hydration
  function setupBodyObserver() {
    const body = document.body
    Log('Monitoring changes of #app')
    const observer = new MutationObserver((muts) => {
      muts.map((x) => {
        if (x.addedNodes) {
          const nodes = [...x.addedNodes].filter((y) => y.id === 'app')
          if (nodes.length > 0) {
            Log('#app has changed, re-observing')
            setupObserver(nodes[nodes.length - 1])
          }
        }
      })
    })
    observer.observe(body, {
      childList: true,
    })
  }

  async function setupObserver(app) {
    let tries = 0
    let vbr = null
    while (vbr === null && tries < VBR_TRY_COUNT) {
      await sleep(800)
      vbr = app.querySelector('#viewbox_report')
      tries++
      if (tries > 0) Log('Still waiting for VBR')
    }
    if (tries > VBR_TRY_COUNT) {
      Log('Cannot find VBR, giving up')
      return
    }

    appendAvBv()

    const observer = new MutationObserver((muts) => {
      muts.map((x) => {
        if (x.target.tagName === 'H1') {
          appendAvBv()
          Log(x)
        }
      })
    })

    observer.observe(vbr, {
      subtree: true,
      attributes: true,
    })

    Log('Observing VBR:', vbr)
  }

  nowOrReady(() => {
    Log('Setting up...')
    setupObserver(document.querySelector('#app'))
    setupBodyObserver()
  })
})()