golang
的b站信息流处理
go-bili-chat
是一个用于处理 Bilibili 直播间信息流库,可以用于开发自己的 Bilibili 直播间信息流处理程序。
b站直播间信息流以Websocket传输并加密, 含有几十个不同的命令, 本项目对其进行了解析, 并提供了一些简单的处理方法, 以便于开发者快速开发自己的程序。
信息流处理流程为: 客户端收到信息 -> 解析后由处理器进行分发
因此, 你需要先将命令处理函数绑定到处理器, 再开启直播间进行处理,
package main
import (
"fmt"
bili "github.com/FishZe/go-bili-chat"
handle "github.com/FishZe/go-bili-chat/handler"
)
func main() {
// 新建一个命令处理器
h := bili.GetNewHandler()
// 注册一个处理,将该直播间的弹幕消息绑定到这个函数
h.AddOption(handle.CmdDanmuMsg, 26097368, func(event handle.MsgEvent) {
// 打印出弹幕消息
fmt.Printf("[%v] %v: %v\n", event.RoomId, event.DanMuMsg.Data.Sender.Name, event.DanMuMsg.Data.Content)
})
// 连接到直播间
_ = h.AddRoom(26097368)
// 启动处理器
h.Run()
}
特殊地, 绑定函数的直播间号为0时,绑定所有房间
package main
import (
"fmt"
bili "github.com/FishZe/go-bili-chat"
handle "github.com/FishZe/go-bili-chat/handler"
"time"
)
func main() {
h := bili.GetNewHandler()
// 运行处理器
go h.Run()
h.AddOption(handle.CmdDanmuMsg, 26097368, func(event handle.MsgEvent) {
fmt.Printf("[%v] %v: %v\n", event.RoomId, event.DanMuMsg.Data.Sender.Name, event.DanMuMsg.Data.Content)
})
_ = h.AddRoom(26097368)
for {
time.Sleep(time.Second)
}
}
package main
import (
"fmt"
bili "github.com/FishZe/go-bili-chat"
handle "github.com/FishZe/go-bili-chat/handler"
)
func main() {
h := bili.GetNewHandler()
h.AddOption(handle.CmdDanmuMsg, 26097368, func(event handle.MsgEvent) {
fmt.Printf("[%v] %v: %v\n", event.RoomId, event.DanMuMsg.Data.Sender.Name, event.DanMuMsg.Data.Content)
})
_ = h.AddRoom(26097368)
_ = h.DelRoom(26097368)
h.Run()
}
关于为什么在处理绑定函数时, 多一个直播间号的参数, 因为考虑到可能会有根据不同的直播间分发处理消息的需求
DefaultPriority: 默认模式, 按照b站提供的顺序进行连接
DelayPriority: 低延迟模式, 将会在连接前计算到所有提供的服务器的延迟, 并选择最低的(连接会慢一些)
NoCDNPriority: 不使用CDN模式, 适合大量连接的情况
默认使用的模式为DefaultPriority
, 有需要的可以使用这种方式修改:
bili.SetClientPriorityMode(bili.DelayPriority)
type Json struct{}
func (j *Json) Unmarshal(data []byte, v interface{}) error {
return json.Unmarshal(data, v)
}
func (j *Json) Marshal(v interface{}) ([]byte, error) {
return json.Marshal(v)
}
bili.SetJsonCoder(&Json{})
具体的示例代码可以查看example/main.gp
bili.ChangeLogLevel(log.DebugLevel)
开启DEBUG
日志后, 可以看到所有的数据包和分发过程, 如果想要直观的看到分发到的函数名称, 可以在AddOption
中写明该函数的备注名
h.AddOption(handle.CmdDanmuMsg, 21545805, func(event handle.MsgEvent) {
fmt.Printf("[%v][弹幕] %v (%v): %v\n", event.RoomId, event.DanMuMsg.Data.Sender.Name, event.DanMuMsg.Data.Medal.MedalName, event.DanMuMsg.Data.Content)
}, "弹幕处理")
控制台会显示类似如下的日志
[bili-live][02-21 16:42:55][DEBUG]: distribute DANMU_MSG cmd to 弹幕处理
这些常量请填入go-bili-chat.GetNewHandler().AddOption()
的第一个参数
常量名 原始命令
CmdDanmuMsg "DANMU_MSG"
CmdSuperChatMessage "SUPER_CHAT_MESSAGE"
CmdSuperChatMessageJpn "SUPER_CHAT_MESSAGE_JPN"
CmdWatchedChange "WATCHED_CHANGE"
CmdSendGift "SEND_GIFT"
CmdOnlineRankCount "ONLINE_RANK_COUNT"
CmdOnlineRankV2 "ONLINE_RANK_V2"
CmdOnlineRankTop3 "ONLINE_RANK_TOP3"
CmdLikeInfoV3Click "LIKE_INFO_V3_CLICK"
CmdInteractWord "INTERACT_WORD"
CmdStopLiveRoomList "STOP_LIVE_ROOM_LIST"
CmdLikeInfoV3Update "LIKE_INFO_V3_UPDATE"
CmdHotRankChange "HOT_RANK_CHANGED"
CmdNoticeMsg "NOTICE_MSG"
CmdRoomRealTimeMessageUpdate "ROOM_REAL_TIME_MESSAGE_UPDATE"
CmdWidgetBanner "WIDGET_BANNER"
CmdHotRankChangedV2 "HOT_RANK_CHANGED_V2"
CmdGuardHonorThousand "GUARD_HONOR_THOUSAND"
CmdLive "LIVE"
CmdRoomChange "ROOM_CHANGE"
CmdRoomBlockMsg "ROOM_BLOCK_MSG"
CmdFullScreenSpecialEffect "FULL_SCREEN_SPECIAL_EFFECT"
CmdCommonNoticeDanmaku "COMMON_NOTICE_DANMAKU"
CmdTradingScore "TRADING_SCORE"
CmdPreparing "PREPARING"
CmdGuardBuy "GUARD_BUY"
CmdGiftStarProcess "GIFT_STAR_PROCESS"
CmdRoomSkinMsg "ROOM_SKIN_MSG"
CmdEnterEffect "ENTER_EFFECT"
CmdUserToastMsg "USER_TOAST_MSG"
CmdHeartBeatReply "HEARTBEAT_REPLY"
CmdPopularityRedPocketNew "POPULARITY_RED_POCKET_NEW"
CmdAreaRankChanged "AREA_RANK_CHANGED"
CmdSuperChatEntrance "SUPER_CHAT_ENTRANCE"
CmdPlayTogether "PLAY_TOGETHER"
CmdComboSend "COMBO_SEND"
CmdPopularityRedPocketStart "POPULARITY_RED_POCKET_START"
由于我也不是很明白b站的命令, 所以这里只是列出了我知道的命令, 如果有人知道更多的命令, 请在issue中提出, 我会及时更新。
相信可以通过直译看懂这些命令...
消息处理函数的原型为:
func someFunc(event MsgEvent)
其中MsgEvent
的定义为:
type MsgEvent struct {
//原始命令
Cmd string
//直播间号
RoomId int
// 以下为不同的消息类型
DanMuMsg *DanMuMsg
SuperChatMessage *SuperChatMessage
// 下同, 可参考上方的消息类型, 取消Cmd即为结构体名称...
...
}
这是弹幕消息的例子
type DanMuMsg struct {
Cmd string `json:"cmd"`
Data struct {
Sender struct {
Uid int64
Name string
RoomId int64
}
Medal FansMedal
Content string
SendTimeStamp int
SendMillionTimeStamp int64
SenderEnterRoomTimeStamp int
}
}
结构体内容, 请参考go-bili-chat/Handler/template.go
中的定义
因为30个实在是太多了, 所以我就不一一列出来了...
2023/03/05 晚上19:30分
上海 32核心 64G内存 Centos7.6 (腾讯云 计算型C5)
开启了8000个直播间, 其中260个正在直播
内存占用 483.61MB CPU总占用3197% (跑满了..)
每秒收集信息如下:
进入直播间:47 弹幕:44 礼物:3 超级留言:0 大航海:0
进入直播间:49 弹幕:42 礼物:3 超级留言:0 大航海:0
进入直播间:60 弹幕:35 礼物:4 超级留言:0 大航海:0
进入直播间:53 弹幕:48 礼物:3 超级留言:0 大航海:0
进入直播间:61 弹幕:28 礼物:6 超级留言:0 大航海:0
进入直播间:52 弹幕:49 礼物:7 超级留言:0 大航海:0
进入直播间:60 弹幕:35 礼物:1 超级留言:0 大航海:0
进入直播间:58 弹幕:40 礼物:1 超级留言:0 大航海:0
进入直播间:54 弹幕:44 礼物:3 超级留言:0 大航海:0
进入直播间:56 弹幕:34 礼物:4 超级留言:0 大航海:0
进入直播间:54 弹幕:44 礼物:7 超级留言:0 大航海:0
进入直播间:54 弹幕:50 礼物:2 超级留言:0 大航海:0
进入直播间:45 弹幕:38 礼物:2 超级留言:1 大航海:0
进入直播间:58 弹幕:36 礼物:4 超级留言:1 大航海:0
进入直播间:50 弹幕:58 礼物:4 超级留言:0 大航海:0
进入直播间:58 弹幕:44 礼物:3 超级留言:0 大航海:0
进入直播间:49 弹幕:48 礼物:8 超级留言:0 大航海:0
进入直播间:47 弹幕:39 礼物:5 超级留言:0 大航海:0
进入直播间:51 弹幕:36 礼物:3 超级留言:0 大航海:0
进入直播间:61 弹幕:49 礼物:6 超级留言:0 大航海:0
进入直播间:55 弹幕:39 礼物:3 超级留言:0 大航海:0
进入直播间:36 弹幕:37 礼物:9 超级留言:0 大航海:0
进入直播间:59 弹幕:46 礼物:5 超级留言:0 大航海:1
进入直播间:56 弹幕:56 礼物:3 超级留言:0 大航海:0
进入直播间:51 弹幕:38 礼物:6 超级留言:0 大航海:0
进入直播间:45 弹幕:39 礼物:4 超级留言:0 大航海:0
进入直播间:51 弹幕:44 礼物:1 超级留言:0 大航海:0
进入直播间:61 弹幕:47 礼物:3 超级留言:0 大航海:0
进入直播间:61 弹幕:45 礼物:2 超级留言:0 大航海:1
进入直播间:39 弹幕:46 礼物:6 超级留言:0 大航海:0
进入直播间:68 弹幕:48 礼物:4 超级留言:0 大航海:0
+============================+ +=================+
| LiveRoom 1 | | |
| goroutine heart beat | | → → goroutine your function
| goroutine receive msg → → ↓| | |
| goroutine msg handler ← ← ←| | → → goroutine your function
+================|↓|=========+ _ |
→ → → → → → → → goroutine → → goroutine your function
+============================+ _ |
| LiveRoom 1 | | msg distribute → → goroutine your function
| goroutine heart beat | | |
| goroutine receive msg → → ↓| | → → goroutine your function
| goroutine msg handler ← ← ←| | |
+================|↓|=========+ _ → → goroutine your function
→ → → → → → → → |
_ → → goroutine your function
+======|↑|========+
↑
↑
+=======|↑|========+
| |
| main goroutine |
| |
+==================+