This project is in progress... ?,有問題歡迎提交issuse, 覺得有用的話可以點個小星星️鼓勵一下,感謝
如果對專案有興趣也歡迎加入頻道交流討論, 提交PR
ToDo List: https://github.com/orgs/OrdinaryRoad-Project/projects/1
更新日誌: https://github.com/OrdinaryRoad-Project/ordinaryroad-live-chat-client/releases
BarrageFly-讓彈幕飛,基於該專案的一個彈幕轉發、過濾、處理平台
*存在平台差異
- ✅: 平台支援且已完成
- ☑️️: 平台支援但未實現
- : 平台網頁端暫不支持
平台 | LiveChatClient | Cookie | 短直播間id | 發送彈幕 | 為主播按讚 | 直播間資訊* |
---|---|---|---|---|---|---|
Bilibili B站 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Douyu 鬥魚 | ✅ | ✅ | ✅ | ✅ | ✅ | |
Huya 虎牙 | ✅ | ✅ | ✅ | ✅ | ✅ | |
Douyin 抖音* | ✅ | ☑️️ | ✅ | ☑️ | ☑️️ | ✅ |
Kuaishou 快手 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Tiktok* | ✅ | ✅ | ✅ | ☑️ | ☑️ | ✅ |
*暫未完全支持,(Tiktok在測試中)
*直播間資訊目前僅支援獲取直播間標題
平台 | 彈幕 | 禮物 | 醒目留言 | 進入房間 | 讚 | 狀態變化 | 統計資訊 | 社群訊息 |
---|---|---|---|---|---|---|---|---|
Bilibili B站 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅(按讚數、目前人數、累積觀看人數) | |
Douyu 鬥魚 | ✅ | ✅ | ☑️ | ✅ | ☑️ | |||
Huya 虎牙 | ✅ | ✅ | ✅(進階用戶) | ☑️ | ||||
Douyin 抖音 | ✅ | ✅ | ✅ | ✅(按讚個數) | ✅ | ✅(按讚數、目前人數) | ✅(分享、關注) | |
Kuaishou 快手 | ✅ | ✅(禮物訊息不全) | ✅(首次按讚) | ✅(按讚數、目前人數) | ||||
Tiktok | ✅ | ✅ | ✅ | ✅(按讚個數) | ✅ | ✅(按讚數、目前人數) | ✅(分享、關注) |
訊息介面內建的方法請參考https://github.com/OrdinaryRoad-Project/ordinaryroad-live-chat-client/tree/main/live-chat-client-commons/live-chat-client-commons-base/src/ main/java/tech/ordinaryroad/live/chat/client/commons/base/msg
運行效果圖
抓取瀏覽器的WebSocket二進位串流,然後分析模擬瀏覽器的行為;這種方式的優點是不需要開發者認證,缺點是沒有官方文檔,分析過程比較費時費力,並且需要適配不同平台的流程變化(不會經常變化)
以後可能會考慮支援平台的開放協議
JDK ≥ 8
< dependency >
< groupId >tech.ordinaryroad</ groupId >
< artifactId >live-chat-client-bilibili</ artifactId >
<!-- 参考github release版本,不需要前缀`v` -->
< version >${ordinaryroad-live-chat-client.version}</ version >
</ dependency >
Gradle使用者註意:自從
0.3.2
版本開始,B站Client配置中,壓縮方式預設為NORMAL_BROTLI
,當使用Gradle引入時,還需要引入作業系統對應的brotli4j native包,詳見:https://github.com /hyperxpro/Brotli4j?tab=readme-ov-file#gradle
例如:
val liveChatClientBrotliVersion = " 1.16.0 "
// Windows
implementation( " com.aayushatharva.brotli4j:native-windows-x86_64: $l iveChatClientBrotliVersion " )
implementation( " com.aayushatharva.brotli4j:native-windows-aarch64: $l iveChatClientBrotliVersion " )
// Linux
implementation( " com.aayushatharva.brotli4j:native-linux-armv7: $l iveChatClientBrotliVersion " )
implementation( " com.aayushatharva.brotli4j:native-linux-aarch64: $l iveChatClientBrotliVersion " )
implementation( " com.aayushatharva.brotli4j:native-linux-x86_64: $l iveChatClientBrotliVersion " )
implementation( " com.aayushatharva.brotli4j:native-linux-s390x: $l iveChatClientBrotliVersion " )
implementation( " com.aayushatharva.brotli4j:native-linux-riscv64: $l iveChatClientBrotliVersion " )
implementation( " com.aayushatharva.brotli4j:native-linux-ppc64le: $l iveChatClientBrotliVersion " )
// Mac
implementation( " com.aayushatharva.brotli4j:native-osx-aarch64: $l iveChatClientBrotliVersion " )
implementation( " com.aayushatharva.brotli4j:native-osx-x86_64: $l iveChatClientBrotliVersion " )
如果引入後仍無法使用,請修改protover配置項,例如改為NORMAL_ZLIB
: BilibiliLiveChatClientConfig.builder().protover(ProtoverEnum.NORMAL_ZLIB).roomId("xxx").build()
< dependency >
< groupId >tech.ordinaryroad</ groupId >
< artifactId >live-chat-client-douyu</ artifactId >
<!-- 参考github release版本,不需要前缀`v` -->
< version >${ordinaryroad-live-chat-client.version}</ version >
</ dependency >
< dependency >
< groupId >tech.ordinaryroad</ groupId >
< artifactId >live-chat-client-huya</ artifactId >
<!-- 参考github release版本,不需要前缀`v` -->
< version >${ordinaryroad-live-chat-client.version}</ version >
</ dependency >
< dependency >
< groupId >tech.ordinaryroad</ groupId >
< artifactId >live-chat-client-douyin</ artifactId >
<!-- 参考github release版本,不需要前缀`v` -->
< version >${ordinaryroad-live-chat-client.version}</ version >
</ dependency >
< dependency >
< groupId >tech.ordinaryroad</ groupId >
< artifactId >live-chat-client-kuaishou</ artifactId >
<!-- 参考github release版本,不需要前缀`v` -->
< version >${ordinaryroad-live-chat-client.version}</ version >
</ dependency >
測試類別包含了多種範例,可供參考
可以重寫onCmdMsg(收到的所有CMD消息)
或onOtherCmdMsg(框架未处理的CMD消息)
回呼方法,判斷CMD來監聽框架已經定義的CMD類型
如果要監聽的訊息枚舉類別中未定義,可以考慮重寫onUnknownCmdMsg(未知CMD消息)
方法
ICmdMsg類型轉換對應關係
@ Override
public void onOtherCmdMsg ( BilibiliCmdEnum cmd , ICmdMsg < BilibiliCmdEnum > cmdMsg ) {
switch ( cmd ) {
case GUARD_BUY : {
// 有人上舰
MessageMsg messageMsg = ( MessageMsg ) cmdMsg ;
...
break ;
}
case SUPER_CHAT_MESSAGE_DELETE : {
// 删除醒目留言
MessageMsg messageMsg = ( MessageMsg ) cmdMsg ;
...
break ;
}
default : {
// ignore
}
}
}
Spring Boot 範例client-example
如果需要查看其他平台的效果,請將
Bilibili
改為其他平台對應的英文,並修改訊息回呼介面的函式簽名
public class ClientModeExample {
public static void main ( String [] args ) {
String cookie = System . getenv ( "cookie" );
// 1. 创建配置
BilibiliLiveChatClientConfig config = BilibiliLiveChatClientConfig . builder ()
// TODO 消息转发地址
. forwardWebsocketUri ( "" )
// TODO 浏览器Cookie
. cookie ( cookie )
// TODO 直播间id(支持短id)
. roomId ( 7777 )
. build ();
// 2. 创建Client并传入配置、添加消息回调
BilibiliLiveChatClient client = new BilibiliLiveChatClient ( config , new IBilibiliMsgListener () {
@ Override
public void onDanmuMsg ( BilibiliBinaryFrameHandler binaryFrameHandler , DanmuMsgMsg msg ) {
IBilibiliMsgListener . super . onDanmuMsg ( binaryFrameHandler , msg );
System . out . printf ( "%s 收到弹幕 %s %s(%s):%s n " , binaryFrameHandler . getRoomId (), msg . getBadgeLevel () != 0 ? msg . getBadgeLevel () + msg . getBadgeName () : "" , msg . getUsername (), msg . getUid (), msg . getContent ());
}
@ Override
public void onGiftMsg ( BilibiliBinaryFrameHandler binaryFrameHandler , SendGiftMsg msg ) {
IBilibiliMsgListener . super . onGiftMsg ( binaryFrameHandler , msg );
System . out . printf ( "%s 收到礼物 %s %s(%s) %s %s(%s)x%s(%s) n " , binaryFrameHandler . getRoomId (), msg . getBadgeLevel () != 0 ? msg . getBadgeLevel () + msg . getBadgeName () : "" , msg . getUsername (), msg . getUid (), msg . getData (). getAction (), msg . getGiftName (), msg . getGiftId (), msg . getGiftCount (), msg . getGiftPrice ());
}
@ Override
public void onSuperChatMsg ( BilibiliBinaryFrameHandler binaryFrameHandler , SuperChatMessageMsg msg ) {
IBilibiliMsgListener . super . onSuperChatMsg ( binaryFrameHandler , msg );
System . out . printf ( "%s 收到醒目留言 %s(%s):%s n " , binaryFrameHandler . getRoomId (), msg . getUsername (), msg . getUid (), msg . getContent ());
}
@ Override
public void onEnterRoomMsg ( InteractWordMsg msg ) {
System . out . printf ( "%s %s(%s) 进入直播间n " , msg . getBadgeLevel () != 0 ? msg . getBadgeLevel () + msg . getBadgeName () : "" , msg . getUsername (), msg . getUid ());
}
@ Override
public void onLikeMsg ( BilibiliBinaryFrameHandler binaryFrameHandler , LikeInfoV3ClickMsg msg ) {
IBilibiliMsgListener . super . onLikeMsg ( binaryFrameHandler , msg );
System . out . printf ( "%s 收到点赞 %s %s(%s) n " , binaryFrameHandler . getRoomId (), msg . getBadgeLevel () != 0 ? msg . getBadgeLevel () + msg . getBadgeName () : "" , msg . getUsername (), msg . getUid ());
}
@ Override
public void onLiveStatusMsg ( BilibiliBinaryFrameHandler binaryFrameHandler , BilibiliLiveStatusChangeMsg msg ) {
IBilibiliMsgListener . super . onLiveStatusMsg ( binaryFrameHandler , msg );
System . out . printf ( "%s 状态变化 %s n " , binaryFrameHandler . getRoomId (), msg . getLiveStatusAction ());
}
@ Override
public void onRoomStatsMsg ( BilibiliBinaryFrameHandler binaryFrameHandler , BilibiliRoomStatsMsg msg ) {
IBilibiliMsgListener . super . onRoomStatsMsg ( binaryFrameHandler , msg );
System . out . printf ( "%s 统计信息 累计点赞数: %s, 当前观看人数: %s, 累计观看人数: %s n " , binaryFrameHandler . getRoomId (), msg . getLikedCount (), msg . getWatchingCount (), msg . getWatchedCount ());
}
});
// 添加客户端连接状态回调
client . addStatusChangeListener (( evt , oldStatus , newStatus ) -> {
if ( newStatus == ClientStatusEnums . CONNECTED ) {
// TODO 要发送的弹幕内容,请注意控制发送频率;框架内置支持设置发送弹幕的最少时间间隔,小于时将忽略该次发送
client . sendDanmu ( "666666" + RandomUtil . randomNumbers ( 1 ));
}
});
// 3. 开始监听直播间
client . connect ();
}
}
void connect(Runnable success, Consumer<Throwable> failed)
void connect(Runnable success)
void connect()
void disconnect(boolean cancelReconnect)
void disconnect()
void destroy()
void send(Object msg, Runnable success, Consumer<Throwable> failed)
void send(Object msg, Runnable success)
void send(Object msg, Consumer<Throwable> failed)
void send(Object msg)
void sendDanmu(Object danmu, Runnable success, Consumer<Throwable> failed)
void sendDanmu(Object danmu, Runnable success)
void sendDanmu(Object danmu, Consumer<Throwable> failed)
void sendDanmu(Object danmu)
void clickLike(int count, Runnable success, Consumer<Throwable> failed)
void clickLike(int count, Runnable success)
void clickLike(int count, Consumer<Throwable> failed)
void clickLike(int count)
boolean addMsgListener(MsgListener msgListener)
boolean addMsgListeners(List<MsgListener> msgListeners)
boolean removeMsgListener(MsgListener msgListener)
boolean removeMsgListeners(List<MsgListener> msgListeners)
ClientStatusEnums getStatus()
void addStatusChangeListener(IClientStatusChangeListener listener)
void removeStatusChangeListener(IClientStatusChangeListener listener)
參考BilibiliHandlerModeExample
參考codec-example
B站範例,其他平台只需修改bilibili
即可
使用Gradle引入B站編解碼模組時,參考#B站
< dependency >
< groupId >tech.ordinaryroad</ groupId >
< artifactId >live-chat-client-codec-bilibili</ artifactId >
<!-- 参考github release版本,不需要前缀`v` -->
< version >${ordinaryroad-live-chat-client.version}</ version >
</ dependency >
生效範圍:僅項目自身,不會影響引用該項目的父項目
在程式碼中修改Config socks5ProxyHost("127.0.0.1")
, socks5ProxyPort("1080")
身份認證(暫未測試)
socks5ProxyUsername("username")
, socks5ProxyPassword("password")
掃描二維碼加入QQ/微信頻道,或點選連結加入QQ頻道【OrdinaryRoad】:https://pd.qq.com/s/3id0n7fvs
開源不易,您的認可與支持是我不斷更新的最大動力!
日期 | 捐贈人 | 金額 | 留言 | 頻道 |
---|---|---|---|---|
2024-03-06 | **睿 | 88.88 | 佬加油 | ZFB |
2024-03-10 | **豪 | 88.8 | 大佬加油 | ZFB |
2024-03-25 | **波 | 188.8 | / | ZFB |
2024-04-02 | **豪 | 30 | / | ZFB |
2024-04-30 | *h | 100 | 大佬牛逼 | WX |
2024-11-18 | *磊 | 200 | / | WX |
… | … | … | … | … |
免責聲明:僅供學術研究使用。對於違反相關法律、造成危害的濫用行為,開發者不負任何責任。
Keywords: 彈幕抓取彈幕爬取彈幕爬蟲