Loading... # BiliBili直播弹幕WS协议浅析 ## 相关接口 - GET https://api.live.bilibili.com/room/v1/Room/room_init 参数:id 直播间号,可以是短号 用于获取短号直播间的真实直播间号,以及主播uid - GET https://api.live.bilibili.com/room/v1/Danmu/getConf 参数: room_id 直播间号 platform=pc 观看平台 player=web 播放方式 用于获取弹幕服务ws地址和token,有个通用的地址:`broadcastlv.chat.bilibili.com` ## WS ws地址:`wss://broadcastlv.chat.bilibili.com/sub` 数据由两部分组成,Header和Body 在连接后5s内需要发送认证数据包(即Body为认证数据),否则会被服务器断开连接 完成认证后,进行正常的交互 ### Header ```kotlin /** * @author mashirot */ data class DataHeader( val totalLength: Int, val headerLength: Short, val protocolVersion: Short, val dataType: Int, val fixed: Int, ) ``` 给出如上类定义 `totalLength`: 为Header+Body的总bit数 `headerLength`: 固定为16,即用2个Byte存头部 `protocolVersion`: 协议版本 `dataType`: 数据类型 `fixed`: 固定位,无意义 ```kotlin /** * @author mashirot */ object DataHeaderConsts { const val TOTAL_LENGTH_IDX = 0 const val HEADER_LENGTH_IDX = 4 const val PROTOCOL_VERSION_IDX = 6 const val DATA_TYPE_IDX = 8 const val FIXED_IDX = 12 const val HEADER_LENGTH: Short = 16 const val HEADER_LENGTH_INT = 16 const val UNCOMPRESSED_PROTOCOL: Short = 0 const val HEARTBEAT_PROTOCOL: Short = 1 const val COMPRESS_PROTOCOL: Short = 3 const val FIXED_VAL = 1 const val CLIENT_HEARTBEAT = 2 const val SERVER_HEARTBEAT = 3 const val SERVER_ADVICE = 5 const val CLIENT_AUTHORIZE = 7 const val SERVER_AUTHORIZE = 8 } ``` 给出如上常量定义,意义不再解释,由如下几点说明 `UNCOMPRESSED_PROTOCOL`通常用来传递高能榜人数,直播间在线人数等数据,`dataType`通常为`SERVER_ADVICE` `HEARTBEAT_PROTOCOL`指的是本数据包为心跳包,除了认证心跳包外,其余均无Body,即`totalLength = headerLength = 16` `COMPRESS_PROTOCOL`通常就是弹幕数据,Body中包含多条弹幕 ### AuthorizeBody ```kotlin /** * @author mashirot */ data class AuthorizeBody( val uid: Long?, val roomid: Long, val protover: Int, val buvid: String?, val platform: String, val type: Int, val key: String?, ) ``` 给出如上类定义 `uid`: uid,用于解除风控导致的弹幕用户名不可见 `roomid`: 直播间号,不能为短号,请通过相关接口获取真实直播间号 `protover`: 协议版本,目前为3 `buvid`: 未知,规则为uuid+infoc,解除风控用 `platform`: web/android,正常使用web `type`: 未知,可以是2 `key`: 调用`https://api.live.bilibili.com/room/v1/Danmu/getConf`接口返回的`token`值,解除风控用 如果不需要解除风控,只需要给`roomid`, `protover`, `platform`, `type`即可 ### HeartbeatBag ```kotlin val header = DataHeader(HEADER_LENGTH_INT, HEADER_LENGTH, HEARTBEAT_PROTOCOL, CLIENT_HEARTBEAT, FIXED_VAL) ``` ### 弹幕数据 从请求头可以发现`gzip, deflate, br`这三种压缩算法,网上很多文章都说用`zlib`解压,实践中确实可以解压出数据,但会有部分乱码,因为实际采用的压缩算法是Google的`brotli`算法(也可能是b站改了 将数据的前16位取出,解析成DataHeader,判断是否是`COMPRESS_PROTOCOL` 通过`brotli`算法解压出弹幕的json(可能为List),并拆分成独立的json对象串,解析成弹幕数据 <br /> 给出我的代码实现:[bilibili-live-comet-demo](https://github.com/mashirot/bilibili-live-comet-demo) <br /> 参考文章: 1. [B站直播弹幕ws协议分析](https://daidr.me/archives/code-526.html) 2. [使用JavaScript中的WebSocket获取b站直播间弹幕](https://www.bilibili.com/read/cv14101053/) 3. [Bilibili_Danmuji](https://github.com/BanqiJane/Bilibili_Danmuji) 最后修改:2024 年 01 月 12 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 1 本作品采用 CC BY-NC-SA 4.0 International License 进行许可。