完善直播WebSocket相关内容
完善弹幕解析
This commit is contained in:
parent
54ac47c8b4
commit
9521e9d5c8
@ -22,5 +22,11 @@
|
||||
<artifactId>rxjava</artifactId>
|
||||
<version>3.1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aayushatharva.brotli4j</groupId>
|
||||
<artifactId>brotli4j</artifactId>
|
||||
<version>1.16.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
@ -5,6 +5,7 @@ import com.yutou.bili.api.LiveApi;
|
||||
import com.yutou.bili.api.UserApi;
|
||||
import com.yutou.bili.bean.live.LiveRoomConfig;
|
||||
import com.yutou.bili.bean.live.LiveRoomPlayInfo;
|
||||
import com.yutou.bili.bean.live.SpiBean;
|
||||
import com.yutou.bili.bean.login.LoginCookie;
|
||||
import com.yutou.bili.bean.login.UserInfoBean;
|
||||
import com.yutou.bili.enums.LiveProtocol;
|
||||
@ -17,35 +18,42 @@ import com.yutou.bili.databases.BiliBiliLoginDatabase;
|
||||
import com.yutou.bili.net.BiliUserNetApiManager;
|
||||
import com.yutou.bili.net.WebSocketManager;
|
||||
import com.yutou.inter.IHttpApiCheckCallback;
|
||||
import com.yutou.okhttp.BaseBean;
|
||||
import com.yutou.okhttp.FileCallback;
|
||||
import com.yutou.okhttp.HttpCallback;
|
||||
import com.yutou.okhttp.HttpLoggingInterceptor;
|
||||
import com.yutou.utils.Log;
|
||||
import jakarta.xml.bind.DatatypeConverter;
|
||||
import okhttp3.Headers;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
HttpLoggingInterceptor.setLog(false);
|
||||
HttpLoggingInterceptor.setLog(true);
|
||||
getPlayUrl();
|
||||
//testSocket();
|
||||
|
||||
// getPlayUrl();
|
||||
LiveRoomConfig config=new LiveRoomConfig();
|
||||
LoginCookie cookie = BiliBiliLoginDatabase.getInstance().get();
|
||||
config.setLogin(true);
|
||||
config.setUid(cookie.getDedeUserID());
|
||||
config.setRoomId(String.valueOf(855204));
|
||||
config.setRoomId(String.valueOf(22642754));
|
||||
config.setRoomId(String.valueOf(81004));
|
||||
WebSocketManager.getInstance().addRoom(config);
|
||||
}
|
||||
|
||||
|
||||
public static void testSocket() {
|
||||
public static void testSocket(SpiBean spi) {
|
||||
try {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("roomid", "13246789");
|
||||
// json.put("roomid", "32805602");
|
||||
json.put("roomid", "855204");
|
||||
json.put("protover", "3");
|
||||
json.put("platform", "web");
|
||||
json.put("type", 2);
|
||||
json.put("buvid",spi.getB_3());
|
||||
json.put("key", "aaaabbb");
|
||||
Log.i(json);
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
// outputStream.write(toLH(json.toString().length() + 16));
|
||||
outputStream.write(new byte[]{0, 0, 1, 68, 0, 16, 0, 1, 0, 0, 0, 7, 0, 0, 0, 1});
|
||||
@ -76,7 +84,7 @@ public class Main {
|
||||
.getApi(new IHttpApiCheckCallback<LiveApi>() {
|
||||
@Override
|
||||
public void onSuccess(LiveApi api) {
|
||||
String roomId = "22689676";
|
||||
String roomId = "32805602";
|
||||
String mid = "68057278";
|
||||
|
||||
// roomId="42062";
|
||||
|
@ -5,10 +5,7 @@ import com.yutou.okhttp.BaseBean;
|
||||
import com.yutou.okhttp.FileBody;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Query;
|
||||
import retrofit2.http.Streaming;
|
||||
import retrofit2.http.Url;
|
||||
import retrofit2.http.*;
|
||||
|
||||
/**
|
||||
* 直播间相关API
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.yutou.bili.api;
|
||||
|
||||
import com.yutou.bili.bean.live.SpiBean;
|
||||
import com.yutou.bili.bean.login.UserInfoBean;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
import retrofit2.Call;
|
||||
@ -8,4 +9,8 @@ import retrofit2.http.GET;
|
||||
public interface UserApi {
|
||||
@GET("/x/web-interface/nav")
|
||||
Call<HttpBody<UserInfoBean>> getUserInfo();
|
||||
|
||||
|
||||
@GET("/x/frontend/finger/spi")
|
||||
Call<HttpBody<SpiBean>> getFingerSpi();
|
||||
}
|
||||
|
12
biliapi/src/main/java/com/yutou/bili/bean/live/SpiBean.java
Normal file
12
biliapi/src/main/java/com/yutou/bili/bean/live/SpiBean.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.yutou.bili.bean.live;
|
||||
|
||||
import com.yutou.okhttp.BaseBean;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class SpiBean extends BaseBean {
|
||||
private String b_3;
|
||||
private String b_4;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.yutou.bili.bean.websocket;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class WebSocketBody {
|
||||
List<JSONObject> bodyList;
|
||||
|
||||
public WebSocketBody(byte[] bytes) {
|
||||
bodyList = new ArrayList<>();
|
||||
addBody(bytes, 0);
|
||||
}
|
||||
|
||||
private void addBody(byte[] bytes, int offset) {
|
||||
if (offset >= bytes.length) {
|
||||
return;
|
||||
}
|
||||
byte[] headerByte = new byte[16];
|
||||
System.arraycopy(bytes, offset, headerByte, 0, headerByte.length);
|
||||
WebSocketHeader header = new WebSocketHeader(headerByte);
|
||||
byte[] data = new byte[header.getDataSize() - header.getHeaderSize()];
|
||||
System.arraycopy(bytes, offset + header.getHeaderSize(), data, 0, data.length);
|
||||
try {
|
||||
bodyList.add(JSONObject.parseObject(new String(data)));
|
||||
} catch (Exception e) {
|
||||
System.out.println(header + "|" + new String(data));
|
||||
}
|
||||
addBody(bytes, offset + header.dataSize);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.yutou.bili.bean.websocket;
|
||||
|
||||
import com.yutou.bili.utils.BytesUtils;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WebSocketHeader {
|
||||
int dataSize;
|
||||
int agree;
|
||||
int headerSize;
|
||||
int cmdData;
|
||||
|
||||
public WebSocketHeader(byte[] bytes) {
|
||||
byte[] size = new byte[4];
|
||||
byte[] header = new byte[4];
|
||||
byte[] cmd = new byte[4];
|
||||
byte[] agreement = new byte[4];
|
||||
System.arraycopy(bytes, 0, size, 0, 4);
|
||||
System.arraycopy(bytes, 8, cmd, 0, 4);
|
||||
System.arraycopy(bytes, 6, agreement, 2, 2);
|
||||
System.arraycopy(bytes, 4, header, 2, 2);
|
||||
dataSize = BytesUtils.bytesToInt2(size, 0);
|
||||
agree = BytesUtils.bytesToInt2(agreement, 0);
|
||||
headerSize = BytesUtils.bytesToInt2(header, 0);
|
||||
cmdData = BytesUtils.bytesToInt2(cmd, 0);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.yutou.utils.Log;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 弹幕信息
|
||||
* <a href="https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/live/message_stream.md#%E5%BC%B9%E5%B9%95">弹幕</a>
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class WSDanmuData extends WSData {
|
||||
private String dm_v2;
|
||||
private int id;
|
||||
private int model;// 1~3 滚动弹幕 4 底端弹幕 5 顶端弹幕 6 逆向弹幕 7 精准定位 8 高级弹幕
|
||||
private int fontSize;
|
||||
private String fontColor;
|
||||
private long time;
|
||||
private String uCode;
|
||||
private String danmu;
|
||||
private long uid;
|
||||
private String uname;
|
||||
private WSUserMedal medal;
|
||||
|
||||
public WSDanmuData(JSONObject json) {
|
||||
super(json);
|
||||
JSONArray infoData = json.getJSONArray("info");
|
||||
setModel(infoData.getJSONArray(0).getInteger(1));
|
||||
setFontSize(infoData.getJSONArray(0).getInteger(2));
|
||||
setFontColor(Integer.toHexString(infoData.getJSONArray(0).getInteger(3)));
|
||||
setTime(infoData.getJSONArray(0).getLong(4));
|
||||
setUCode(infoData.getJSONArray(0).getString(7));
|
||||
setDanmu(infoData.getString(1));
|
||||
setUid(infoData.getJSONArray(2).getInteger(0));
|
||||
setUname(infoData.getJSONArray(2).getString(1));
|
||||
try {
|
||||
medal = WSUserMedal.create(infoData.getJSONArray(3));
|
||||
} catch (Exception e) {
|
||||
Log.i("弹幕信息解析失败:" + json);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "弹幕 = " + "用户:" + getUname() + " 发送了: " + getDanmu() +" | json = "+jsonSrc;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class WSData implements Serializable {
|
||||
public String cmd;
|
||||
public String jsonSrc;
|
||||
public long ws_timer;
|
||||
|
||||
@Deprecated
|
||||
public WSData() {
|
||||
throw new NullPointerException("需要传入json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WSData{" +
|
||||
"cmd='" + cmd + '\'' +
|
||||
", jsonSrc='" + jsonSrc + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public WSData(JSONObject json) {
|
||||
this.cmd = json.getString("cmd");
|
||||
ws_timer = System.currentTimeMillis();
|
||||
this.jsonSrc = json.toString();
|
||||
}
|
||||
|
||||
public static WSData parse(JSONObject json) {
|
||||
String cmd = json.getString("cmd");
|
||||
return switch (cmd) {
|
||||
case "DANMU_MSG" -> new WSDanmuData(json);
|
||||
case "DM_INTERACTION" -> new WSDmInteraction(json);
|
||||
case "SEND_GIFT" -> new WSSendGift(json);
|
||||
case "INTERACT_WORD" -> new WSInteractWord(json);
|
||||
case "GUARD_BUY" -> new WSGuardBuy(json);
|
||||
default -> new WSData(json);
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 连续弹幕消息
|
||||
* <a href="https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/live/message_stream.md#%E8%BF%9E%E7%BB%AD%E5%BC%B9%E5%B9%95%E6%B6%88%E6%81%AF">连续弹幕消息</a>
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class WSDmInteraction extends WSData{
|
||||
public final static int TYPE_ZAN=106;//点赞
|
||||
public final static int TYPE_SHARE=105;//分享
|
||||
public final static int TYPE_DANMU=102;//弹幕
|
||||
private ComboData combo;
|
||||
private int type;
|
||||
|
||||
public static void main(String[] args) {
|
||||
JSONObject json=JSONObject.parseObject("{\"cmd\":\"DM_INTERACTION\",\"data\":{\"data\":\"{\\\"fade_duration\\\":10000,\\\"cnt\\\":5,\\\"card_appear_interval\\\":0,\\\"suffix_text\\\":\\\"人正在点赞\\\",\\\"reset_cnt\\\":1,\\\"display_flag\\\":1}\",\"dmscore\":36,\"id\":53793047788032,\"status\":4,\"type\":106}}");
|
||||
WSDmInteraction wsDmInteraction=new WSDmInteraction(json);
|
||||
System.out.println(wsDmInteraction);
|
||||
}
|
||||
public WSDmInteraction(JSONObject json) {
|
||||
super(json);
|
||||
JSONObject data=json.getJSONObject("data");
|
||||
JSONObject comboJson=JSONObject.parseObject(data.getString("data"));
|
||||
combo=JSONObject.parseObject(data.getString("data"), ComboData.class);
|
||||
type=data.getIntValue("type");
|
||||
if(type==106){
|
||||
combo.setContent(comboJson.getString("suffix_text"));
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class ComboData implements Serializable {
|
||||
String content;
|
||||
String guide;
|
||||
int cnt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WSDmInteraction{" +
|
||||
"combo=" + combo +
|
||||
", cmd='" + cmd + '\'' +
|
||||
", jsonSrc='" + jsonSrc + '\'' +
|
||||
", ws_timer=" + ws_timer +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 大航海购买
|
||||
* <a href="https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/live/message_stream.md#%E4%B8%8A%E8%88%B0%E9%80%9A%E7%9F%A5">上舰通知</a>
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class WSGuardBuy extends WSData{
|
||||
private long uid;
|
||||
private String username;
|
||||
private long guardLevel;
|
||||
private long num;
|
||||
private long price;
|
||||
private long giftID;
|
||||
private String giftName;
|
||||
private long startTime;
|
||||
private long endTime;
|
||||
|
||||
public static void main(String[] args) {
|
||||
JSONObject json=JSONObject.parseObject("{\"cmd\":\"GUARD_BUY\",\"data\":{\"uid\":5427372,\"username\":\"李湜渰\",\"guard_level\":3,\"num\":1,\"price\":198000,\"gift_id\":10003,\"gift_name\":\"舰长\",\"start_time\":1724985039,\"end_time\":1724985039}}");
|
||||
WSGuardBuy wsguardBuy = new WSGuardBuy(json);
|
||||
System.out.println(wsguardBuy);
|
||||
}
|
||||
public WSGuardBuy(JSONObject json) {
|
||||
super(json);
|
||||
JSONObject data = json.getJSONObject("data");
|
||||
uid = data.getLong("uid");
|
||||
username = data.getString("username");
|
||||
guardLevel = data.getLong("guard_level");
|
||||
num = data.getLong("num");
|
||||
price = data.getLong("price");
|
||||
giftID = data.getLong("gift_id");
|
||||
giftName = data.getString("gift_name");
|
||||
startTime = data.getLong("start_time");
|
||||
endTime = data.getLong("end_time");
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 进场信息
|
||||
* <a href="https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/live/message_stream.md#%E8%BF%9B%E5%9C%BA%E6%88%96%E5%85%B3%E6%B3%A8%E6%B6%88%E6%81%AF">进场</a>
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class WSInteractWord extends WSData {
|
||||
public final static int TYPE_ENTER = 1;
|
||||
public final static int TYPE_FOLLOW = 2;
|
||||
private int type; //1为进场,2为关注
|
||||
private long roomId;
|
||||
private long timer;
|
||||
private WSUserMedal medal;
|
||||
private long uid;
|
||||
private String uname;
|
||||
private String uname_color;
|
||||
private String face;
|
||||
|
||||
|
||||
public WSInteractWord(JSONObject json) {
|
||||
super(json);
|
||||
JSONObject data = json.getJSONObject("data");
|
||||
JSONObject medalJson = data.containsKey("fans_medal") ? data.getJSONObject("fans_medal"):null;
|
||||
type = data.getIntValue("msg_type");
|
||||
roomId = data.getLong("roomid");
|
||||
timer = data.getLong("score");
|
||||
uid = data.getLong("uid");
|
||||
uname = data.getString("uname");
|
||||
uname_color = data.getString("uname_color");
|
||||
face = data.getJSONObject("uinfo").getJSONObject("base").getString("face");
|
||||
if (medalJson != null) {
|
||||
medal = new WSUserMedal();
|
||||
medal.setUid(medalJson.getLong("anchor_roomid"));
|
||||
medal.setMedal_name(medalJson.getString("medal_name"));
|
||||
medal.setMedal_color(Integer.toHexString(medalJson.getIntValue("medal_color")));
|
||||
medal.setMedal_level(medalJson.getIntValue("medal_level"));
|
||||
}
|
||||
}
|
||||
|
||||
public String getUname_color() {
|
||||
if (StringUtils.hasLength(uname_color)) {
|
||||
uname_color = "FFFFFF";
|
||||
}
|
||||
return uname_color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WSInteractWord{" +
|
||||
"type=" + type +
|
||||
", roomId=" + roomId +
|
||||
", timer=" + timer +
|
||||
", medal=" + medal +
|
||||
", uid=" + uid +
|
||||
", uname='" + uname + '\'' +
|
||||
", uname_color='" + uname_color + '\'' +
|
||||
", face='" + face + '\'' +
|
||||
", cmd='" + cmd + '\'' +
|
||||
", jsonSrc='" + jsonSrc + '\'' +
|
||||
", ws_timer=" + ws_timer +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.yutou.okhttp.BaseBean;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class WSMedalInfo extends BaseBean {
|
||||
@JSONField(name = "anchor_roomid")
|
||||
private long anchorRoomid;
|
||||
@JSONField(name = "anchor_uname")
|
||||
private String anchorUname;
|
||||
@JSONField(name = "guard_level")
|
||||
private long guardLevel;
|
||||
@JSONField(name = "icon_id")
|
||||
private long iconID;
|
||||
@JSONField(name = "is_lighted")
|
||||
private long isLighted;
|
||||
@JSONField(name = "medal_color")
|
||||
private long medalColor;
|
||||
@JSONField(name = "medal_color_border")
|
||||
private long medalColorBorder;
|
||||
@JSONField(name = "medal_color_end")
|
||||
private long medalColorEnd;
|
||||
@JSONField(name = "medal_color_start")
|
||||
private long medalColorStart;
|
||||
@JSONField(name = "medal_level")
|
||||
private long medalLevel;
|
||||
@JSONField(name = "medal_name")
|
||||
private String medalName;
|
||||
@JSONField(name = "special")
|
||||
private String special;
|
||||
@JSONField(name = "target_id")
|
||||
private long targetID;
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@lombok.Data
|
||||
public class WSSendGift extends WSData {
|
||||
private Data data;
|
||||
|
||||
public WSSendGift(JSONObject json) {
|
||||
super(json);
|
||||
data = JSONObject.parseObject(json.getJSONObject("data").toString(), Data.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WSSendGift{" +
|
||||
"data=" + data +
|
||||
", cmd='" + cmd + '\'' +
|
||||
", jsonSrc='" + jsonSrc + '\'' +
|
||||
", ws_timer=" + ws_timer +
|
||||
'}';
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
public static class Data implements Serializable {
|
||||
@JSONField(name = "action")
|
||||
private String action;
|
||||
@JSONField(name = "batch_combo_id")
|
||||
private String batchComboID;
|
||||
@JSONField(name = "batch_combo_send")
|
||||
private ComboSend batchComboSend;
|
||||
@JSONField(name = "combo_send")
|
||||
private ComboSend comboSend;
|
||||
@JSONField(name = "beatId")
|
||||
private String beatID;
|
||||
@JSONField(name = "biz_source")
|
||||
private String bizSource;
|
||||
@JSONField(name = "broadcast_id")
|
||||
private long broadcastID;
|
||||
@JSONField(name = "coin_type")
|
||||
private String coinType;
|
||||
@JSONField(name = "combo_resources_id")
|
||||
private long comboResourcesID;
|
||||
@JSONField(name = "combo_stay_time")
|
||||
private long comboStayTime;
|
||||
@JSONField(name = "combo_total_coin")
|
||||
private long comboTotalCoin;
|
||||
@JSONField(name = "crit_prob")
|
||||
private long critProb;
|
||||
@JSONField(name = "demarcation")
|
||||
private long demarcation;
|
||||
@JSONField(name = "discount_price")
|
||||
private long discountPrice;
|
||||
@JSONField(name = "dmscore")
|
||||
private long dmscore;
|
||||
@JSONField(name = "draw")
|
||||
private long draw;
|
||||
@JSONField(name = "effect")
|
||||
private long effect;
|
||||
@JSONField(name = "effect_block")
|
||||
private long effectBlock;
|
||||
@JSONField(name = "face")
|
||||
private String face;
|
||||
@JSONField(name = "face_effect_id")
|
||||
private long faceEffectID;
|
||||
@JSONField(name = "face_effect_type")
|
||||
private long faceEffectType;
|
||||
@JSONField(name = "face_effect_v2")
|
||||
private FaceEffectV2 faceEffectV2;
|
||||
@JSONField(name = "float_sc_resource_id")
|
||||
private long floatScResourceID;
|
||||
@JSONField(name = "giftId")
|
||||
private long giftID;
|
||||
@JSONField(name = "giftName")
|
||||
private String giftName;
|
||||
@JSONField(name = "giftType")
|
||||
private long giftType;
|
||||
@JSONField(name = "gift_info")
|
||||
private GiftInfo giftInfo;
|
||||
@JSONField(name = "gift_tag")
|
||||
private List<Long> giftTag;
|
||||
@JSONField(name = "gold")
|
||||
private long gold;
|
||||
@JSONField(name = "guard_level")
|
||||
private long guardLevel;
|
||||
@JSONField(name = "is_first")
|
||||
private boolean isFirst;
|
||||
@JSONField(name = "is_join_receiver")
|
||||
private boolean isJoinReceiver;
|
||||
@JSONField(name = "is_naming")
|
||||
private boolean isNaming;
|
||||
@JSONField(name = "is_special_batch")
|
||||
private long isSpecialBatch;
|
||||
@JSONField(name = "magnification")
|
||||
private long magnification;
|
||||
@JSONField(name = "medal_info")
|
||||
private WSMedalInfo medalInfo;
|
||||
@JSONField(name = "name_color")
|
||||
private String nameColor;
|
||||
@JSONField(name = "num")
|
||||
private long num;
|
||||
@JSONField(name = "original_gift_name")
|
||||
private String originalGiftName;
|
||||
@JSONField(name = "price")
|
||||
private long price;
|
||||
@JSONField(name = "rcost")
|
||||
private long rcost;
|
||||
@JSONField(name = "receive_user_info")
|
||||
private ReceiveUserInfo receiveUserInfo;
|
||||
@JSONField(name = "receiver_uinfo")
|
||||
private ErUinfo receiverUinfo;
|
||||
@JSONField(name = "remain")
|
||||
private long remain;
|
||||
@JSONField(name = "rnd")
|
||||
private String rnd;
|
||||
@JSONField(name = "sender_uinfo")
|
||||
private ErUinfo senderUinfo;
|
||||
@JSONField(name = "silver")
|
||||
private long silver;
|
||||
@JSONField(name = "super")
|
||||
private long dataSuper;
|
||||
@JSONField(name = "super_batch_gift_num")
|
||||
private long superBatchGiftNum;
|
||||
@JSONField(name = "super_gift_num")
|
||||
private long superGiftNum;
|
||||
@JSONField(name = "svga_block")
|
||||
private long svgaBlock;
|
||||
@JSONField(name = "switch")
|
||||
private boolean dataSwitch;
|
||||
@JSONField(name = "tag_image")
|
||||
private String tagImage;
|
||||
@JSONField(name = "tid")
|
||||
private String tid;
|
||||
@JSONField(name = "timestamp")
|
||||
private long timestamp;
|
||||
@JSONField(name = "total_coin")
|
||||
private long totalCoin;
|
||||
@JSONField(name = "uid")
|
||||
private long uid;
|
||||
@JSONField(name = "uname")
|
||||
private String uname;
|
||||
@JSONField(name = "wealth_level")
|
||||
private long wealthLevel;
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
public static class FaceEffectV2 implements Serializable{
|
||||
@JSONField(name = "id")
|
||||
private long id;
|
||||
@JSONField(name = "type")
|
||||
private long type;
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
public static class GiftInfo implements Serializable{
|
||||
@JSONField(name = "effect_id")
|
||||
private long effectID;
|
||||
@JSONField(name = "has_imaged_gift")
|
||||
private long hasImagedGift;
|
||||
@JSONField(name = "img_basic")
|
||||
private String imgBasic;
|
||||
@JSONField(name = "webp")
|
||||
private String webp;
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
public static class ReceiveUserInfo implements Serializable {
|
||||
@JSONField(name = "uid")
|
||||
private long uid;
|
||||
@JSONField(name = "uname")
|
||||
private String uname;
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
public static class ErUinfo implements Serializable {
|
||||
@JSONField(name = "base")
|
||||
private Base base;
|
||||
@JSONField(name = "uid")
|
||||
private long uid;
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
public static class Base implements Serializable {
|
||||
@JSONField(name = "face")
|
||||
private String face;
|
||||
@JSONField(name = "is_mystery")
|
||||
private boolean isMystery;
|
||||
@JSONField(name = "name")
|
||||
private String name;
|
||||
@JSONField(name = "name_color")
|
||||
private long nameColor;
|
||||
@JSONField(name = "name_color_str")
|
||||
private String nameColorStr;
|
||||
@JSONField(name = "official_info")
|
||||
private OfficialInfo officialInfo;
|
||||
@JSONField(name = "origin_info")
|
||||
private Info originInfo;
|
||||
@JSONField(name = "risk_ctrl_info")
|
||||
private Info riskCtrlInfo;
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
public static class OfficialInfo implements Serializable {
|
||||
@JSONField(name = "desc")
|
||||
private String desc;
|
||||
@JSONField(name = "role")
|
||||
private long role;
|
||||
@JSONField(name = "title")
|
||||
private String title;
|
||||
@JSONField(name = "type")
|
||||
private long type;
|
||||
}
|
||||
|
||||
@lombok.Data
|
||||
public static class Info implements Serializable {
|
||||
@JSONField(name = "face")
|
||||
private String face;
|
||||
@JSONField(name = "name")
|
||||
private String name;
|
||||
}
|
||||
@lombok.Data
|
||||
public static class ComboSend implements Serializable {
|
||||
@JSONField(name = "action")
|
||||
private String action;
|
||||
@JSONField(name = "combo_id")
|
||||
private String comboID;
|
||||
@JSONField(name = "combo_num")
|
||||
private long comboNum;
|
||||
@JSONField(name = "gift_id")
|
||||
private long giftID;
|
||||
@JSONField(name = "gift_name")
|
||||
private String giftName;
|
||||
@JSONField(name = "gift_num")
|
||||
private long giftNum;
|
||||
@JSONField(name = "uid")
|
||||
private long uid;
|
||||
@JSONField(name = "uname")
|
||||
private String uname;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 超级留言
|
||||
* <a href="https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/live/message_stream.md#%E9%86%92%E7%9B%AE%E7%95%99%E8%A8%80">醒目留言</a>
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class WSSuperChatMessage extends WSData{
|
||||
private long price;
|
||||
private long rate;
|
||||
private long uid;
|
||||
private long start_time;
|
||||
private long end_time;
|
||||
private String message;
|
||||
private String message_trans;
|
||||
private String message_font_color;
|
||||
private WSMedalInfo medal_info;
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
JSONObject json=JSONObject.parseObject("{\"cmd\":\"SUPER_CHAT_MESSAGE\",\"data\":{\"background_bottom_color\":\"#2A60B2\",\"background_color\":\"#EDF5FF\",\"background_color_end\":\"#405D85\",\"background_color_start\":\"#3171D2\",\"background_icon\":\"\",\"background_image\":\"\",\"background_price_color\":\"#7497CD\",\"color_point\":0.7,\"dmscore\":616,\"end_time\":1724997230,\"gift\":{\"gift_id\":12000,\"gift_name\":\"醒目留言\",\"num\":1},\"group_medal\":{\"is_lighted\":0,\"medal_id\":0,\"name\":\"\"},\"id\":10427329,\"is_mystery\":false,\"is_ranked\":0,\"is_send_audit\":1,\"medal_info\":{\"anchor_roomid\":81004,\"anchor_uname\":\"艾尔莎_Channel\",\"guard_level\":0,\"icon_id\":0,\"is_lighted\":1,\"medal_color\":\"#1a544b\",\"medal_color_border\":1725515,\"medal_color_end\":5414290,\"medal_color_start\":1725515,\"medal_level\":21,\"medal_name\":\"艾薯条\",\"special\":\"\",\"target_id\":1521415},\"message\":\"莎莎,想安利你个植物大战僵尸的改版叫植物大战僵尸:肉鸽,具体情况私信你了,辛苦了\",\"message_font_color\":\"#A3F6FF\",\"message_trans\":\"サーシャ、あなたのPlantsvs.Zombiesの改版をPlantsvs.Zombiesと言いたい:肉鳩、具体的な状況は私的にあなたを信じて、お疲れ様でした\",\"price\":30,\"rate\":1000,\"start_time\":1724997170,\"time\":60,\"token\":\"9925C118\",\"trans_mark\":0,\"ts\":1724997170,\"uid\":100002175,\"uinfo\":{\"base\":{\"face\":\"https://i1.hdslb.com/bfs/face/b5ec3b1f7025b5546225ae0f36941d55ddef405b.jpg\",\"is_mystery\":false,\"name\":\"中吴同学\",\"name_color\":0,\"name_color_str\":\"#666666\",\"official_info\":{\"desc\":\"\",\"role\":0,\"title\":\"\",\"type\":-1},\"origin_info\":{\"face\":\"https://i1.hdslb.com/bfs/face/b5ec3b1f7025b5546225ae0f36941d55ddef405b.jpg\",\"name\":\"中吴同学\"}},\"guard\":{\"expired_str\":\"\",\"level\":0},\"medal\":{\"color\":1725515,\"color_border\":1725515,\"color_end\":5414290,\"color_start\":1725515,\"guard_icon\":\"\",\"guard_level\":0,\"honor_icon\":\"\",\"id\":0,\"is_light\":1,\"level\":21,\"name\":\"艾薯条\",\"ruid\":1521415,\"score\":50001980,\"typ\":0,\"user_receive_count\":0,\"v2_medal_color_border\":\"#5FC7F4FF\",\"v2_medal_color_end\":\"#43B3E3CC\",\"v2_medal_color_level\":\"#00308C99\",\"v2_medal_color_start\":\"#43B3E3CC\",\"v2_medal_color_text\":\"#FFFFFFFF\"},\"title\":{\"old_title_css_id\":\"\",\"title_css_id\":\"\"},\"uid\":100002175},\"user_info\":{\"face\":\"https://i1.hdslb.com/bfs/face/b5ec3b1f7025b5546225ae0f36941d55ddef405b.jpg\",\"face_frame\":\"\",\"guard_level\":0,\"is_main_vip\":1,\"is_svip\":0,\"is_vip\":0,\"level_color\":\"#5896de\",\"manager\":0,\"name_color\":\"#666666\",\"title\":\"\",\"uname\":\"中吴同学\",\"user_level\":25}},\"is_report\":true,\"msg_id\":\"19106780029655552:1000:1000\",\"p_is_ack\":true,\"p_msg_type\":1,\"send_time\":1724997170767}");
|
||||
WSSuperChatMessage message=new WSSuperChatMessage(json);
|
||||
System.out.println(message);
|
||||
}
|
||||
public WSSuperChatMessage(JSONObject json) {
|
||||
super(json);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.yutou.bili.bean.websocket.live;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WSUserMedal {
|
||||
private long uid;
|
||||
private String medal_name;
|
||||
private String medal_color = "FFFFFF";
|
||||
private String medal_anchor;
|
||||
private int medal_level;
|
||||
|
||||
public static WSUserMedal create(JSONArray array) {
|
||||
if (array.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
WSUserMedal medal = new WSUserMedal();
|
||||
medal.setUid(array.getIntValue(3));
|
||||
medal.setMedal_name(array.getString(1));
|
||||
medal.setMedal_anchor(array.getString(2));
|
||||
medal.setMedal_level(array.getIntValue(0));
|
||||
return medal;
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ public class BiliLiveNetApiManager extends BaseApi {
|
||||
header.put("Referer", "https://live.bilibili.com");
|
||||
header.put("Connection", "keep-alive");
|
||||
header.put("Upgrade-Insecure-Requests", "1");
|
||||
setHeaders(header);
|
||||
addHeader(header);
|
||||
callback.onSuccess(createApi(LiveApi.class));
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,27 @@
|
||||
package com.yutou.bili.net;
|
||||
|
||||
import com.aayushatharva.brotli4j.Brotli4jLoader;
|
||||
import com.aayushatharva.brotli4j.decoder.Decoder;
|
||||
import com.aayushatharva.brotli4j.decoder.DecoderJNI;
|
||||
import com.aayushatharva.brotli4j.decoder.DirectDecompress;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.yutou.bili.api.LiveApi;
|
||||
import com.yutou.bili.bean.live.LiveDanmuInfo;
|
||||
import com.yutou.bili.bean.live.LiveRoomConfig;
|
||||
import com.yutou.bili.bean.websocket.WebSocketBody;
|
||||
import com.yutou.bili.bean.websocket.WebSocketHeader;
|
||||
import com.yutou.bili.bean.websocket.live.WSData;
|
||||
import com.yutou.bili.databases.BiliBiliLoginDatabase;
|
||||
import com.yutou.bili.utils.BiliUserUtils;
|
||||
import com.yutou.bili.utils.BytesUtils;
|
||||
import com.yutou.inter.IHttpApiCheckCallback;
|
||||
import com.yutou.okhttp.HttpCallback;
|
||||
import jakarta.xml.bind.DatatypeConverter;
|
||||
import com.yutou.utils.Log;
|
||||
import okhttp3.Headers;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -21,7 +30,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public class WebSocketManager {
|
||||
private static WebSocketManager instance;
|
||||
@ -81,25 +89,6 @@ public class WebSocketManager {
|
||||
super(serverUri);
|
||||
this.roomConfig = roomId;
|
||||
heartbeatTask = new HeartbeatTask();
|
||||
HashMap<String, String> header = new HashMap<>();
|
||||
header.put("Sec-WebSocket-Extensions", "permessage-deflate; client_max_window_bits");
|
||||
header.put("Sec-WebSocket-Key", "f1kFoce72Pn+wbjdPyONLw==");
|
||||
// header.put("Sec-WebSocket-Key", roomId.getLiveInfo().getToken());
|
||||
header.put("Sec-WebSocket-Version", "13");
|
||||
header.put("Cache-Control", "no-cache");
|
||||
header.put("Connection", "Upgrade");
|
||||
header.put("Accept-Encoding:", "gzip, deflate, br, zstd");
|
||||
header.put("Host", roomId.getLiveInfo().getHostList().get(0).getHost() + ":" + roomId.getLiveInfo().getHostList().get(0).getWssPort());
|
||||
header.put("Origin", "https://live.bilibili.com");
|
||||
header.put("Pragma", "no-cache");
|
||||
header.put("Upgrade", "websocket");
|
||||
header.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36");
|
||||
for (String key : header.keySet()) {
|
||||
addHeader(key, header.get(key));
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
System.out.println("header = " + header);
|
||||
connect();
|
||||
}
|
||||
|
||||
@ -108,7 +97,7 @@ public class WebSocketManager {
|
||||
WebSocketManager.getInstance().roomMap.put(roomConfig, this);
|
||||
heartbeatTask.setSocket(this);
|
||||
heartbeatTask.sendInitAuthData();
|
||||
new Timer().schedule(heartbeatTask, 0, 30000);
|
||||
new Timer().schedule(heartbeatTask, 1000, 30000);
|
||||
System.out.println("WebSocketClientTh.onOpen");
|
||||
}
|
||||
|
||||
@ -146,17 +135,40 @@ public class WebSocketManager {
|
||||
* @param data 待压缩的数据
|
||||
*/
|
||||
public void decompress(byte[] data) {
|
||||
byte[] bytes = new byte[data.length - 16];
|
||||
WebSocketHeader header = new WebSocketHeader(data);
|
||||
System.arraycopy(data, header.getHeaderSize(), bytes, 0, data.length - header.getHeaderSize());
|
||||
System.out.println("数据大小:" + header.getDataSize() + " 协议:" + header.getAgree() + " 头部大小:" + header.getHeaderSize() + " 命令:" + header.getCmdData());
|
||||
switch (header.getAgree()) {
|
||||
case 0:
|
||||
case 1:
|
||||
danmu(bytes);
|
||||
break;
|
||||
default:
|
||||
unzipDanmu(bytes, header.getAgree() == 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void danmu(byte[] bytes) {
|
||||
Log.i("未压缩:" + new String(bytes));
|
||||
}
|
||||
|
||||
private void unzipDanmu(byte[] bytes, boolean useHeader) {
|
||||
try {
|
||||
Inflater inflater = new Inflater();
|
||||
inflater.reset();
|
||||
inflater.setInput(data);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(data.length);
|
||||
byte[] buf = new byte[8192];
|
||||
while (!inflater.finished()) {
|
||||
int i = inflater.inflate(buf);
|
||||
out.write(buf, 0, i);
|
||||
Brotli4jLoader.ensureAvailability();
|
||||
DirectDecompress directDecompress = Decoder.decompress(bytes);
|
||||
if (directDecompress.getResultStatus() == DecoderJNI.Status.DONE) {
|
||||
WebSocketBody body = new WebSocketBody(directDecompress.getDecompressedData());
|
||||
Log.i("3协议:" + useHeader + " 命令数:" + body.getBodyList().size());
|
||||
for (JSONObject json : body.getBodyList()) {
|
||||
Log.i("解压:" + WSData.parse(json));
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
} else {
|
||||
Log.e(new RuntimeException("解压失败"));
|
||||
}
|
||||
System.out.println("接收值:" + new String(out.toByteArray()));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -171,60 +183,66 @@ public class WebSocketManager {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
// com.yutou.bilibili.Tools.Log.i("-------发送心跳--------");
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
outputStream.write(BytesUtils.toLH("[object Object]".length() + 16));
|
||||
outputStream.write(new byte[]{0, 16, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1});
|
||||
outputStream.write("[object Object]".getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.flush();
|
||||
socket.send(outputStream.toByteArray());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void sendInitAuthData() {
|
||||
JSONObject json = new JSONObject();
|
||||
if (roomConfig.isLogin()) {
|
||||
json.put("uid", roomConfig.getUid());
|
||||
json.put("uid", Long.parseLong(roomConfig.getUid()));
|
||||
|
||||
} else {
|
||||
json.put("uid", "0");
|
||||
json.put("uid", 0);
|
||||
}
|
||||
try {
|
||||
json.put("roomid", roomConfig.getRoomId());
|
||||
json.put("protover", "3");
|
||||
json.put("platform", "web");
|
||||
json.put("buvid", "F56FA00C-B043-DDB7-B7D2-D1A2AEC3034E24804infoc");
|
||||
json.put("type", 2);
|
||||
json.put("key", roomConfig.getLiveInfo().getToken());
|
||||
byte[] bytes = {0, 16, 0, 1, 0, 0, 0, 7, 0, 0, 0, 1};
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
outputStream.write(toLH(json.toString().length() + bytes.length));
|
||||
outputStream.write(bytes);
|
||||
outputStream.write(json.toJSONString().getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.flush();
|
||||
System.out.println("\n\n\n");
|
||||
String str = DatatypeConverter.printHexBinary(outputStream.toByteArray());
|
||||
for (int i = 0; i < str.length(); i = i + 4) {
|
||||
if (i % 32 == 0 && i != 0) {
|
||||
System.out.println();
|
||||
}
|
||||
if (str.length() - i > 4) {
|
||||
System.out.print(str.substring(i, i + 4) + " ");
|
||||
} else {
|
||||
System.out.println(str.substring(i));
|
||||
BiliUserUtils.getBuvid(new IHttpApiCheckCallback<String>() {
|
||||
@Override
|
||||
public void onSuccess(String api) {
|
||||
try {
|
||||
json.put("roomid", Long.parseLong(roomConfig.getRoomId()));
|
||||
json.put("protover", 3);
|
||||
json.put("buvid", api);
|
||||
json.put("platform", "web");
|
||||
json.put("type", 2);
|
||||
json.put("key", roomConfig.getLiveInfo().getToken());
|
||||
byte[] bytes = {0, 16, 0, 1, 0, 0, 0, 7, 0, 0, 0, 1};
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
System.out.println("bytes.length = " + bytes.length);
|
||||
Log.i(json);
|
||||
outputStream.write(BytesUtils.toLH(json.toString().length() + 16));
|
||||
outputStream.write(bytes);
|
||||
outputStream.write(json.toJSONString().getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.flush();
|
||||
BytesUtils.printHex(outputStream.toByteArray());
|
||||
System.out.println(socket.isOpen());
|
||||
socket.send(outputStream.toByteArray());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
System.out.println("\n\n\n");
|
||||
System.out.println(socket.isOpen());
|
||||
socket.send(outputStream.toByteArray());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@Override
|
||||
public void onError(int code, String error) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public byte[] toLH(int n) {
|
||||
byte[] b = new byte[4];
|
||||
b[3] = (byte) (n & 0xff);
|
||||
b[2] = (byte) (n >> 8 & 0xff);
|
||||
b[1] = (byte) (n >> 16 & 0xff);
|
||||
b[0] = (byte) (n >> 24 & 0xff);
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
package com.yutou.bili.utils;
|
||||
|
||||
import com.yutou.bili.api.UserApi;
|
||||
import com.yutou.bili.bean.live.SpiBean;
|
||||
import com.yutou.bili.net.BiliUserNetApiManager;
|
||||
import com.yutou.inter.IHttpApiCheckCallback;
|
||||
import com.yutou.okhttp.HttpCallback;
|
||||
import com.yutou.utils.RedisTools;
|
||||
import okhttp3.Headers;
|
||||
|
||||
public class BiliUserUtils {
|
||||
public static void getBuvid(IHttpApiCheckCallback<String> callback) {
|
||||
String buvid= RedisTools.get(RedisTools.BILI_USER_BUVID);
|
||||
if(buvid!=null){
|
||||
callback.onSuccess(buvid);
|
||||
return;
|
||||
}
|
||||
BiliUserNetApiManager.getInstance().getUserApi(new IHttpApiCheckCallback<UserApi>() {
|
||||
@Override
|
||||
public void onSuccess(UserApi api) {
|
||||
api.getFingerSpi().enqueue(new HttpCallback<SpiBean>() {
|
||||
@Override
|
||||
public void onResponse(Headers headers, int code, String status, SpiBean response, String rawResponse) {
|
||||
RedisTools.set(RedisTools.BILI_USER_BUVID,response.getB_3());
|
||||
callback.onSuccess(response.getB_3());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String error) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
41
biliapi/src/main/java/com/yutou/bili/utils/BytesUtils.java
Normal file
41
biliapi/src/main/java/com/yutou/bili/utils/BytesUtils.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.yutou.bili.utils;
|
||||
|
||||
import com.yutou.utils.Log;
|
||||
import jakarta.xml.bind.DatatypeConverter;
|
||||
|
||||
public class BytesUtils {
|
||||
|
||||
public static int bytesToInt2(byte[] src, int offset) {
|
||||
int value;
|
||||
value = (int) (((src[offset] & 0xFF) << 24)
|
||||
| ((src[offset + 1] & 0xFF) << 16)
|
||||
| ((src[offset + 2] & 0xFF) << 8)
|
||||
| (src[offset + 3] & 0xFF));
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void printHex(byte[] byteArray) {
|
||||
System.out.println("\n\n\n");
|
||||
String str = DatatypeConverter.printHexBinary(byteArray);
|
||||
Log.i(str);
|
||||
for (int i = 0; i < str.length(); i = i + 4) {
|
||||
if (i % 32 == 0 && i != 0) {
|
||||
System.out.println();
|
||||
}
|
||||
if (str.length() - i > 4) {
|
||||
System.out.print(str.substring(i, i + 4) + " ");
|
||||
} else {
|
||||
System.out.println(str.substring(i));
|
||||
}
|
||||
}
|
||||
System.out.println("\n\n\n");
|
||||
}
|
||||
public static byte[] toLH(int n) {
|
||||
byte[] b = new byte[4];
|
||||
b[3] = (byte) (n & 0xff);
|
||||
b[2] = (byte) (n >> 8 & 0xff);
|
||||
b[1] = (byte) (n >> 16 & 0xff);
|
||||
b[0] = (byte) (n >> 24 & 0xff);
|
||||
return b;
|
||||
}
|
||||
}
|
@ -35,6 +35,10 @@ public class BaseApi {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
public void addHeader(HashMap<String,String> headers){
|
||||
this.headers.putAll(headers);
|
||||
}
|
||||
|
||||
|
||||
public BaseApi setParams(HashMap<String, String> params) {
|
||||
this.params = params;
|
||||
|
@ -8,7 +8,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class Log {
|
||||
private static Logger logger;
|
||||
private static Logger logger=Logger.getLogger("Biliob");
|
||||
|
||||
public static void i(String tag, Object log) {
|
||||
i('[' + tag + ']' + log);
|
||||
@ -18,6 +18,7 @@ public class Log {
|
||||
if (!((boolean) ConfigTools.load(ConfigTools.CONFIG, "logcat"))) {
|
||||
return;
|
||||
}
|
||||
// logger.log(Level.INFO, log.toString());
|
||||
System.out.printf("[%s]%s%n",
|
||||
AppTools.getToDayNowTimeToString(),
|
||||
log
|
||||
|
@ -14,6 +14,7 @@ import java.util.Set;
|
||||
|
||||
public class RedisTools {
|
||||
public static final int QQBOT_USER = 3;
|
||||
public static final String BILI_USER_BUVID = "bili_user_buvid";
|
||||
private static boolean isNotInstallRedis = false;
|
||||
private static String host;
|
||||
private static int port;
|
||||
@ -28,7 +29,7 @@ public class RedisTools {
|
||||
//Properties properties = PropertyUtil.loadProperties("jedis.properties");
|
||||
//host = properties.getProperty("redis.host");
|
||||
//port = Integer.valueOf(properties.getProperty("redis.port"));
|
||||
host = "127.0.0.1";
|
||||
host = "172.22.81.254";
|
||||
port = 6379;
|
||||
}
|
||||
|
||||
@ -74,7 +75,7 @@ public class RedisTools {
|
||||
}
|
||||
|
||||
public static String get(String key, int dbIndex) {
|
||||
String value = "-999";
|
||||
String value = null;
|
||||
if (isNotInstallRedis) {
|
||||
return value;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user