TypeScript初戰Chrome外掛:Bilibili彈幕熱度

MegrezZhu發表於2019-02-21

TL;DR

這是一個用來在B站視訊進度條上方建立顯示彈幕熱度的Chrome外掛,以彈幕數量-時間的直方圖顯示,在高能處(定義為短時間內有大量彈幕出現的時間點)有明顯的峰值,可以用來直觀地看視訊中的熱點,也可以拿來作為空降(跳躍快進)的指示。

已經上架Chrome外掛市場,在這裡或者搜【Danmaku】就能找到。

原始碼在GitHub,歡迎Star。

Chrome Webstore

背景

其實做一個這樣的外掛的想法已經在腦海裡盤桓好一陣了(創意來源於某Hub),直到最近才有空(摸魚)寫了出來,正好拿來作為TypeScript跟Chrome Extension的練手專案。

實現

外掛的實現主要分為如下幾個部分:

  • 程式碼注入
  • 獲取av號及分P
  • 獲取彈幕
  • 視覺化
  • 監控網頁過載

基於chrome-extension-typescript-starter的腳手架。

比較核心的庫

  • TypeScript
    • 型別系統用來靜態檢查/程式碼提示的效率提升還是十分顯著的,也減少了一些很蠢的bug的發生
  • echarts
    • 百度家的圖表庫,用來生成直方圖
  • rxjs
    • 觀察者 + 迭代器模式的實現
  • jquery
    • 簡易的DOM操作

程式碼注入

依靠Chrome Extension的manifest.json檔案可以指定在bilibili的頁面中執行指定的程式碼檔案。

獲取av號、分P

av號跟分P資訊一般可從url中直接獲得(形如https://www.bilibili.com/video/avXXXXX/?p=XXXX),但事實上B站的視訊格式分很多種,目前光我見到的就有下面幾種:

  • 普通視訊/video/avXXXXX/?p=XXXX
  • 稍後再看/watchlater/#/avXXXXXX/pXXXX
  • 從歷史觀看中進入/video/avXXXXXX/index_XXXXX.html
  • 番劇
    • 具體的某一集/bangumi/play/epYYYYY/
    • 從【番劇】分割槽中直接點進/bangumi/play/ssZZZZZ

因此需要有不同的處理,特別是番劇,url中沒有av號資訊,需要從DOM中獲取。

獲取彈幕

B站每個視訊都有一個av號,但由於每個視訊有可能有多個分P,因此B站還有一個隱含的cid用以索引一個具體的視訊(以及彈幕),通過分析找到了這個API:

https://api.bilibili.com/x/player/pagelist?aid=AV_ID&jsonp=jsonp

其實cid可以有多種方法獲得,包括網頁DOM、原網頁HTML等等,但由於B站視訊分類眾多(普通視訊、番劇、稍後再看、歷史觀看)且網頁DOM都有不同,因此還是用這個API比較優雅

可以通過av號拿到該視訊每個分P的cid以及視訊長度,然後通過API

https://comment.bilibili.com/CID.xml

能夠獲取xml格式的彈幕資料,告一段落

彈幕資料的解析參考自這篇部落格

生成直方圖

這個倒簡單,處理一下彈幕資料呼叫echarts的API即可。

監控網頁過載

在使用者點選切換分P或者其他操作的時候,B站前端用的是HTML5的History API(也有的是hashchange),因此不能光用window.onhashchange事件來監控。而對於H5 History的監控,標準上又只有onpopstate事件,沒有onpushstate(這一點是我比較困惑的,望有人解惑)。

因此只能使用折中的方案:利用外掛的background script以及webNavigation許可權監控所有B站選項卡的history更新(通過chrome提供的onHistoryStateUpdated事件),並且建立content_script與background_script的連線進行單點通知,觸發頁面中的url更新事件。

相關文章