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
代码语言:javascript复制/**
* @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
: 固定位,无意义
/**
* @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
代码语言:javascript复制/**
* @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
代码语言:javascript复制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对象串,解析成弹幕数据
给出我的代码实现:bilibili-live-comet-demo
参考文章:
- B站直播弹幕ws协议分析
- 使用JavaScript中的WebSocket获取b站直播间弹幕
- Bilibili_Danmuji