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")
|
||||
private String message;
|
||||
|
||||
//在 web 端发送弹幕, 该字段是固定的, 为用户进入直播页面的时间的时间戳. 但是在 Android 端, 这是一个随机数
|
||||
//该随机数不包括符号位有 9 位
|
||||
@SerializedName("rnd")
|
||||
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 org.junit.After;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.slf4j.Logger;
|
||||
@ -34,6 +35,7 @@ public class LoginTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void _2refreshToken() throws Exception {
|
||||
LOGGER.info("Refreshing token");
|
||||
|
@ -14,6 +14,7 @@ import java.io.InputStreamReader;
|
||||
@Suite.SuiteClasses({
|
||||
LoginTest.class,
|
||||
LiveServiceTest.class,
|
||||
LiveRoomTest.class,
|
||||
LogoutTest.class
|
||||
})
|
||||
public class RuleSuite {
|
||||
|
Loading…
Reference in New Issue
Block a user