mirror of
https://github.com/czp3009/bilibili-api.git
synced 2025-01-20 20:40:42 +08:00
初步完成 LiveClient 用于获取直播间实时弹幕
This commit is contained in:
parent
189301a4a9
commit
e6037e6c02
43
document/bullet_screen_stream_json/DANMU_MSG.json
Normal file
43
document/bullet_screen_stream_json/DANMU_MSG.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"info": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
25,
|
||||||
|
16777215,
|
||||||
|
1510498713,
|
||||||
|
"1510498712",
|
||||||
|
0,
|
||||||
|
"8a0f75dc",
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"网易云音乐库在当前直播间已停留0天0时39分41秒",
|
||||||
|
[
|
||||||
|
39042255,
|
||||||
|
"夏沫丶琉璃浅梦",
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
10000,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
[
|
||||||
|
13,
|
||||||
|
"夏沫",
|
||||||
|
"乄夏沫丶",
|
||||||
|
"1547306",
|
||||||
|
16746162,
|
||||||
|
""
|
||||||
|
],
|
||||||
|
[
|
||||||
|
41,
|
||||||
|
0,
|
||||||
|
16746162,
|
||||||
|
6603
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"cmd": "DANMU_MSG"
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"info": [
|
||||||
|
//弹幕基本属性
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
//pool
|
||||||
|
1,
|
||||||
|
//mode
|
||||||
|
25,
|
||||||
|
//fontSize
|
||||||
|
16777215,
|
||||||
|
//color
|
||||||
|
1510498713,
|
||||||
|
//弹幕发送时间
|
||||||
|
"1510498712",
|
||||||
|
//用户进房时间(Android 客户端发送的弹幕, 这个值会是随机数)
|
||||||
|
0,
|
||||||
|
"8a0f75dc",
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"网易云音乐库在当前直播间已停留0天0时39分41秒",
|
||||||
|
//发送者有关信息
|
||||||
|
[
|
||||||
|
39042255,
|
||||||
|
//发送者 ID
|
||||||
|
"夏沫丶琉璃浅梦",
|
||||||
|
//发送者用户名
|
||||||
|
0,
|
||||||
|
//是否是管理员
|
||||||
|
1,
|
||||||
|
//是否是 VIP
|
||||||
|
0,
|
||||||
|
//是否是 svip
|
||||||
|
10000,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
//发送者的粉丝勋章有关信息(没有粉丝勋章的发送者, 这个 JsonArray 将是空的)
|
||||||
|
[
|
||||||
|
13,
|
||||||
|
//勋章等级
|
||||||
|
"夏沫",
|
||||||
|
//勋章名称
|
||||||
|
"乄夏沫丶",
|
||||||
|
//勋章主播的名字
|
||||||
|
"1547306",
|
||||||
|
//勋章主播的直播间
|
||||||
|
16746162,
|
||||||
|
""
|
||||||
|
],
|
||||||
|
//用户经验有关信息
|
||||||
|
[
|
||||||
|
41,
|
||||||
|
//发送者的观众等级
|
||||||
|
0,
|
||||||
|
16746162,
|
||||||
|
6603
|
||||||
|
//排名
|
||||||
|
],
|
||||||
|
//用户头衔有关信息(里面有两个元素, 但是总是一样的, 不知道为什么)
|
||||||
|
[
|
||||||
|
"title-131-1",
|
||||||
|
"title-131-1"
|
||||||
|
],
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"cmd": "DANMU_MSG"
|
||||||
|
}
|
4
document/bullet_screen_stream_json/LIVE.json
Normal file
4
document/bullet_screen_stream_json/LIVE.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"cmd": "LIVE",
|
||||||
|
"roomid": 1110317
|
||||||
|
}
|
4
document/bullet_screen_stream_json/PREPARING.json
Normal file
4
document/bullet_screen_stream_json/PREPARING.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"cmd": "PREPARING",
|
||||||
|
"roomid": 1110317
|
||||||
|
}
|
80
document/bullet_screen_stream_json/SEND_GIFT.json
Normal file
80
document/bullet_screen_stream_json/SEND_GIFT.json
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
{
|
||||||
|
"cmd": "SEND_GIFT",
|
||||||
|
"data": {
|
||||||
|
"giftName": "\u4ebf\u5706",
|
||||||
|
"num": 1,
|
||||||
|
"uname": "\u30c5\u4ee3\u6211\u56de\u5bb6",
|
||||||
|
"rcost": 106855699,
|
||||||
|
"uid": 14146398,
|
||||||
|
"top_list": [
|
||||||
|
{
|
||||||
|
"uid": 10952886,
|
||||||
|
"uname": "\u5b89\u4e36\u664b",
|
||||||
|
"coin": 498900,
|
||||||
|
"face": "http://static.hdslb.com/images/member/noface.gif",
|
||||||
|
"guard_level": 0,
|
||||||
|
"rank": 1,
|
||||||
|
"score": 498900
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": 13174983,
|
||||||
|
"uname": "-\u56db\u5b63\u8c46-",
|
||||||
|
"coin": 384300,
|
||||||
|
"face": "http://i0.hdslb.com/bfs/face/23f9f57a69378736f68b50fc4cac4f6b01683e97.jpg",
|
||||||
|
"guard_level": "3",
|
||||||
|
"rank": 2,
|
||||||
|
"score": 384300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": 87444977,
|
||||||
|
"uname": "\u964c\u964c\u821e\u98ce",
|
||||||
|
"coin": 377700,
|
||||||
|
"face": "http://i2.hdslb.com/bfs/face/c06c835bf8ed6401535847bf21e78d4d3b89d402.jpg",
|
||||||
|
"guard_level": 0,
|
||||||
|
"rank": 3,
|
||||||
|
"score": 377700
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timestamp": 1510565032,
|
||||||
|
"giftId": 6,
|
||||||
|
"giftType": 0,
|
||||||
|
"action": "\u8d60\u9001",
|
||||||
|
"super": 0,
|
||||||
|
"price": 1000,
|
||||||
|
"rnd": "541907145",
|
||||||
|
"newMedal": 0,
|
||||||
|
"newTitle": 0,
|
||||||
|
"medal": [],
|
||||||
|
"title": "",
|
||||||
|
"beatId": "",
|
||||||
|
"biz_source": "live",
|
||||||
|
"metadata": "",
|
||||||
|
"remain": 0,
|
||||||
|
"gold": 0,
|
||||||
|
"silver": 0,
|
||||||
|
"eventScore": 0,
|
||||||
|
"eventNum": 0,
|
||||||
|
"smalltv_msg": [],
|
||||||
|
"specialGift": null,
|
||||||
|
"notice_msg": [],
|
||||||
|
"capsule": {
|
||||||
|
"normal": {
|
||||||
|
"coin": 6,
|
||||||
|
"change": 0,
|
||||||
|
"progress": {
|
||||||
|
"now": 4800,
|
||||||
|
"max": 10000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"colorful": {
|
||||||
|
"coin": 0,
|
||||||
|
"change": 0,
|
||||||
|
"progress": {
|
||||||
|
"now": 0,
|
||||||
|
"max": 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addFollow": 0
|
||||||
|
}
|
||||||
|
}
|
11
document/bullet_screen_stream_json/SYS_GIFT.json
Normal file
11
document/bullet_screen_stream_json/SYS_GIFT.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"cmd": "SYS_GIFT",
|
||||||
|
"msg": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
|
||||||
|
"msg_text": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
|
||||||
|
"tips": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
|
||||||
|
"url": "http:\/\/live.bilibili.com\/71084",
|
||||||
|
"roomid": 71084,
|
||||||
|
"real_roomid": 71084,
|
||||||
|
"giftId": 102,
|
||||||
|
"msgTips": 0
|
||||||
|
}
|
12
document/bullet_screen_stream_json/SYS_MSG.json
Normal file
12
document/bullet_screen_stream_json/SYS_MSG.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"cmd": "SYS_MSG",
|
||||||
|
"msg": "\u3010\u5e7d\u5c0f\u591c\u5929\u5c0f\u52ab\u3011:?\u5728\u76f4\u64ad\u95f4:?\u3010392\u3011:?\u8d60\u9001 \u5c0f\u7535\u89c6\u4e00\u4e2a\uff0c\u8bf7\u524d\u5f80\u62bd\u5956",
|
||||||
|
"msg_text": "\u3010\u5e7d\u5c0f\u591c\u5929\u5c0f\u52ab\u3011:?\u5728\u76f4\u64ad\u95f4:?\u3010392\u3011:?\u8d60\u9001 \u5c0f\u7535\u89c6\u4e00\u4e2a\uff0c\u8bf7\u524d\u5f80\u62bd\u5956",
|
||||||
|
"rep": 1,
|
||||||
|
"styleType": 2,
|
||||||
|
"url": "http:\/\/live.bilibili.com\/392",
|
||||||
|
"roomid": 392,
|
||||||
|
"real_roomid": 71084,
|
||||||
|
"rnd": 44332151,
|
||||||
|
"tv_id": "29349"
|
||||||
|
}
|
10
document/bullet_screen_stream_json/WELCOME.json
Normal file
10
document/bullet_screen_stream_json/WELCOME.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"cmd": "WELCOME",
|
||||||
|
"data": {
|
||||||
|
"uid": 18625858,
|
||||||
|
"uname": "\u662f\u767d\u8272\u70e4\u6f06",
|
||||||
|
"isadmin": 0,
|
||||||
|
"svip": 1
|
||||||
|
},
|
||||||
|
"roomid": 39189
|
||||||
|
}
|
10
document/bullet_screen_stream_json/WELCOME_GUARD.json
Normal file
10
document/bullet_screen_stream_json/WELCOME_GUARD.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"cmd": "WELCOME_GUARD",
|
||||||
|
"data": {
|
||||||
|
"uid": 23598108,
|
||||||
|
"username": "lovevael",
|
||||||
|
"guard_level": 3,
|
||||||
|
"water_god": 0
|
||||||
|
},
|
||||||
|
"roomid": 43001
|
||||||
|
}
|
@ -12,6 +12,7 @@ public class BulletScreenEntity {
|
|||||||
@SerializedName("msg")
|
@SerializedName("msg")
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
|
//在 web 端发送弹幕, 该字段是固定的, 为用户进入直播页面的时间的时间戳. 但是在 Android 端, 这是一个随机数
|
||||||
//该随机数不包括符号位有 9 位
|
//该随机数不包括符号位有 9 位
|
||||||
@SerializedName("rnd")
|
@SerializedName("rnd")
|
||||||
private long random = (long) (Math.random() * (999999999 - (-999999999)) + (-999999999));
|
private long random = (long) (Math.random() * (999999999 - (-999999999)) + (-999999999));
|
||||||
|
@ -0,0 +1,116 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.hiczp.bilibili.api.live.socket.entity.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class BulletScreenDispatcherRunnable implements Runnable {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(BulletScreenDispatcherRunnable.class);
|
||||||
|
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
private static final JsonParser JSON_PARSER = new JsonParser();
|
||||||
|
private SocketChannel socketChannel;
|
||||||
|
private LiveClient liveClient;
|
||||||
|
|
||||||
|
public BulletScreenDispatcherRunnable(SocketChannel socketChannel, LiveClient liveClient) {
|
||||||
|
this.socketChannel = socketChannel;
|
||||||
|
this.liveClient = liveClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invokeCallback(Consumer<BulletScreenListener> consumer) {
|
||||||
|
Utils.invokeCallback(liveClient.getBulletScreenListeners(), consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
ByteBuffer[] byteBuffers = PackageRepository.readNextPackageSplit(socketChannel);
|
||||||
|
//如果没有回调则不解析数据包, 直接开始接收下一个数据包
|
||||||
|
if (liveClient.getBulletScreenListeners().size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断数据包类型
|
||||||
|
byte[] packageTypeBytes = byteBuffers[3].array();
|
||||||
|
Consumer<BulletScreenListener> consumer = null;
|
||||||
|
if (Arrays.equals(packageTypeBytes, PackageRepository.DATA_PACKAGE_TYPE_BYTES)) { //弹幕
|
||||||
|
String json = new String(byteBuffers[5].array());
|
||||||
|
JsonObject jsonObject = JSON_PARSER.parse(json).getAsJsonObject();
|
||||||
|
String cmd = jsonObject.get("cmd").getAsString();
|
||||||
|
//判断 cmd
|
||||||
|
switch (cmd) {
|
||||||
|
case "DANMU_MSG": {
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onDanMuMSGPackage(GSON.fromJson(json, DanMuMSGEntity.class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "SEND_GIFT": {
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onSendGiftPackage(GSON.fromJson(json, SendGiftEntity.class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "SYS_MSG": {
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onSysMSGPackage(GSON.fromJson(json, SysMSGEntity.class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "SYS_GIFT": {
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onSysGiftPackage(GSON.fromJson(json, SysGiftEntity.class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "WELCOME": {
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onWelcomePackage(GSON.fromJson(json, WelcomeEntity.class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "WELCOME_GUARD": {
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onWelcomeGuardPackage(GSON.fromJson(json, WelcomeGuardEntity.class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "LIVE": {
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onLivePackage(GSON.fromJson(json, LiveEntity.class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "PREPARING": {
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onPreparingPackage(GSON.fromJson(json, PreparingEntity.class));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: { //未知的 cmd
|
||||||
|
LOGGER.error("Unknown json below: ");
|
||||||
|
GSON.toJson(jsonObject, System.out);
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Arrays.equals(packageTypeBytes, PackageRepository.VIEWER_COUNT_PACKAGE_TYPE_BYTES)) { //在线人数
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onViewerCountPackage(byteBuffers[5].getInt());
|
||||||
|
} else { //未知类型
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocate(Arrays.stream(byteBuffers).mapToInt(ByteBuffer::limit).sum());
|
||||||
|
Arrays.stream(byteBuffers).forEach(byteBuffer::put);
|
||||||
|
byte[] bytes = byteBuffer.array();
|
||||||
|
LOGGER.error("Unknown package below: ");
|
||||||
|
Utils.printBytes(bytes);
|
||||||
|
consumer = bulletScreenListener -> bulletScreenListener.onUnknownPackage(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
//执行回调
|
||||||
|
invokeCallback(consumer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.debug("Connection closed, BulletScreenDispatcherThread prepare to exit");
|
||||||
|
try {
|
||||||
|
liveClient.close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
//调用 onDisconnect 回调
|
||||||
|
invokeCallback(BulletScreenListener::onDisconnect);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket;
|
||||||
|
|
||||||
|
import com.hiczp.bilibili.api.live.socket.entity.*;
|
||||||
|
|
||||||
|
public interface BulletScreenListener {
|
||||||
|
void onConnect();
|
||||||
|
|
||||||
|
void onDisconnect();
|
||||||
|
|
||||||
|
void onViewerCountPackage(int viewerCount);
|
||||||
|
|
||||||
|
void onDanMuMSGPackage(DanMuMSGEntity danMuMSGEntity);
|
||||||
|
|
||||||
|
void onSendGiftPackage(SendGiftEntity sendGiftEntity);
|
||||||
|
|
||||||
|
void onSysMSGPackage(SysMSGEntity sysMSGEntity);
|
||||||
|
|
||||||
|
void onSysGiftPackage(SysGiftEntity sysGiftEntity);
|
||||||
|
|
||||||
|
void onWelcomePackage(WelcomeEntity welcomeEntity);
|
||||||
|
|
||||||
|
void onWelcomeGuardPackage(WelcomeGuardEntity welcomeGuardEntity);
|
||||||
|
|
||||||
|
void onLivePackage(LiveEntity liveEntity);
|
||||||
|
|
||||||
|
void onPreparingPackage(PreparingEntity preparingEntity);
|
||||||
|
|
||||||
|
void onUnknownPackage(byte[] raw);
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket;
|
||||||
|
|
||||||
|
import com.hiczp.bilibili.api.live.socket.entity.*;
|
||||||
|
|
||||||
|
public class BulletScreenListenerAdaptor implements BulletScreenListener {
|
||||||
|
@Override
|
||||||
|
public void onConnect() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisconnect() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewerCountPackage(int viewerCount) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDanMuMSGPackage(DanMuMSGEntity danMuMSGEntity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSendGiftPackage(SendGiftEntity sendGiftEntity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSysMSGPackage(SysMSGEntity sysMSGEntity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSysGiftPackage(SysGiftEntity sysGiftEntity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWelcomePackage(WelcomeEntity welcomeEntity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWelcomeGuardPackage(WelcomeGuardEntity welcomeGuardEntity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLivePackage(LiveEntity liveEntity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPreparingPackage(PreparingEntity preparingEntity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnknownPackage(byte[] raw) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
138
src/main/java/com/hiczp/bilibili/api/live/socket/LiveClient.java
Normal file
138
src/main/java/com/hiczp/bilibili/api/live/socket/LiveClient.java
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket;
|
||||||
|
|
||||||
|
import com.hiczp.bilibili.api.BilibiliRESTAPI;
|
||||||
|
import com.hiczp.bilibili.api.live.LiveService;
|
||||||
|
import com.hiczp.bilibili.api.live.entity.LiveRoomInfoEntity;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
public class LiveClient implements Closeable {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(LiveClient.class);
|
||||||
|
|
||||||
|
private int showRoomId;
|
||||||
|
private int roomId;
|
||||||
|
private int userId = BilibiliRESTAPI.getMid();
|
||||||
|
private LiveService liveService = BilibiliRESTAPI.getLiveService();
|
||||||
|
private Vector<BulletScreenListener> bulletScreenListeners = new Vector<>();
|
||||||
|
private LiveRoomInfoEntity.LiveRoomEntity liveRoomEntity;
|
||||||
|
private SocketChannel socketChannel;
|
||||||
|
private Thread bulletScreenDispatcherThread;
|
||||||
|
private Timer heartBeatTimer;
|
||||||
|
|
||||||
|
public LiveClient(int showRoomId) {
|
||||||
|
this.showRoomId = showRoomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
//如果不传入 userId, 将使用默认值 0
|
||||||
|
public LiveClient(int showRoomId, int userId) {
|
||||||
|
this.showRoomId = showRoomId;
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveClient addListener(BulletScreenListener bulletScreenListener) {
|
||||||
|
bulletScreenListeners.add(bulletScreenListener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveClient removeListener(BulletScreenListener bulletScreenListener) {
|
||||||
|
bulletScreenListeners.remove(bulletScreenListener);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveClient connect() throws IOException {
|
||||||
|
LOGGER.info("Entering live room {} with uid {}", showRoomId, userId);
|
||||||
|
//获取直播间信息
|
||||||
|
LiveRoomInfoEntity liveRoomInfoEntity = liveService.getRoomInfo(showRoomId).execute().body();
|
||||||
|
if (liveRoomInfoEntity.getCode() != 0) {
|
||||||
|
LOGGER.error("Can't get live room info");
|
||||||
|
throw new IOException(liveRoomInfoEntity.getMessage());
|
||||||
|
}
|
||||||
|
liveRoomEntity = liveRoomInfoEntity.getData();
|
||||||
|
roomId = liveRoomEntity.getRoomId();
|
||||||
|
LOGGER.debug("Real room id: {}", roomId);
|
||||||
|
|
||||||
|
//socket 连接
|
||||||
|
String address = liveRoomEntity.getCmt();
|
||||||
|
int port = liveRoomEntity.getCmtPortGoim();
|
||||||
|
LOGGER.info("Connect to {}:{}", address, port);
|
||||||
|
socketChannel = SocketChannel.open(new InetSocketAddress(address, port));
|
||||||
|
//发送进房包
|
||||||
|
socketChannel.write(PackageRepository.createEnterRoomPackage(roomId, userId));
|
||||||
|
//验证下一个数据包是否是进房成功数据包
|
||||||
|
if (PackageRepository.isNextPackageIsEnterRoomSuccessPackage(socketChannel)) {
|
||||||
|
LOGGER.info("Socket connection success");
|
||||||
|
//调用 onConnect 回调
|
||||||
|
Utils.invokeCallback(bulletScreenListeners, BulletScreenListener::onConnect);
|
||||||
|
} else {
|
||||||
|
LOGGER.error("Socket connection failed");
|
||||||
|
socketChannel.close();
|
||||||
|
throw new SocketException("Can't connection to Bullet Screen server");
|
||||||
|
}
|
||||||
|
|
||||||
|
//启动回调分发线程
|
||||||
|
bulletScreenDispatcherThread = new Thread(new BulletScreenDispatcherRunnable(socketChannel, this));
|
||||||
|
bulletScreenDispatcherThread.setName("BulletScreenDispatcherThread");
|
||||||
|
bulletScreenDispatcherThread.start();
|
||||||
|
LOGGER.debug("BulletScreenDispatcherThread started");
|
||||||
|
|
||||||
|
//启动心跳包线程
|
||||||
|
heartBeatTimer = new Timer("LiveHeartBeatThread");
|
||||||
|
heartBeatTimer.schedule(new TimerTask() {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(TimerTask.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
socketChannel.socket().getOutputStream().write(PackageRepository.createHeartBeatPackage(roomId, userId).array());
|
||||||
|
logger.debug("Send heart beat package success");
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Connection closed, cancel HeartBeatTimerTask");
|
||||||
|
cancel();
|
||||||
|
try {
|
||||||
|
close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0, 30 * 1000);
|
||||||
|
LOGGER.debug("HeatBeatTimer started");
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void close() throws IOException {
|
||||||
|
if (heartBeatTimer != null) {
|
||||||
|
heartBeatTimer.cancel();
|
||||||
|
LOGGER.debug("HeartBeatTimer canceled");
|
||||||
|
heartBeatTimer = null;
|
||||||
|
}
|
||||||
|
if (socketChannel != null && socketChannel.isConnected()) {
|
||||||
|
socketChannel.close();
|
||||||
|
LOGGER.debug("Socket closed");
|
||||||
|
socketChannel = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector<BulletScreenListener> getBulletScreenListeners() {
|
||||||
|
return bulletScreenListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBulletScreenListeners(Vector<BulletScreenListener> bulletScreenListeners) {
|
||||||
|
this.bulletScreenListeners = bulletScreenListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveRoomInfoEntity.LiveRoomEntity getLiveRoomEntity() {
|
||||||
|
return liveRoomEntity;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.hiczp.bilibili.api.live.socket.entity.EnterRoomEntity;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
//数据包结构说明
|
||||||
|
//00 00 00 28 00 10 00 00 00 00 00 07 00 00 00 00
|
||||||
|
//00 00 00 28/00 10/00 00 00 00 00 07/00 00 00 00
|
||||||
|
//1-4 字节: 数据包长度
|
||||||
|
//5-6 字节: 协议头长度, 固定值 0x10
|
||||||
|
//7-8 字节: 设备类型, Android 固定为 0
|
||||||
|
//9-12 字节: 数据包类型
|
||||||
|
//13-16 字节: 设备类型, 同 7-8 字节
|
||||||
|
public class PackageRepository {
|
||||||
|
//数据包总长标识占用的 bytes 长度
|
||||||
|
static final short PACKAGE_LENGTH_BYTES_LENGTH = 4;
|
||||||
|
//协议头长度标识占用的 bytes 长度
|
||||||
|
static final short PROTOCOL_HEAD_LENGTH_BYTES_LENGTH = 2;
|
||||||
|
//设备类型短标识 bytes
|
||||||
|
static final byte[] SHORT_DEVICE_TYPE_BYTES = {0x00, 0x00};
|
||||||
|
//数据包类型标识 bytes
|
||||||
|
static final short PACKAGE_TYPE_BYTES_LENGTH = 4;
|
||||||
|
static final byte[] HEART_BEAT_PACKAGE_TYPE_BYTES = {0x00, 0x00, 0x00, 0x02}; //心跳包
|
||||||
|
static final byte[] VIEWER_COUNT_PACKAGE_TYPE_BYTES = {0x00, 0x00, 0x00, 0x03}; //观众人数
|
||||||
|
static final byte[] DATA_PACKAGE_TYPE_BYTES = {0x00, 0x00, 0x00, 0x05}; //弹幕, 礼物, 系统消息 etc
|
||||||
|
static final byte[] ENTER_ROOM_PACKAGE_TYPE_BYTES = {0x00, 0x00, 0x00, 0x07}; //进入房间
|
||||||
|
static final byte[] ENTER_ROOM_SUCCESS_PACKAGE_TYPE_BYTES = {0x00, 0x00, 0x00, 0x08}; //进入房间的响应包
|
||||||
|
//设备类型长标识 bytes
|
||||||
|
static final byte[] LONG_DEVICE_TYPE_BYTES = {0x00, 0x00, 0x00, 0x00};
|
||||||
|
//协议头总长度
|
||||||
|
static final short PROTOCOL_HEAD_LENGTH = (short) (PACKAGE_LENGTH_BYTES_LENGTH + PROTOCOL_HEAD_LENGTH_BYTES_LENGTH + SHORT_DEVICE_TYPE_BYTES.length + PACKAGE_TYPE_BYTES_LENGTH + LONG_DEVICE_TYPE_BYTES.length);
|
||||||
|
//协议头长度标识 bytes
|
||||||
|
static final byte[] PROTOCOL_HEAD_LENGTH_BYTES = ByteBuffer.allocate(PROTOCOL_HEAD_LENGTH_BYTES_LENGTH).putShort(PROTOCOL_HEAD_LENGTH).array();
|
||||||
|
private static final Gson GSON = new Gson();
|
||||||
|
|
||||||
|
private static ByteBuffer createPackage(byte[] packageTypeBytes, String content) {
|
||||||
|
int totalLength = PROTOCOL_HEAD_LENGTH + content.length();
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocate(totalLength)
|
||||||
|
.putInt(totalLength)
|
||||||
|
.put(PROTOCOL_HEAD_LENGTH_BYTES)
|
||||||
|
.put(SHORT_DEVICE_TYPE_BYTES)
|
||||||
|
.put(packageTypeBytes)
|
||||||
|
.put(LONG_DEVICE_TYPE_BYTES)
|
||||||
|
.put(content.getBytes());
|
||||||
|
byteBuffer.flip();
|
||||||
|
return byteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readDataFromSocketChannel(SocketChannel socketChannel, ByteBuffer byteBuffer) throws IOException {
|
||||||
|
while (byteBuffer.hasRemaining()) {
|
||||||
|
socketChannel.read(byteBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//userId 为 0 表示用户未登录, 并不影响弹幕推送, 但是可能和用户统计有关
|
||||||
|
public static ByteBuffer createEnterRoomPackage(int roomId, int userId) {
|
||||||
|
return createPackage(ENTER_ROOM_PACKAGE_TYPE_BYTES, GSON.toJson(new EnterRoomEntity(roomId, userId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteBuffer createHeartBeatPackage(int roomId, int userId) {
|
||||||
|
return createPackage(HEART_BEAT_PACKAGE_TYPE_BYTES, GSON.toJson(new EnterRoomEntity(roomId, userId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteBuffer readNextPackage(SocketChannel socketChannel) throws IOException {
|
||||||
|
//获取数据包总长度
|
||||||
|
ByteBuffer packageLengthByteBuffer = ByteBuffer.allocate(PACKAGE_LENGTH_BYTES_LENGTH);
|
||||||
|
readDataFromSocketChannel(socketChannel, packageLengthByteBuffer);
|
||||||
|
packageLengthByteBuffer.flip();
|
||||||
|
int packageLength = packageLengthByteBuffer.getInt();
|
||||||
|
packageLengthByteBuffer.rewind();
|
||||||
|
|
||||||
|
//获取数据包剩下的部分
|
||||||
|
ByteBuffer restPackageByteBuffer = ByteBuffer.allocate(packageLength - PACKAGE_LENGTH_BYTES_LENGTH);
|
||||||
|
readDataFromSocketChannel(socketChannel, restPackageByteBuffer);
|
||||||
|
restPackageByteBuffer.flip();
|
||||||
|
|
||||||
|
//合并 ByteBuffer
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocate(packageLengthByteBuffer.limit() + restPackageByteBuffer.limit());
|
||||||
|
byteBuffer.put(packageLengthByteBuffer).put(restPackageByteBuffer);
|
||||||
|
byteBuffer.flip();
|
||||||
|
return byteBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteBuffer[] readNextPackageSplit(SocketChannel socketChannel) throws IOException {
|
||||||
|
//获取数据包总长度
|
||||||
|
ByteBuffer packageLengthByteBuffer = ByteBuffer.allocate(PACKAGE_LENGTH_BYTES_LENGTH);
|
||||||
|
readDataFromSocketChannel(socketChannel, packageLengthByteBuffer);
|
||||||
|
packageLengthByteBuffer.flip();
|
||||||
|
int packageLength = packageLengthByteBuffer.getInt();
|
||||||
|
packageLengthByteBuffer.rewind();
|
||||||
|
|
||||||
|
//获取协议头长度
|
||||||
|
ByteBuffer protocolHeadLengthByteBuffer = ByteBuffer.allocate(PROTOCOL_HEAD_LENGTH_BYTES_LENGTH);
|
||||||
|
readDataFromSocketChannel(socketChannel, protocolHeadLengthByteBuffer);
|
||||||
|
protocolHeadLengthByteBuffer.flip();
|
||||||
|
int protocolHeadLength = protocolHeadLengthByteBuffer.getShort();
|
||||||
|
protocolHeadLengthByteBuffer.rewind();
|
||||||
|
|
||||||
|
//获取剩余的协议头
|
||||||
|
ByteBuffer restProtocolHeadByteBuffer = ByteBuffer.allocate(protocolHeadLength - PACKAGE_LENGTH_BYTES_LENGTH - PROTOCOL_HEAD_LENGTH_BYTES_LENGTH);
|
||||||
|
readDataFromSocketChannel(socketChannel, restProtocolHeadByteBuffer);
|
||||||
|
restProtocolHeadByteBuffer.flip();
|
||||||
|
|
||||||
|
//得到设备类型短标识
|
||||||
|
ByteBuffer shortDeviceTypeByteBuffer = ByteBuffer.allocate(SHORT_DEVICE_TYPE_BYTES.length);
|
||||||
|
shortDeviceTypeByteBuffer.putShort(restProtocolHeadByteBuffer.getShort());
|
||||||
|
shortDeviceTypeByteBuffer.flip();
|
||||||
|
|
||||||
|
//得到数据包类型
|
||||||
|
ByteBuffer packageTypeByteBuffer = ByteBuffer.allocate(PACKAGE_TYPE_BYTES_LENGTH);
|
||||||
|
packageTypeByteBuffer.putInt(restProtocolHeadByteBuffer.getInt());
|
||||||
|
packageTypeByteBuffer.flip();
|
||||||
|
|
||||||
|
//得到设备类型长标识
|
||||||
|
ByteBuffer longDeviceTypeByteBuffer = ByteBuffer.allocate(LONG_DEVICE_TYPE_BYTES.length);
|
||||||
|
longDeviceTypeByteBuffer.putInt(restProtocolHeadByteBuffer.getInt());
|
||||||
|
longDeviceTypeByteBuffer.flip();
|
||||||
|
|
||||||
|
//获取正文
|
||||||
|
ByteBuffer contentByteBuffer = ByteBuffer.allocate(packageLength - protocolHeadLength);
|
||||||
|
readDataFromSocketChannel(socketChannel, contentByteBuffer);
|
||||||
|
contentByteBuffer.flip();
|
||||||
|
|
||||||
|
//组成数组
|
||||||
|
return new ByteBuffer[]{
|
||||||
|
packageLengthByteBuffer, //0
|
||||||
|
protocolHeadLengthByteBuffer, //1
|
||||||
|
shortDeviceTypeByteBuffer, //2
|
||||||
|
packageTypeByteBuffer, //3
|
||||||
|
longDeviceTypeByteBuffer, //4
|
||||||
|
contentByteBuffer //5
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNextPackageIsEnterRoomSuccessPackage(SocketChannel socketChannel) throws IOException {
|
||||||
|
return Arrays.equals(readNextPackageSplit(socketChannel)[3].array(), ENTER_ROOM_SUCCESS_PACKAGE_TYPE_BYTES);
|
||||||
|
}
|
||||||
|
}
|
70
src/main/java/com/hiczp/bilibili/api/live/socket/Utils.java
Normal file
70
src/main/java/com/hiczp/bilibili/api/live/socket/Utils.java
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket;
|
||||||
|
|
||||||
|
import com.sun.istack.internal.Nullable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
private static byte[][] splitBytes(byte[] bytes, int n) {
|
||||||
|
int lineCount = bytes.length % n == 0 ? bytes.length / n : bytes.length / n + 1;
|
||||||
|
byte[][] result = new byte[lineCount][];
|
||||||
|
int to;
|
||||||
|
for (int line = 1; line <= lineCount; line++) {
|
||||||
|
if (line != lineCount) {
|
||||||
|
to = line * n;
|
||||||
|
} else {
|
||||||
|
to = bytes.length;
|
||||||
|
}
|
||||||
|
result[line - 1] = Arrays.copyOfRange(bytes, (line - 1) * n, to);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void invokeCallback(List<BulletScreenListener> bulletScreenListeners, @Nullable Consumer<BulletScreenListener> consumer) {
|
||||||
|
if (consumer != null) {
|
||||||
|
for (int i = bulletScreenListeners.size() - 1; i >= 0; i--) {
|
||||||
|
try {
|
||||||
|
consumer.accept(bulletScreenListeners.get(i));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void printBytes(byte[] bytes) {
|
||||||
|
byte[][] data = splitBytes(bytes, 16);
|
||||||
|
byte[] currentRow;
|
||||||
|
char c;
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
System.out.printf("%08x ", i * 16);
|
||||||
|
currentRow = data[i];
|
||||||
|
for (int j = 0; j < currentRow.length; j++) {
|
||||||
|
System.out.printf("%02x ", currentRow[j]);
|
||||||
|
if (j == 7) {
|
||||||
|
System.out.print(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentRow.length < 16) {
|
||||||
|
for (int k = 0; k < (48 - currentRow.length * 2 - (currentRow.length - 1)); k++) {
|
||||||
|
System.out.print(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.print(" ");
|
||||||
|
for (int j = 0; j < currentRow.length; j++) {
|
||||||
|
if (currentRow[j] < ' ') {
|
||||||
|
c = '.';
|
||||||
|
} else {
|
||||||
|
c = (char) currentRow[j];
|
||||||
|
}
|
||||||
|
System.out.print(c);
|
||||||
|
if (j == 7) {
|
||||||
|
System.out.print(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class DanMuMSGEntity {
|
||||||
|
private static final Gson GSON = new Gson();
|
||||||
|
private static final Type LIST_STRING_TYPE = new TypeToken<List<String>>() {
|
||||||
|
}.getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* info : [[0,1,25,16777215,1510498713,"1510498712",0,"8a0f75dc",0],"网易云音乐库在当前直播间已停留0天0时39分41秒",[39042255,"夏沫丶琉璃浅梦",0,1,0,10000,1],[13,"夏沫","乄夏沫丶","1547306",16746162,""],[41,0,16746162,6603],[],0,0]
|
||||||
|
* cmd : DANMU_MSG
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("cmd")
|
||||||
|
private String cmd;
|
||||||
|
@SerializedName("info")
|
||||||
|
private JsonArray info;
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonArray getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfo(JsonArray info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pool 发布的弹幕池 (0 普通 1 字幕 2 特殊)
|
||||||
|
public int getPool() {
|
||||||
|
return info.get(0).getAsJsonArray().get(0).getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//mode 弹幕的模式 (1 普通 4 底端 5 顶端 6 逆向 7 特殊 9 高级)
|
||||||
|
public int getMode() {
|
||||||
|
return info.get(0).getAsJsonArray().get(1).getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//fontSize 字体大小
|
||||||
|
public int getFontSize() {
|
||||||
|
return info.get(0).getAsJsonArray().get(2).getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//color 字体颜色
|
||||||
|
public int getColor() {
|
||||||
|
return info.get(0).getAsJsonArray().get(3).getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//弹幕发送时间(Unix 时间戳)(其实是服务器接收到弹幕的时间)
|
||||||
|
public long getSendTime() {
|
||||||
|
return info.get(0).getAsJsonArray().get(4).getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//用户进入房间的时间(Unix 时间戳)(但是 Android 发送的弹幕, 这个值会是随机数)
|
||||||
|
public String getUserEnterTime() {
|
||||||
|
return info.get(0).getAsJsonArray().get(5).getAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//得到弹幕内容
|
||||||
|
public String getMessage() {
|
||||||
|
return info.get(1).getAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//得到发送者的用户 ID
|
||||||
|
public int getUserId() {
|
||||||
|
return info.get(2).getAsJsonArray().get(0).getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//得到发送者的用户名
|
||||||
|
public String getUsername() {
|
||||||
|
return info.get(2).getAsJsonArray().get(1).getAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送者是否是管理员
|
||||||
|
public boolean isAdmin() {
|
||||||
|
return info.get(2).getAsJsonArray().get(2).getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送者是否是 VIP
|
||||||
|
public boolean isVip() {
|
||||||
|
return info.get(2).getAsJsonArray().get(3).getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送者是否是 SVip
|
||||||
|
public boolean isSVip() {
|
||||||
|
return info.get(2).getAsJsonArray().get(4).getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
//表示粉丝勋章有关信息的 JsonArray 可能是空的
|
||||||
|
//获取粉丝勋章等级
|
||||||
|
public Optional<Integer> getFansMedalLevel() {
|
||||||
|
if (info.get(3).getAsJsonArray().size() > 0) {
|
||||||
|
return Optional.of(info.get(3).getAsJsonArray().get(0).getAsInt());
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取粉丝勋章名称
|
||||||
|
public Optional<String> getFansMedalName() {
|
||||||
|
if (info.get(3).getAsJsonArray().size() > 0) {
|
||||||
|
return Optional.of(info.get(3).getAsJsonArray().get(1).getAsString());
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取粉丝勋章对应的主播的名字
|
||||||
|
public Optional<String> getFansMedalOwnerName() {
|
||||||
|
if (info.get(3).getAsJsonArray().size() > 0) {
|
||||||
|
return Optional.of(info.get(3).getAsJsonArray().get(2).getAsString());
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取粉丝勋章对应的主播的直播间 ID
|
||||||
|
public Optional<String> getFansMedalOwnerRoomId() {
|
||||||
|
if (info.get(3).getAsJsonArray().size() > 0) {
|
||||||
|
return Optional.of(info.get(3).getAsJsonArray().get(3).getAsString());
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获得用户的观众等级
|
||||||
|
public int getUserLevel() {
|
||||||
|
return info.get(4).getAsJsonArray().get(0).getAsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
//获得用户的观众等级排名
|
||||||
|
public String getUserRank() {
|
||||||
|
return info.get(4).getAsJsonArray().get(3).getAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//获得用户头衔
|
||||||
|
public List<String> getUserTitles() {
|
||||||
|
return GSON.fromJson(info.get(5), LIST_STRING_TYPE);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class EnterRoomEntity {
|
||||||
|
@SerializedName("roomid")
|
||||||
|
private int roomId;
|
||||||
|
@SerializedName("uid")
|
||||||
|
private int userId;
|
||||||
|
|
||||||
|
public EnterRoomEntity(int roomId, int userId) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRoomId() {
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomId(int roomId) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(int userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class LiveEntity {
|
||||||
|
/**
|
||||||
|
* cmd : LIVE
|
||||||
|
* roomid : 1110317
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("cmd")
|
||||||
|
private String cmd;
|
||||||
|
@SerializedName("roomid")
|
||||||
|
private String roomId;
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoomId() {
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomId(String roomId) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class PreparingEntity {
|
||||||
|
/**
|
||||||
|
* cmd : PREPARING
|
||||||
|
* roomid : 1110317
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("cmd")
|
||||||
|
private String cmd;
|
||||||
|
@SerializedName("roomid")
|
||||||
|
private String roomId;
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoomId() {
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomId(String roomId) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,605 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SendGiftEntity {
|
||||||
|
/**
|
||||||
|
* cmd : SEND_GIFT
|
||||||
|
* data : {"giftName":"辣条","num":64,"uname":"明暗纠结星","rcost":66347035,"uid":12768615,"top_list":[{"uid":9256,"userName":"SSR丶尧","coin":2905900,"face":"http://i0.hdslb.com/bfs/face/eba52abb1daaf3aecd7b986b9731451872d66613.jpg","guard_level":"3","rank":1,"score":2905900},{"uid":4986301,"userName":"乄夏沫丶","coin":1386000,"face":"http://i2.hdslb.com/bfs/face/b3969027a263d2610711317addf437fe59a9b97e.jpg","guard_level":0,"rank":2,"score":1386000},{"uid":5211302,"userName":"朝雾怜","coin":805700,"face":"http://i1.hdslb.com/bfs/face/d366be69d716469514d355642aa324ceba3fa122.jpg","guard_level":0,"rank":3,"score":805700}],"timestamp":1510498496,"giftId":1,"giftType":0,"action":"喂食","super":0,"price":100,"rnd":"1510498460","newMedal":0,"newTitle":0,"medal":[],"title":"","beatId":"0","biz_source":"live","metadata":"","remain":0,"gold":0,"silver":0,"eventScore":0,"eventNum":0,"smalltv_msg":[],"notice_msg":[],"capsule":{"normal":{"coin":13,"change":1,"progress":{"now":4000,"max":10000}},"colorful":{"coin":0,"change":0,"progress":{"now":0,"max":5000}}},"addFollow":0}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("cmd")
|
||||||
|
private String cmd;
|
||||||
|
@SerializedName("data")
|
||||||
|
private DataEntity data;
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataEntity getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(DataEntity data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DataEntity {
|
||||||
|
/**
|
||||||
|
* giftName : 辣条
|
||||||
|
* num : 64
|
||||||
|
* uname : 明暗纠结星
|
||||||
|
* rcost : 66347035
|
||||||
|
* uid : 12768615
|
||||||
|
* top_list : [{"uid":9256,"uname":"SSR丶尧","coin":2905900,"face":"http://i0.hdslb.com/bfs/face/eba52abb1daaf3aecd7b986b9731451872d66613.jpg","guard_level":"3","rank":1,"score":2905900},{"uid":4986301,"userName":"乄夏沫丶","coin":1386000,"face":"http://i2.hdslb.com/bfs/face/b3969027a263d2610711317addf437fe59a9b97e.jpg","guard_level":0,"rank":2,"score":1386000},{"uid":5211302,"userName":"朝雾怜","coin":805700,"face":"http://i1.hdslb.com/bfs/face/d366be69d716469514d355642aa324ceba3fa122.jpg","guard_level":0,"rank":3,"score":805700}]
|
||||||
|
* timestamp : 1510498496
|
||||||
|
* giftId : 1
|
||||||
|
* giftType : 0
|
||||||
|
* action : 喂食
|
||||||
|
* super : 0
|
||||||
|
* price : 100
|
||||||
|
* rnd : 1510498460
|
||||||
|
* newMedal : 0
|
||||||
|
* newTitle : 0
|
||||||
|
* medal : []
|
||||||
|
* title :
|
||||||
|
* beatId : 0
|
||||||
|
* biz_source : live
|
||||||
|
* metadata :
|
||||||
|
* remain : 0
|
||||||
|
* gold : 0
|
||||||
|
* silver : 0
|
||||||
|
* eventScore : 0
|
||||||
|
* eventNum : 0
|
||||||
|
* smalltv_msg : []
|
||||||
|
* notice_msg : []
|
||||||
|
* capsule : {"normal":{"coin":13,"change":1,"progress":{"now":4000,"max":10000}},"colorful":{"coin":0,"change":0,"progress":{"now":0,"max":5000}}}
|
||||||
|
* addFollow : 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("giftName")
|
||||||
|
private String giftName;
|
||||||
|
@SerializedName("num")
|
||||||
|
private int num;
|
||||||
|
@SerializedName("uname")
|
||||||
|
private String userName;
|
||||||
|
@SerializedName("rcost")
|
||||||
|
private int rCost;
|
||||||
|
@SerializedName("uid")
|
||||||
|
private int uid;
|
||||||
|
@SerializedName("timestamp")
|
||||||
|
private int timestamp;
|
||||||
|
@SerializedName("giftId")
|
||||||
|
private int giftId;
|
||||||
|
@SerializedName("giftType")
|
||||||
|
private int giftType;
|
||||||
|
@SerializedName("action")
|
||||||
|
private String action;
|
||||||
|
@SerializedName("super")
|
||||||
|
private int superX;
|
||||||
|
@SerializedName("price")
|
||||||
|
private int price;
|
||||||
|
@SerializedName("rnd")
|
||||||
|
private String rnd;
|
||||||
|
@SerializedName("newMedal")
|
||||||
|
private int newMedal;
|
||||||
|
@SerializedName("newTitle")
|
||||||
|
private int newTitle;
|
||||||
|
@SerializedName("title")
|
||||||
|
private String title;
|
||||||
|
@SerializedName("beatId")
|
||||||
|
private String beatId;
|
||||||
|
@SerializedName("biz_source")
|
||||||
|
private String bizSource;
|
||||||
|
@SerializedName("metadata")
|
||||||
|
private String metadata;
|
||||||
|
@SerializedName("remain")
|
||||||
|
private int remain;
|
||||||
|
@SerializedName("gold")
|
||||||
|
private int gold;
|
||||||
|
@SerializedName("silver")
|
||||||
|
private int silver;
|
||||||
|
@SerializedName("eventScore")
|
||||||
|
private int eventScore;
|
||||||
|
@SerializedName("eventNum")
|
||||||
|
private int eventNum;
|
||||||
|
@SerializedName("capsule")
|
||||||
|
private CapsuleEntity capsule;
|
||||||
|
@SerializedName("addFollow")
|
||||||
|
private int addFollow;
|
||||||
|
@SerializedName("top_list")
|
||||||
|
private List<TopListEntity> topList;
|
||||||
|
@SerializedName("medal")
|
||||||
|
private JsonElement medal;
|
||||||
|
@SerializedName("smalltv_msg")
|
||||||
|
private JsonElement smallTVMsg;
|
||||||
|
@SerializedName("notice_msg")
|
||||||
|
private List<?> noticeMsg;
|
||||||
|
|
||||||
|
public String getGiftName() {
|
||||||
|
return giftName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGiftName(String giftName) {
|
||||||
|
this.giftName = giftName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNum() {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNum(int num) {
|
||||||
|
this.num = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getrCost() {
|
||||||
|
return rCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setrCost(int rCost) {
|
||||||
|
this.rCost = rCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUid() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUid(int uid) {
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimestamp(int timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGiftId() {
|
||||||
|
return giftId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGiftId(int giftId) {
|
||||||
|
this.giftId = giftId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGiftType() {
|
||||||
|
return giftType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGiftType(int giftType) {
|
||||||
|
this.giftType = giftType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAction(String action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSuperX() {
|
||||||
|
return superX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuperX(int superX) {
|
||||||
|
this.superX = superX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPrice() {
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrice(int price) {
|
||||||
|
this.price = price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRnd() {
|
||||||
|
return rnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRnd(String rnd) {
|
||||||
|
this.rnd = rnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNewMedal() {
|
||||||
|
return newMedal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNewMedal(int newMedal) {
|
||||||
|
this.newMedal = newMedal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNewTitle() {
|
||||||
|
return newTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNewTitle(int newTitle) {
|
||||||
|
this.newTitle = newTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBeatId() {
|
||||||
|
return beatId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeatId(String beatId) {
|
||||||
|
this.beatId = beatId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBizSource() {
|
||||||
|
return bizSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBizSource(String bizSource) {
|
||||||
|
this.bizSource = bizSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMetadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMetadata(String metadata) {
|
||||||
|
this.metadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRemain() {
|
||||||
|
return remain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemain(int remain) {
|
||||||
|
this.remain = remain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGold() {
|
||||||
|
return gold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGold(int gold) {
|
||||||
|
this.gold = gold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSilver() {
|
||||||
|
return silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSilver(int silver) {
|
||||||
|
this.silver = silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEventScore() {
|
||||||
|
return eventScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEventScore(int eventScore) {
|
||||||
|
this.eventScore = eventScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEventNum() {
|
||||||
|
return eventNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEventNum(int eventNum) {
|
||||||
|
this.eventNum = eventNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CapsuleEntity getCapsule() {
|
||||||
|
return capsule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCapsule(CapsuleEntity capsule) {
|
||||||
|
this.capsule = capsule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAddFollow() {
|
||||||
|
return addFollow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddFollow(int addFollow) {
|
||||||
|
this.addFollow = addFollow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TopListEntity> getTopList() {
|
||||||
|
return topList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopList(List<TopListEntity> topList) {
|
||||||
|
this.topList = topList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonElement getMedal() {
|
||||||
|
return medal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMedal(JsonElement medal) {
|
||||||
|
this.medal = medal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonElement getSmallTVMsg() {
|
||||||
|
return smallTVMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSmallTVMsg(JsonObject smallTVMsg) {
|
||||||
|
this.smallTVMsg = smallTVMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<?> getNoticeMsg() {
|
||||||
|
return noticeMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNoticeMsg(List<?> noticeMsg) {
|
||||||
|
this.noticeMsg = noticeMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CapsuleEntity {
|
||||||
|
/**
|
||||||
|
* normal : {"coin":13,"change":1,"progress":{"now":4000,"max":10000}}
|
||||||
|
* colorful : {"coin":0,"change":0,"progress":{"now":0,"max":5000}}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("normal")
|
||||||
|
private NormalEntity normal;
|
||||||
|
@SerializedName("colorful")
|
||||||
|
private ColorfulEntity colorful;
|
||||||
|
|
||||||
|
public NormalEntity getNormal() {
|
||||||
|
return normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNormal(NormalEntity normal) {
|
||||||
|
this.normal = normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorfulEntity getColorful() {
|
||||||
|
return colorful;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColorful(ColorfulEntity colorful) {
|
||||||
|
this.colorful = colorful;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NormalEntity {
|
||||||
|
/**
|
||||||
|
* coin : 13
|
||||||
|
* change : 1
|
||||||
|
* progress : {"now":4000,"max":10000}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("coin")
|
||||||
|
private int coin;
|
||||||
|
@SerializedName("change")
|
||||||
|
private int change;
|
||||||
|
@SerializedName("progress")
|
||||||
|
private ProgressEntity progress;
|
||||||
|
|
||||||
|
public int getCoin() {
|
||||||
|
return coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCoin(int coin) {
|
||||||
|
this.coin = coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChange() {
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChange(int change) {
|
||||||
|
this.change = change;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressEntity getProgress() {
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgress(ProgressEntity progress) {
|
||||||
|
this.progress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ProgressEntity {
|
||||||
|
/**
|
||||||
|
* now : 4000
|
||||||
|
* max : 10000
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("now")
|
||||||
|
private int now;
|
||||||
|
@SerializedName("max")
|
||||||
|
private int max;
|
||||||
|
|
||||||
|
public int getNow() {
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNow(int now) {
|
||||||
|
this.now = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMax(int max) {
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ColorfulEntity {
|
||||||
|
/**
|
||||||
|
* coin : 0
|
||||||
|
* change : 0
|
||||||
|
* progress : {"now":0,"max":5000}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("coin")
|
||||||
|
private int coin;
|
||||||
|
@SerializedName("change")
|
||||||
|
private int change;
|
||||||
|
@SerializedName("progress")
|
||||||
|
private ProgressEntityX progress;
|
||||||
|
|
||||||
|
public int getCoin() {
|
||||||
|
return coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCoin(int coin) {
|
||||||
|
this.coin = coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChange() {
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChange(int change) {
|
||||||
|
this.change = change;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressEntityX getProgress() {
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgress(ProgressEntityX progress) {
|
||||||
|
this.progress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ProgressEntityX {
|
||||||
|
/**
|
||||||
|
* now : 0
|
||||||
|
* max : 5000
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("now")
|
||||||
|
private int now;
|
||||||
|
@SerializedName("max")
|
||||||
|
private int max;
|
||||||
|
|
||||||
|
public int getNow() {
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNow(int now) {
|
||||||
|
this.now = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMax(int max) {
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TopListEntity {
|
||||||
|
/**
|
||||||
|
* uid : 9256
|
||||||
|
* uname : SSR丶尧
|
||||||
|
* coin : 2905900
|
||||||
|
* face : http://i0.hdslb.com/bfs/face/eba52abb1daaf3aecd7b986b9731451872d66613.jpg
|
||||||
|
* guard_level : 3
|
||||||
|
* rank : 1
|
||||||
|
* score : 2905900
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("uid")
|
||||||
|
private int uid;
|
||||||
|
@SerializedName("uname")
|
||||||
|
private String userName;
|
||||||
|
@SerializedName("coin")
|
||||||
|
private int coin;
|
||||||
|
@SerializedName("face")
|
||||||
|
private String face;
|
||||||
|
@SerializedName("guard_level")
|
||||||
|
private String guardLevel;
|
||||||
|
@SerializedName("rank")
|
||||||
|
private int rank;
|
||||||
|
@SerializedName("score")
|
||||||
|
private int score;
|
||||||
|
|
||||||
|
public int getUid() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUid(int uid) {
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCoin() {
|
||||||
|
return coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCoin(int coin) {
|
||||||
|
this.coin = coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFace() {
|
||||||
|
return face;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFace(String face) {
|
||||||
|
this.face = face;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGuardLevel() {
|
||||||
|
return guardLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGuardLevel(String guardLevel) {
|
||||||
|
this.guardLevel = guardLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRank() {
|
||||||
|
return rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRank(int rank) {
|
||||||
|
this.rank = rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScore() {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScore(int score) {
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class SysGiftEntity {
|
||||||
|
/**
|
||||||
|
* cmd : SYS_GIFT
|
||||||
|
* msg : あさひなみよう在直播间5135178开启了丰收祭典,一起来分享收获的福利吧!
|
||||||
|
* msg_text : あさひなみよう在直播间5135178开启了丰收祭典,一起来分享收获的福利吧!
|
||||||
|
* tips : あさひなみよう在直播间5135178开启了丰收祭典,一起来分享收获的福利吧!
|
||||||
|
* url : http://live.bilibili.com/5135178
|
||||||
|
* roomid : 5135178
|
||||||
|
* real_roomid : 5135178
|
||||||
|
* giftId : 103
|
||||||
|
* msgTips : 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("cmd")
|
||||||
|
private String cmd;
|
||||||
|
@SerializedName("msg")
|
||||||
|
private String msg;
|
||||||
|
@SerializedName("msg_text")
|
||||||
|
private String msgText;
|
||||||
|
@SerializedName("tips")
|
||||||
|
private String tips;
|
||||||
|
@SerializedName("url")
|
||||||
|
private String url;
|
||||||
|
@SerializedName("roomid")
|
||||||
|
private int roomId;
|
||||||
|
@SerializedName("real_roomid")
|
||||||
|
private int realRoomId;
|
||||||
|
@SerializedName("giftId")
|
||||||
|
private int giftId;
|
||||||
|
@SerializedName("msgTips")
|
||||||
|
private int msgTips;
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsg(String msg) {
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsgText() {
|
||||||
|
return msgText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsgText(String msgText) {
|
||||||
|
this.msgText = msgText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTips() {
|
||||||
|
return tips;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTips(String tips) {
|
||||||
|
this.tips = tips;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRoomId() {
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomId(int roomId) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRealRoomId() {
|
||||||
|
return realRoomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealRoomId(int realRoomId) {
|
||||||
|
this.realRoomId = realRoomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGiftId() {
|
||||||
|
return giftId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGiftId(int giftId) {
|
||||||
|
this.giftId = giftId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMsgTips() {
|
||||||
|
return msgTips;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsgTips(int msgTips) {
|
||||||
|
this.msgTips = msgTips;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class SysMSGEntity {
|
||||||
|
/**
|
||||||
|
* cmd : SYS_MSG
|
||||||
|
* msg : 【瑾然-】:?在直播间:?【3939852】:?赠送 小电视一个,请前往抽奖
|
||||||
|
* msg_text : 【瑾然-】:?在直播间:?【3939852】:?赠送 小电视一个,请前往抽奖
|
||||||
|
* rep : 1
|
||||||
|
* styleType : 2
|
||||||
|
* url : http://live.bilibili.com/3939852
|
||||||
|
* roomid : 3939852
|
||||||
|
* real_roomid : 3939852
|
||||||
|
* rnd : 1510499432
|
||||||
|
* tv_id : 29318
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("cmd")
|
||||||
|
private String cmd;
|
||||||
|
@SerializedName("msg")
|
||||||
|
private String msg;
|
||||||
|
//B站自己的广告, msgText 可能是空的
|
||||||
|
@SerializedName("msg_text")
|
||||||
|
private String msgText;
|
||||||
|
@SerializedName("rep")
|
||||||
|
private int rep;
|
||||||
|
@SerializedName("styleType")
|
||||||
|
private int styleType;
|
||||||
|
@SerializedName("url")
|
||||||
|
private String url;
|
||||||
|
@SerializedName("roomid")
|
||||||
|
private int roomId;
|
||||||
|
@SerializedName("real_roomid")
|
||||||
|
private int realRoomId;
|
||||||
|
@SerializedName("rnd")
|
||||||
|
private int rnd;
|
||||||
|
@SerializedName("tv_id")
|
||||||
|
private String tvId;
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsg(String msg) {
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsgText() {
|
||||||
|
return msgText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsgText(String msgText) {
|
||||||
|
this.msgText = msgText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRep() {
|
||||||
|
return rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRep(int rep) {
|
||||||
|
this.rep = rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStyleType() {
|
||||||
|
return styleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStyleType(int styleType) {
|
||||||
|
this.styleType = styleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRoomId() {
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomId(int roomId) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRealRoomId() {
|
||||||
|
return realRoomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealRoomId(int realRoomId) {
|
||||||
|
this.realRoomId = realRoomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRnd() {
|
||||||
|
return rnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRnd(int rnd) {
|
||||||
|
this.rnd = rnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTvId() {
|
||||||
|
return tvId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTvId(String tvId) {
|
||||||
|
this.tvId = tvId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class WelcomeEntity {
|
||||||
|
/**
|
||||||
|
* cmd : WELCOME
|
||||||
|
* data : {"uid":516505,"uname":"圣蝎","is_admin":false,"vip":1}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("cmd")
|
||||||
|
private String cmd;
|
||||||
|
@SerializedName("data")
|
||||||
|
private DataEntity data;
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataEntity getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(DataEntity data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DataEntity {
|
||||||
|
/**
|
||||||
|
* uid : 516505
|
||||||
|
* uname : 圣蝎
|
||||||
|
* is_admin : false
|
||||||
|
* vip : 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("uid")
|
||||||
|
private int uid;
|
||||||
|
@SerializedName("uname")
|
||||||
|
private String userName;
|
||||||
|
@SerializedName("is_admin")
|
||||||
|
private boolean isAdmin;
|
||||||
|
@SerializedName("vip")
|
||||||
|
private int vip;
|
||||||
|
|
||||||
|
public int getUid() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUid(int uid) {
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserName(String userName) {
|
||||||
|
this.userName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIsAdmin() {
|
||||||
|
return isAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsAdmin(boolean isAdmin) {
|
||||||
|
this.isAdmin = isAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVip() {
|
||||||
|
return vip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVip(int vip) {
|
||||||
|
this.vip = vip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package com.hiczp.bilibili.api.live.socket.entity;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class WelcomeGuardEntity {
|
||||||
|
/**
|
||||||
|
* cmd : WELCOME_GUARD
|
||||||
|
* data : {"uid":23598108,"username":"lovevael","guard_level":3,"water_god":0}
|
||||||
|
* roomid : 43001
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("cmd")
|
||||||
|
private String cmd;
|
||||||
|
@SerializedName("data")
|
||||||
|
private DataEntity data;
|
||||||
|
@SerializedName("roomid")
|
||||||
|
private int roomId;
|
||||||
|
|
||||||
|
public String getCmd() {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCmd(String cmd) {
|
||||||
|
this.cmd = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataEntity getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(DataEntity data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRoomId() {
|
||||||
|
return roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoomId(int roomId) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DataEntity {
|
||||||
|
/**
|
||||||
|
* uid : 23598108
|
||||||
|
* username : lovevael
|
||||||
|
* guard_level : 3
|
||||||
|
* water_god : 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SerializedName("uid")
|
||||||
|
private int uid;
|
||||||
|
@SerializedName("username")
|
||||||
|
private String username;
|
||||||
|
@SerializedName("guard_level")
|
||||||
|
private int guardLevel;
|
||||||
|
@SerializedName("water_god")
|
||||||
|
private int waterGod;
|
||||||
|
|
||||||
|
public int getUid() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUid(int uid) {
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGuardLevel() {
|
||||||
|
return guardLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGuardLevel(int guardLevel) {
|
||||||
|
this.guardLevel = guardLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWaterGod() {
|
||||||
|
return waterGod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWaterGod(int waterGod) {
|
||||||
|
this.waterGod = waterGod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
156
src/test/java/com/hiczp/bilibili/api/test/LiveRoomTest.java
Normal file
156
src/test/java/com/hiczp/bilibili/api/test/LiveRoomTest.java
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package com.hiczp.bilibili.api.test;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.hiczp.bilibili.api.BilibiliRESTAPI;
|
||||||
|
import com.hiczp.bilibili.api.live.entity.BulletScreenEntity;
|
||||||
|
import com.hiczp.bilibili.api.live.entity.LiveRoomInfoEntity;
|
||||||
|
import com.hiczp.bilibili.api.live.entity.SendBulletScreenResponseEntity;
|
||||||
|
import com.hiczp.bilibili.api.live.socket.BulletScreenListenerAdaptor;
|
||||||
|
import com.hiczp.bilibili.api.live.socket.LiveClient;
|
||||||
|
import com.hiczp.bilibili.api.live.socket.PackageRepository;
|
||||||
|
import com.hiczp.bilibili.api.live.socket.Utils;
|
||||||
|
import com.hiczp.bilibili.api.live.socket.entity.*;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
public class LiveRoomTest {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(LiveRoomTest.class);
|
||||||
|
private static final Config CONFIG = Config.getInstance();
|
||||||
|
private static final int USER_ID = BilibiliRESTAPI.getMid();
|
||||||
|
private static final int STOP_AFTER_N_HEART_BEATS = 3;
|
||||||
|
private static final int STOP_AFTER_SECOND = 90;
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
@Test
|
||||||
|
public void _0socketTest() throws IOException {
|
||||||
|
LOGGER.info("Start socket connection to live Bullet Screen stream server, test continue for {} heart beat", STOP_AFTER_N_HEART_BEATS);
|
||||||
|
LiveRoomInfoEntity.LiveRoomEntity liveRoomEntity = BilibiliRESTAPI.getLiveService().getRoomInfo(CONFIG.getRoomId()).execute().body().getData();
|
||||||
|
int roomId = liveRoomEntity.getRoomId();
|
||||||
|
|
||||||
|
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(liveRoomEntity.getCmt(), liveRoomEntity.getCmtPortGoim()));
|
||||||
|
socketChannel.write(PackageRepository.createEnterRoomPackage(roomId, USER_ID));
|
||||||
|
Thread thread = new Thread(() -> {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Utils.printBytes(PackageRepository.readNextPackage(socketChannel).array());
|
||||||
|
System.out.println();
|
||||||
|
} catch (IOException e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
|
||||||
|
for (int i = STOP_AFTER_N_HEART_BEATS; i > 0; i--) {
|
||||||
|
socketChannel.write(PackageRepository.createHeartBeatPackage(roomId, USER_ID));
|
||||||
|
LOGGER.debug("Send heart beat package");
|
||||||
|
BilibiliRESTAPI.getLiveService().sendBulletScreen(new BulletScreenEntity(roomId, "send heart beat")).enqueue(new Callback<SendBulletScreenResponseEntity>() {
|
||||||
|
private Gson gson = new Gson();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<SendBulletScreenResponseEntity> call, Response<SendBulletScreenResponseEntity> response) {
|
||||||
|
gson.toJson(response.body(), System.out);
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<SendBulletScreenResponseEntity> call, Throwable throwable) {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
Thread.sleep(30 * 1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
socketChannel.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void _1liveClientTest() throws IOException {
|
||||||
|
int roomId = CONFIG.getRoomId();
|
||||||
|
LOGGER.info("Start LiveClientTest for room {}", roomId);
|
||||||
|
LiveClient liveClient = new LiveClient(roomId, USER_ID)
|
||||||
|
.addListener(new BulletScreenListenerAdaptor() {
|
||||||
|
@Override
|
||||||
|
public void onConnect() {
|
||||||
|
LOGGER.info("Connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisconnect() {
|
||||||
|
LOGGER.info("Disconnected");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewerCountPackage(int viewerCount) {
|
||||||
|
LOGGER.info("Current viewers: {}", viewerCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDanMuMSGPackage(DanMuMSGEntity danMuMSGEntity) {
|
||||||
|
LOGGER.info("[{}]{}", danMuMSGEntity.getUsername(), danMuMSGEntity.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSendGiftPackage(SendGiftEntity sendGiftEntity) {
|
||||||
|
SendGiftEntity.DataEntity dataEntity = sendGiftEntity.getData();
|
||||||
|
LOGGER.info("{} send {} * {}", dataEntity.getUserName(), dataEntity.getGiftName(), dataEntity.getNum());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSysMSGPackage(SysMSGEntity sysMSGEntity) {
|
||||||
|
LOGGER.info("System message: {} {}", sysMSGEntity.getMsg(), sysMSGEntity.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSysGiftPackage(SysGiftEntity sysGiftEntity) {
|
||||||
|
LOGGER.info("System gift: {} {}", sysGiftEntity.getMsg(), sysGiftEntity.getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWelcomePackage(WelcomeEntity welcomeEntity) {
|
||||||
|
LOGGER.info("Welcome {}", welcomeEntity.getData().getUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWelcomeGuardPackage(WelcomeGuardEntity welcomeGuardEntity) {
|
||||||
|
WelcomeGuardEntity.DataEntity dataEntity = welcomeGuardEntity.getData();
|
||||||
|
LOGGER.info("Welcome guard [Lv{}]{}", dataEntity.getGuardLevel(), dataEntity.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLivePackage(LiveEntity liveEntity) {
|
||||||
|
LOGGER.info("Room {} start live", liveEntity.getRoomId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPreparingPackage(PreparingEntity preparingEntity) {
|
||||||
|
LOGGER.info("Room {} stop live", preparingEntity.getRoomId());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.connect();
|
||||||
|
try {
|
||||||
|
Thread.sleep(STOP_AFTER_SECOND * 1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
liveClient.close();
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder;
|
|||||||
import com.hiczp.bilibili.api.BilibiliRESTAPI;
|
import com.hiczp.bilibili.api.BilibiliRESTAPI;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.FixMethodOrder;
|
import org.junit.FixMethodOrder;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runners.MethodSorters;
|
import org.junit.runners.MethodSorters;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -34,6 +35,7 @@ public class LoginTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
@Test
|
@Test
|
||||||
public void _2refreshToken() throws Exception {
|
public void _2refreshToken() throws Exception {
|
||||||
LOGGER.info("Refreshing token");
|
LOGGER.info("Refreshing token");
|
||||||
|
@ -14,6 +14,7 @@ import java.io.InputStreamReader;
|
|||||||
@Suite.SuiteClasses({
|
@Suite.SuiteClasses({
|
||||||
LoginTest.class,
|
LoginTest.class,
|
||||||
LiveServiceTest.class,
|
LiveServiceTest.class,
|
||||||
|
LiveRoomTest.class,
|
||||||
LogoutTest.class
|
LogoutTest.class
|
||||||
})
|
})
|
||||||
public class RuleSuite {
|
public class RuleSuite {
|
||||||
|
Loading…
Reference in New Issue
Block a user