TL;DR
這是一個用來在B站視訊進度條上方建立顯示彈幕熱度的Chrome外掛,以彈幕數量-時間的直方圖顯示,在高能處(定義為短時間內有大量彈幕出現的時間點)有明顯的峰值,可以用來直觀地看視訊中的熱點,也可以拿來作為空降(跳躍快進)的指示。
已經上架Chrome外掛市場,在這裡或者搜【Danmaku】就能找到。
原始碼在GitHub,歡迎Star。
背景
其實做一個這樣的外掛的想法已經在腦海裡盤桓好一陣了(創意來源於某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更新事件。