新版改版:
新增B站接口 测试直播WebSocket
This commit is contained in:
parent
b178010f8f
commit
54ac47c8b4
184
biliapi/src/main/java/com/yutou/Main.java
Normal file
184
biliapi/src/main/java/com/yutou/Main.java
Normal file
@ -0,0 +1,184 @@
|
||||
package com.yutou;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
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.login.LoginCookie;
|
||||
import com.yutou.bili.bean.login.UserInfoBean;
|
||||
import com.yutou.bili.enums.LiveProtocol;
|
||||
import com.yutou.bili.enums.LiveVideoCodec;
|
||||
import com.yutou.bili.enums.LiveVideoDefinition;
|
||||
import com.yutou.bili.enums.LiveVideoFormat;
|
||||
import com.yutou.bili.net.BiliLiveNetApiManager;
|
||||
import com.yutou.bili.net.BiliLoginNetApiManager;
|
||||
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 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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void testSocket() {
|
||||
try {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("roomid", "13246789");
|
||||
json.put("protover", "3");
|
||||
json.put("platform", "web");
|
||||
json.put("type", 2);
|
||||
json.put("key", "aaaabbb");
|
||||
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});
|
||||
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));
|
||||
}
|
||||
}
|
||||
System.out.println("\n\n\n");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void getPlayUrl() {
|
||||
BiliLiveNetApiManager
|
||||
.getInstance()
|
||||
.getApi(new IHttpApiCheckCallback<LiveApi>() {
|
||||
@Override
|
||||
public void onSuccess(LiveApi api) {
|
||||
String roomId = "22689676";
|
||||
String mid = "68057278";
|
||||
|
||||
// roomId="42062";
|
||||
|
||||
api.getLiveRoomPlayInfo(
|
||||
roomId,
|
||||
LiveProtocol.getAll(),
|
||||
LiveVideoFormat.getAll(),
|
||||
LiveVideoCodec.getAll(),
|
||||
LiveVideoDefinition.ORIGINAL.getValue()
|
||||
).enqueue(new HttpCallback<>() {
|
||||
@Override
|
||||
public void onResponse(Headers headers, int code, String status, LiveRoomPlayInfo response, String rawResponse) {
|
||||
LiveRoomPlayInfo.Codec codec = response.getPlayurlInfo().getPlayurl().getStream().get(0).getFormat().get(0).getCodec().get(0);
|
||||
|
||||
LiveRoomConfig config = new LiveRoomConfig();
|
||||
config.setUid("0");
|
||||
config.setRoomId(roomId);
|
||||
config.setMid(mid);
|
||||
config.setLogin(false);
|
||||
WebSocketManager.getInstance().addRoom(config);
|
||||
|
||||
/*String url = codec.getUrlInfo().get(0).getHost() + codec.getBaseUrl() + codec.getUrlInfo().get(0).getExtra();
|
||||
System.out.println("下载url = " + url);
|
||||
api.downloadLive(url).enqueue(new FileCallback<>(response) {
|
||||
@Override
|
||||
public void onStart(LiveRoomPlayInfo bean) {
|
||||
System.out.println("开始下载");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDownload(Headers headers, LiveRoomPlayInfo bean, long len, long total) {
|
||||
System.out.println("下载中:"+len+"|"+total);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(LiveRoomPlayInfo bean) {
|
||||
System.out.println("下载结束");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(LiveRoomPlayInfo bean, Throwable throwable) {
|
||||
System.out.println("下载失败");
|
||||
}
|
||||
});*/
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String error) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void login(String username, String password) {
|
||||
BiliLoginNetApiManager.getInstance().login(new HttpCallback<LoginCookie>() {
|
||||
@Override
|
||||
public void onResponse(Headers headers, int code, String status, LoginCookie response, String rawResponse) {
|
||||
System.out.println("headers = " + headers + ", code = " + code + ", status = " + status + ", response = " + response + ", rawResponse = " + rawResponse);
|
||||
if (code == BiliLoginNetApiManager.LOGIN_SUCCESS) {
|
||||
BiliBiliLoginDatabase.getInstance().initData(response).close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void getUserInfo() {
|
||||
BiliUserNetApiManager.getInstance().getUserApi(new IHttpApiCheckCallback<UserApi>() {
|
||||
@Override
|
||||
public void onSuccess(UserApi api) {
|
||||
api.getUserInfo().enqueue(new HttpCallback<UserInfoBean>() {
|
||||
@Override
|
||||
public void onResponse(Headers headers, int code, String status, UserInfoBean response, String rawResponse) {
|
||||
System.out.println("response = " + rawResponse);
|
||||
System.out.println(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String error) {
|
||||
System.out.println("code = " + code + ", error = " + error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
56
biliapi/src/main/java/com/yutou/bili/api/LiveApi.java
Normal file
56
biliapi/src/main/java/com/yutou/bili/api/LiveApi.java
Normal file
@ -0,0 +1,56 @@
|
||||
package com.yutou.bili.api;
|
||||
|
||||
import com.yutou.bili.bean.live.*;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 直播间相关API
|
||||
* <a href="https://socialsisteryi.github.io/bilibili-API-collect/docs/live/info.html#%E8%8E%B7%E5%8F%96%E7%9B%B4%E6%92%AD%E9%97%B4%E4%BF%A1%E6%81%AF">文档地址</a>
|
||||
*/
|
||||
public interface LiveApi {
|
||||
/**
|
||||
* 获取直播间信息
|
||||
* @param roomId 直播间号 必要 可以为短号
|
||||
*/
|
||||
@GET("/room/v1/Room/get_info")
|
||||
Call<HttpBody<LiveRoomInfo>> getRoomInfo(@Query("room_id")String roomId);
|
||||
@GET("/room/v1/Room/getRoomInfoOld")
|
||||
Call<HttpBody<LiveRoomStatus>> getRoomStatus(@Query("mid")String mid);
|
||||
|
||||
/**
|
||||
* 获取主播信息
|
||||
*/
|
||||
@GET("/live_user/v1/Master/info")
|
||||
Call<HttpBody<MasterInfoBean>> getMasterInfo(@Query("uid")String uid);
|
||||
|
||||
/**
|
||||
* 获取直播间信息
|
||||
* @param id 直播间id
|
||||
* @param protocol 直播协议 {@link com.yutou.bili.enums.LiveProtocol}
|
||||
* @param format 格式 {@link com.yutou.bili.enums.LiveVideoFormat}
|
||||
* @param codec 编码 {@link com.yutou.bili.enums.LiveVideoCodec}
|
||||
* @param qn 清晰度 {@link com.yutou.bili.enums.LiveVideoDefinition}
|
||||
* @return
|
||||
*/
|
||||
@GET("/xlive/web-room/v2/index/getRoomPlayInfo")
|
||||
Call<HttpBody<LiveRoomPlayInfo>> getLiveRoomPlayInfo(
|
||||
@Query("room_id")String id,
|
||||
@Query("protocol")String protocol,
|
||||
@Query("format")String format,
|
||||
@Query("codec")String codec,
|
||||
@Query("qn")int qn
|
||||
);
|
||||
@Streaming
|
||||
@GET()
|
||||
Call<FileBody<LiveRoomPlayInfo>> downloadLive(@Url String url);
|
||||
|
||||
@GET("/xlive/web-room/v1/index/getDanmuInfo")
|
||||
Call<HttpBody<LiveDanmuInfo>> getLiveRoomDanmuInfo(@Query("id")String id);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.yutou.bili.api;
|
||||
|
||||
import com.yutou.bili.bean.login.CheckCookieBean;
|
||||
import com.yutou.bili.bean.login.LoginInfoBean;
|
||||
import com.yutou.bili.bean.login.QRCodeGenerateBean;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
@ -8,11 +9,23 @@ import retrofit2.http.GET;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface LoginApi {
|
||||
/**
|
||||
* 获取登陆二维码
|
||||
*/
|
||||
@GET("/x/passport-login/web/qrcode/generate")
|
||||
Call<HttpBody<QRCodeGenerateBean>> getQRCodeGenerate();
|
||||
|
||||
/**
|
||||
* 通过二维码登录
|
||||
*/
|
||||
@GET("/x/passport-login/web/qrcode/poll")
|
||||
Call<HttpBody<LoginInfoBean>> loginQRCode(@Query("qrcode_key") String qrcode_key);
|
||||
|
||||
/**
|
||||
* 检查cookie是否有效,太麻烦了以后做
|
||||
*/
|
||||
@GET("x/passport-login/web/cookie/info")
|
||||
Call<HttpBody<CheckCookieBean>> checkCookie();
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package com.yutou.bili.bean.live;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class LiveDanmuInfo {
|
||||
@JSONField(name = "group")
|
||||
private String group;
|
||||
|
||||
@JSONField(name = "business_id")
|
||||
private int businessId;
|
||||
|
||||
@JSONField(name = "refresh_row_factor")
|
||||
private double refreshRowFactor;
|
||||
|
||||
@JSONField(name = "refresh_rate")
|
||||
private int refreshRate;
|
||||
|
||||
@JSONField(name = "max_delay")
|
||||
private int maxDelay;
|
||||
|
||||
@JSONField(name = "token")
|
||||
private String token;
|
||||
|
||||
@JSONField(name = "host_list")
|
||||
private List<Host> hostList;
|
||||
|
||||
@Data
|
||||
public static class Host {
|
||||
|
||||
@JSONField(name = "host")
|
||||
private String host;
|
||||
|
||||
@JSONField(name = "port")
|
||||
private int port;
|
||||
|
||||
@JSONField(name = "wss_port")
|
||||
private int wssPort;
|
||||
|
||||
@JSONField(name = "ws_port")
|
||||
private int wsPort;
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.yutou.bili.bean.live;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LiveRoomConfig {
|
||||
String uid;
|
||||
String roomId;
|
||||
String mid;//真实房间id
|
||||
boolean isLogin;
|
||||
LiveDanmuInfo liveInfo;
|
||||
|
||||
}
|
234
biliapi/src/main/java/com/yutou/bili/bean/live/LiveRoomInfo.java
Normal file
234
biliapi/src/main/java/com/yutou/bili/bean/live/LiveRoomInfo.java
Normal file
@ -0,0 +1,234 @@
|
||||
package com.yutou.bili.bean.live;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class LiveRoomInfo {
|
||||
@JSONField(name = "uid")
|
||||
private int uid;
|
||||
|
||||
@JSONField(name = "room_id")
|
||||
private int roomId;
|
||||
|
||||
@JSONField(name = "short_id")
|
||||
private int shortId;
|
||||
|
||||
@JSONField(name = "attention")
|
||||
private int attention;
|
||||
|
||||
@JSONField(name = "online")
|
||||
private int online;
|
||||
|
||||
@JSONField(name = "is_portrait")
|
||||
private boolean isPortrait;
|
||||
|
||||
@JSONField(name = "description")
|
||||
private String description;
|
||||
|
||||
@JSONField(name = "live_status")
|
||||
private int liveStatus;
|
||||
|
||||
@JSONField(name = "area_id")
|
||||
private int areaId;
|
||||
|
||||
@JSONField(name = "parent_area_id")
|
||||
private int parentAreaId;
|
||||
|
||||
@JSONField(name = "parent_area_name")
|
||||
private String parentAreaName;
|
||||
|
||||
@JSONField(name = "old_area_id")
|
||||
private int oldAreaId;
|
||||
|
||||
@JSONField(name = "background")
|
||||
private String background;
|
||||
|
||||
@JSONField(name = "title")
|
||||
private String title;
|
||||
|
||||
@JSONField(name = "user_cover")
|
||||
private String userCover;
|
||||
|
||||
@JSONField(name = "keyframe")
|
||||
private String keyframe;
|
||||
|
||||
@JSONField(name = "is_strict_room")
|
||||
private boolean isStrictRoom;
|
||||
|
||||
@JSONField(name = "live_time")
|
||||
private String liveTime;
|
||||
|
||||
@JSONField(name = "tags")
|
||||
private String tags;
|
||||
|
||||
@JSONField(name = "is_anchor")
|
||||
private int isAnchor;
|
||||
|
||||
@JSONField(name = "room_silent_type")
|
||||
private String roomSilentType;
|
||||
|
||||
@JSONField(name = "room_silent_level")
|
||||
private int roomSilentLevel;
|
||||
|
||||
@JSONField(name = "room_silent_second")
|
||||
private int roomSilentSecond;
|
||||
|
||||
@JSONField(name = "area_name")
|
||||
private String areaName;
|
||||
|
||||
@JSONField(name = "pendants")
|
||||
private String pendants;
|
||||
|
||||
@JSONField(name = "area_pendants")
|
||||
private String areaPendants;
|
||||
|
||||
@JSONField(name = "hot_words")
|
||||
private List<String> hotWords;
|
||||
|
||||
@JSONField(name = "hot_words_status")
|
||||
private int hotWordsStatus;
|
||||
|
||||
@JSONField(name = "verify")
|
||||
private String verify;
|
||||
|
||||
@JSONField(name = "new_pendants")
|
||||
private NewPendants newPendants;
|
||||
|
||||
@JSONField(name = "up_session")
|
||||
private String upSession;
|
||||
|
||||
@JSONField(name = "pk_status")
|
||||
private int pkStatus;
|
||||
|
||||
@JSONField(name = "pk_id")
|
||||
private int pkId;
|
||||
|
||||
@JSONField(name = "battle_id")
|
||||
private int battleId;
|
||||
|
||||
@JSONField(name = "allow_change_area_time")
|
||||
private int allowChangeAreaTime;
|
||||
|
||||
@JSONField(name = "allow_upload_cover_time")
|
||||
private int allowUploadCoverTime;
|
||||
|
||||
@JSONField(name = "studio_info")
|
||||
private StudioInfo studioInfo;
|
||||
|
||||
@Data
|
||||
public static class NewPendants {
|
||||
@JSONField(name = "frame")
|
||||
private Frame frame;
|
||||
|
||||
@JSONField(name = "badge")
|
||||
private Badge badge;
|
||||
|
||||
@JSONField(name = "mobile_frame")
|
||||
private MobileFrame mobileFrame;
|
||||
@JSONField(name = "mobile_badge")
|
||||
private MobileBadge mobileBadge;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Frame {
|
||||
@JSONField(name = "name")
|
||||
private String name;
|
||||
|
||||
@JSONField(name = "value")
|
||||
private String value;
|
||||
|
||||
@JSONField(name = "position")
|
||||
private int position;
|
||||
|
||||
@JSONField(name = "desc")
|
||||
private String desc;
|
||||
|
||||
@JSONField(name = "area")
|
||||
private int area;
|
||||
|
||||
@JSONField(name = "area_old")
|
||||
private int areaOld;
|
||||
|
||||
@JSONField(name = "bg_color")
|
||||
private String bgColor;
|
||||
|
||||
@JSONField(name = "bg_pic")
|
||||
private String bgPic;
|
||||
|
||||
@JSONField(name = "use_old_area")
|
||||
private boolean useOldArea;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Badge {
|
||||
@JSONField(name = "name")
|
||||
private String name;
|
||||
|
||||
@JSONField(name = "position")
|
||||
private int position;
|
||||
|
||||
@JSONField(name = "value")
|
||||
private String value;
|
||||
|
||||
@JSONField(name = "desc")
|
||||
private String desc;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MobileFrame {
|
||||
@JSONField(name = "name")
|
||||
private String name;
|
||||
|
||||
@JSONField(name = "value")
|
||||
private String value;
|
||||
|
||||
@JSONField(name = "position")
|
||||
private int position;
|
||||
|
||||
@JSONField(name = "desc")
|
||||
private String desc;
|
||||
|
||||
@JSONField(name = "area")
|
||||
private int area;
|
||||
|
||||
@JSONField(name = "area_old")
|
||||
private int areaOld;
|
||||
|
||||
@JSONField(name = "bg_color")
|
||||
private String bgColor;
|
||||
|
||||
@JSONField(name = "bg_pic")
|
||||
private String bgPic;
|
||||
|
||||
@JSONField(name = "use_old_area")
|
||||
private boolean useOldArea;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MobileBadge {
|
||||
@JSONField(name = "name")
|
||||
private String name;
|
||||
|
||||
@JSONField(name = "position")
|
||||
private int position;
|
||||
|
||||
@JSONField(name = "value")
|
||||
private String value;
|
||||
|
||||
@JSONField(name = "desc")
|
||||
private String desc;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class StudioInfo {
|
||||
@JSONField(name = "status")
|
||||
private int status;
|
||||
|
||||
@JSONField(name = "master_list")
|
||||
private List<String> masterList;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
package com.yutou.bili.bean.live;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.yutou.okhttp.BaseBean;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class LiveRoomPlayInfo extends BaseBean {
|
||||
@JSONField(name = "room_id")
|
||||
private int roomId;
|
||||
|
||||
@JSONField(name = "short_id")
|
||||
private int shortId;
|
||||
|
||||
@JSONField(name = "uid")
|
||||
private int uid;
|
||||
|
||||
@JSONField(name = "is_hidden")
|
||||
private boolean isHidden;
|
||||
|
||||
@JSONField(name = "is_locked")
|
||||
private boolean isLocked;
|
||||
|
||||
@JSONField(name = "is_portrait")
|
||||
private boolean isPortrait;
|
||||
|
||||
@JSONField(name = "live_status")
|
||||
private int liveStatus;
|
||||
|
||||
@JSONField(name = "hidden_till")
|
||||
private int hiddenTill;
|
||||
|
||||
@JSONField(name = "lock_till")
|
||||
private int lockTill;
|
||||
|
||||
@JSONField(name = "encrypted")
|
||||
private boolean encrypted;
|
||||
|
||||
@JSONField(name = "pwd_verified")
|
||||
private boolean pwdVerified;
|
||||
|
||||
@JSONField(name = "live_time")
|
||||
private int liveTime;
|
||||
|
||||
@JSONField(name = "room_shield")
|
||||
private int roomShield;
|
||||
|
||||
@JSONField(name = "all_special_types")
|
||||
private List<Integer> allSpecialTypes;
|
||||
|
||||
@JSONField(name = "playurl_info")
|
||||
private PlayurlInfo playurlInfo;
|
||||
|
||||
@JSONField(name = "official_type")
|
||||
private int officialType;
|
||||
|
||||
@JSONField(name = "official_room_id")
|
||||
private int officialRoomId;
|
||||
|
||||
@JSONField(name = "risk_with_delay")
|
||||
private int riskWithDelay;
|
||||
|
||||
@Data
|
||||
public static class PlayurlInfo {
|
||||
@JSONField(name = "conf_json")
|
||||
private String confJson;
|
||||
|
||||
@JSONField(name = "playurl")
|
||||
private Playurl playurl;
|
||||
|
||||
@JSONField(name = "dolby_qn")
|
||||
private Integer dolbyQn;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Playurl {
|
||||
@JSONField(name = "cid")
|
||||
private int cid;
|
||||
|
||||
@JSONField(name = "g_qn_desc")
|
||||
private List<QnDesc> gQnDesc;
|
||||
|
||||
@JSONField(name = "stream")
|
||||
private List<Stream> stream;
|
||||
|
||||
@JSONField(name = "p2p_data")
|
||||
private P2pData p2pData;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class QnDesc {
|
||||
@JSONField(name = "qn")
|
||||
private int qn;
|
||||
|
||||
@JSONField(name = "desc")
|
||||
private String desc;
|
||||
|
||||
@JSONField(name = "hdr_desc")
|
||||
private String hdrDesc;
|
||||
|
||||
@JSONField(name = "attr_desc")
|
||||
private Object attrDesc;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Stream {
|
||||
@JSONField(name = "protocol_name")
|
||||
private String protocolName;
|
||||
|
||||
@JSONField(name = "format")
|
||||
private List<Format> format;
|
||||
|
||||
@JSONField(name = "p2p_type")
|
||||
private int p2pType;
|
||||
|
||||
@JSONField(name = "free_type")
|
||||
private int freeType;
|
||||
|
||||
@JSONField(name = "mid")
|
||||
private int mid;
|
||||
|
||||
@JSONField(name = "sid")
|
||||
private String sid;
|
||||
|
||||
@JSONField(name = "chash")
|
||||
private int chash;
|
||||
|
||||
@JSONField(name = "bmt")
|
||||
private int bmt;
|
||||
|
||||
@JSONField(name = "sche")
|
||||
private String sche;
|
||||
|
||||
@JSONField(name = "score")
|
||||
private int score;
|
||||
|
||||
@JSONField(name = "pp")
|
||||
private String pp;
|
||||
|
||||
@JSONField(name = "source")
|
||||
private String source;
|
||||
|
||||
@JSONField(name = "trace")
|
||||
private int trace;
|
||||
|
||||
@JSONField(name = "site")
|
||||
private String site;
|
||||
@JSONField(name = "zoneid_l")
|
||||
private int zoneidL;
|
||||
|
||||
@JSONField(name = "sid_l")
|
||||
private String sidL;
|
||||
|
||||
@JSONField(name = "order")
|
||||
private int order;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Format {
|
||||
@JSONField(name = "format_name")
|
||||
private String formatName;
|
||||
|
||||
@JSONField(name = "codec")
|
||||
private List<Codec> codec;
|
||||
|
||||
@JSONField(name = "hdr_qn")
|
||||
private Integer hdrQn;
|
||||
|
||||
@JSONField(name = "dolby_type")
|
||||
private int dolbyType;
|
||||
|
||||
@JSONField(name = "attr_name")
|
||||
private String attrName;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Codec {
|
||||
@JSONField(name = "codec_name")
|
||||
private String codecName;
|
||||
|
||||
@JSONField(name = "current_qn")
|
||||
private int currentQn;
|
||||
|
||||
@JSONField(name = "accept_qn")
|
||||
private List<Integer> acceptQn;
|
||||
|
||||
@JSONField(name = "base_url")
|
||||
private String baseUrl;
|
||||
|
||||
@JSONField(name = "url_info")
|
||||
private List<UrlInfo> urlInfo;
|
||||
|
||||
@JSONField(name = "hdr_desc")
|
||||
private String hdrDesc;
|
||||
|
||||
@JSONField(name = "attr_desc")
|
||||
private Object attrDesc;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class UrlInfo {
|
||||
@JSONField(name = "host")
|
||||
private String host;
|
||||
|
||||
@JSONField(name = "extra")
|
||||
private String extra;
|
||||
|
||||
@JSONField(name = "stream_ttl")
|
||||
private int streamTtl;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class P2pData {
|
||||
@JSONField(name = "p2p")
|
||||
private boolean p2p;
|
||||
|
||||
@JSONField(name = "p2p_type")
|
||||
private int p2pType;
|
||||
|
||||
@JSONField(name = "m_p2p")
|
||||
private boolean mP2p;
|
||||
|
||||
@JSONField(name = "m_servers")
|
||||
private List<String> mServers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.yutou.bili.bean.live;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LiveRoomStatus {
|
||||
@JSONField(name = "roomStatus")
|
||||
private int roomStatus;
|
||||
|
||||
@JSONField(name = "roundStatus")
|
||||
private int roundStatus;
|
||||
|
||||
@JSONField(name = "liveStatus")
|
||||
private int liveStatus;
|
||||
|
||||
@JSONField(name = "url")
|
||||
private String url;
|
||||
|
||||
@JSONField(name = "title")
|
||||
private String title;
|
||||
|
||||
@JSONField(name = "cover")
|
||||
private String cover;
|
||||
|
||||
@JSONField(name = "online")
|
||||
private int online;
|
||||
|
||||
@JSONField(name = "roomid")
|
||||
private int roomid;
|
||||
|
||||
@JSONField(name = "broadcast_type")
|
||||
private int broadcastType;
|
||||
|
||||
@JSONField(name = "online_hidden")
|
||||
private int onlineHidden;
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package com.yutou.bili.bean.live;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.yutou.okhttp.BaseBean;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MasterInfoBean extends BaseBean {
|
||||
@JSONField(name = "info")
|
||||
private Info info;
|
||||
|
||||
@JSONField(name = "exp")
|
||||
private Exp exp;
|
||||
|
||||
@JSONField(name = "follower_num")
|
||||
private int followerNum;
|
||||
|
||||
@JSONField(name = "room_id")
|
||||
private int roomId;
|
||||
|
||||
@JSONField(name = "medal_name")
|
||||
private String medalName;
|
||||
|
||||
@JSONField(name = "glory_count")
|
||||
private int gloryCount;
|
||||
|
||||
@JSONField(name = "pendant")
|
||||
private String pendant;
|
||||
|
||||
@JSONField(name = "link_group_num")
|
||||
private int linkGroupNum;
|
||||
|
||||
@JSONField(name = "room_news")
|
||||
private RoomNews roomNews;
|
||||
|
||||
@Data
|
||||
public static class Info {
|
||||
@JSONField(name = "uid")
|
||||
private int uid;
|
||||
|
||||
@JSONField(name = "uname")
|
||||
private String uname;
|
||||
|
||||
@JSONField(name = "face")
|
||||
private String face;
|
||||
|
||||
@JSONField(name = "official_verify")
|
||||
private OfficialVerify officialVerify;
|
||||
|
||||
@JSONField(name = "gender")
|
||||
private int gender;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Exp {
|
||||
@JSONField(name = "master_level")
|
||||
private MasterLevel masterLevel;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MasterLevel {
|
||||
@JSONField(name = "level")
|
||||
private int level;
|
||||
|
||||
@JSONField(name = "color")
|
||||
private int color;
|
||||
|
||||
@JSONField(name = "current")
|
||||
private List<Integer> current;
|
||||
|
||||
@JSONField(name = "next")
|
||||
private List<Integer> next;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class OfficialVerify {
|
||||
@JSONField(name = "type")
|
||||
private int type;
|
||||
|
||||
@JSONField(name = "desc")
|
||||
private String desc;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class RoomNews {
|
||||
@JSONField(name = "content")
|
||||
private String content;
|
||||
|
||||
@JSONField(name = "ctime")
|
||||
private String ctime;
|
||||
|
||||
@JSONField(name = "ctime_text")
|
||||
private String ctimeText;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.yutou.bili.bean.login;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.yutou.okhttp.BaseBean;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class CheckCookieBean extends BaseBean {
|
||||
@JSONField(name = "refresh")
|
||||
boolean refresh;
|
||||
@JSONField(name = "timestamp")
|
||||
long timestamp;
|
||||
}
|
@ -35,12 +35,16 @@ public class BiliBiliLoginDatabase extends SQLiteManager {
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<LoginCookie> get() {
|
||||
return super.get(cookie.getTableName(), LoginCookie.class);
|
||||
public LoginCookie get() {
|
||||
List<LoginCookie> list = super.get(cookie.getTableName(), LoginCookie.class);
|
||||
if (!list.isEmpty()) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LoginCookie getDataBean() {
|
||||
protected LoginCookie getDataBean() {
|
||||
return new LoginCookie();
|
||||
}
|
||||
}
|
||||
|
23
biliapi/src/main/java/com/yutou/bili/enums/LiveProtocol.java
Normal file
23
biliapi/src/main/java/com/yutou/bili/enums/LiveProtocol.java
Normal file
@ -0,0 +1,23 @@
|
||||
package com.yutou.bili.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum LiveProtocol {
|
||||
stream(0),
|
||||
hls(1);
|
||||
|
||||
private final int value;
|
||||
|
||||
private LiveProtocol(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static String getAll() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (LiveProtocol value : values()) {
|
||||
sb.append(String.valueOf(value.value)).append(",");
|
||||
}
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.yutou.bili.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum LiveVideoCodec {
|
||||
AVC(0),
|
||||
HEVC(1);
|
||||
|
||||
private final int value;
|
||||
|
||||
private LiveVideoCodec(int value) {
|
||||
this.value=value;
|
||||
}
|
||||
public static String getAll() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (LiveVideoCodec value : values()) {
|
||||
sb.append(String.valueOf(value.value)).append(",");
|
||||
}
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.yutou.bili.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum LiveVideoDefinition {
|
||||
|
||||
LOW(80), // 流畅
|
||||
HIGH(150), // 高清
|
||||
SUPER(250), // 超清
|
||||
BLU_RAY(400), // 蓝光
|
||||
ORIGINAL(10000), // 原画
|
||||
V4K(20000),
|
||||
DOLBY(30000);
|
||||
|
||||
private final int value;
|
||||
|
||||
private LiveVideoDefinition(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
public static String getAll() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (LiveVideoDefinition value : values()) {
|
||||
sb.append(String.valueOf(value.value)).append(",");
|
||||
}
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.yutou.bili.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum LiveVideoFormat {
|
||||
FLV(0),
|
||||
TS(1),
|
||||
FMP4(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
private LiveVideoFormat(int value) {
|
||||
this.value=value;
|
||||
}
|
||||
public static String getAll() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (LiveVideoFormat value : values()) {
|
||||
sb.append(String.valueOf(value.value)).append(",");
|
||||
}
|
||||
return sb.substring(0, sb.length() - 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.yutou.bili.net;
|
||||
|
||||
import com.yutou.bili.bean.login.CheckCookieBean;
|
||||
import com.yutou.bili.bean.login.LoginInfoBean;
|
||||
import com.yutou.inter.IHttpApiCheckCallback;
|
||||
import com.yutou.okhttp.HttpCallback;
|
||||
import com.yutou.utils.RSAUtils;
|
||||
import okhttp3.Headers;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.OAEPParameterSpec;
|
||||
import javax.crypto.spec.PSource;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.MGF1ParameterSpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
public class BiliCookieManager {
|
||||
public static final int COOKIE_INVALID = -101;
|
||||
public static final int COOKIE_SUCCESS = 0;
|
||||
|
||||
private static final String PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" +
|
||||
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLgd2OAkcGVtoE3ThUREbio0Eg\n" +
|
||||
"Uc/prcajMKXvkCKFCWhJYJcLkcM2DKKcSeFpD/j6Boy538YXnR6VhcuUJOhH2x71\n" +
|
||||
"nzPjfdTcqMz7djHum0qSZA0AyCBDABUqCrfNgCiJ00Ra7GmRj+YCK1NJEuewlb40\n" +
|
||||
"JNrRuoEUXpabUzGB8QIDAQAB\n" +
|
||||
"-----END PUBLIC KEY-----";
|
||||
|
||||
public void checkCookie(IHttpApiCheckCallback<Integer> callback){
|
||||
BiliLoginNetApiManager.getInstance().getLoginApi(true)
|
||||
.checkCookie().enqueue(new HttpCallback<CheckCookieBean>() {
|
||||
@Override
|
||||
public void onResponse(Headers headers, int code, String status, CheckCookieBean response, String rawResponse) {
|
||||
if(code==-101){
|
||||
// TODO cookie失效,需要重新登录
|
||||
callback.onError(COOKIE_INVALID,"cookie失效,需要重新登录");
|
||||
return;
|
||||
}
|
||||
if(response.isRefresh()){
|
||||
refreshCookie();
|
||||
}
|
||||
callback.onSuccess(COOKIE_SUCCESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href="https://socialsisteryi.github.io/bilibili-API-collect/docs/login/cookie_refresh.html#java">文档地址</a>
|
||||
*/
|
||||
private void refreshCookie(){
|
||||
try {
|
||||
String refreshTime = String.format("refresh_%d", System.currentTimeMillis());
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
String publicKeyStr = PUBLIC_KEY
|
||||
.replace("-----BEGIN PUBLIC KEY-----", "")
|
||||
.replace("-----END PUBLIC KEY-----", "")
|
||||
.replace("\n", "")
|
||||
.trim();
|
||||
byte[] publicBytes = Base64.getDecoder().decode(publicKeyStr);
|
||||
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicBytes);
|
||||
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
|
||||
|
||||
String algorithm = "RSA/ECB/OAEPPadding";
|
||||
Cipher cipher = Cipher.getInstance(algorithm);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
|
||||
// Encode the plaintext to bytes
|
||||
byte[] plaintextBytes = refreshTime.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
// Add OAEP padding to the plaintext bytes
|
||||
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams);
|
||||
// Encrypt the padded plaintext bytes
|
||||
byte[] encryptedBytes = cipher.doFinal(plaintextBytes);
|
||||
// Convert the encrypted bytes to a Base64-encoded string
|
||||
String encrypted = new BigInteger(1, encryptedBytes).toString(16);
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.yutou.bili.net;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.yutou.bili.api.LiveApi;
|
||||
import com.yutou.bili.bean.login.LoginCookie;
|
||||
import com.yutou.bili.databases.BiliBiliLoginDatabase;
|
||||
import com.yutou.inter.IHttpApiCheckCallback;
|
||||
import com.yutou.okhttp.api.BaseApi;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class BiliLiveNetApiManager extends BaseApi {
|
||||
private static BiliLiveNetApiManager instance;
|
||||
|
||||
public static BiliLiveNetApiManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new BiliLiveNetApiManager("https://api.live.bilibili.com");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private BiliLiveNetApiManager(String URL) {
|
||||
super(URL);
|
||||
}
|
||||
|
||||
public void getApi(IHttpApiCheckCallback<LiveApi> callback) {
|
||||
LoginCookie cookie = BiliBiliLoginDatabase.getInstance().get();
|
||||
if (cookie != null) {
|
||||
useCookie(JSONObject.parseObject(JSONObject.toJSONString(cookie)));
|
||||
}
|
||||
HashMap<String,String> header=new HashMap<>();
|
||||
header.put("Accept-Language", "zh-CN,zh;q=0.8");
|
||||
header.put("Referer", "https://live.bilibili.com");
|
||||
header.put("Connection", "keep-alive");
|
||||
header.put("Upgrade-Insecure-Requests", "1");
|
||||
setHeaders(header);
|
||||
callback.onSuccess(createApi(LiveApi.class));
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ import com.yutou.bili.bean.login.LoginCookie;
|
||||
import com.yutou.bili.bean.login.LoginInfoBean;
|
||||
import com.yutou.bili.bean.login.QRCodeGenerateBean;
|
||||
import com.yutou.bili.databases.BiliBiliLoginDatabase;
|
||||
import com.yutou.databases.AbsDatabasesBean;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
import com.yutou.okhttp.HttpCallback;
|
||||
import com.yutou.okhttp.api.BaseApi;
|
||||
@ -38,10 +37,24 @@ public class BiliLoginNetApiManager extends BaseApi {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public LoginApi getLoginApi() {
|
||||
return getLoginApi(false);
|
||||
}
|
||||
|
||||
public LoginApi getLoginApi(boolean isCookie) {
|
||||
if (isCookie) {
|
||||
LoginCookie cookie = BiliBiliLoginDatabase.getInstance().get();
|
||||
if (cookie != null) {
|
||||
useCookie(JSONObject.parseObject(JSONObject.toJSONString(cookie)));
|
||||
}
|
||||
}
|
||||
return loginApi;
|
||||
}
|
||||
|
||||
public void login(HttpCallback<LoginCookie> callback) {
|
||||
List<LoginCookie> cookie = BiliBiliLoginDatabase.getInstance().get();
|
||||
if (!cookie.isEmpty()) {
|
||||
callback.onResponse(null, LOGIN_SUCCESS, null, cookie.get(0), null);
|
||||
LoginCookie cookie = BiliBiliLoginDatabase.getInstance().get();
|
||||
if (cookie != null) {
|
||||
callback.onResponse(null, LOGIN_SUCCESS, null, cookie, null);
|
||||
return;
|
||||
}
|
||||
loginApi.getQRCodeGenerate().enqueue(new HttpCallback<QRCodeGenerateBean>() {
|
||||
|
@ -27,12 +27,11 @@ public class BiliUserNetApiManager extends BaseApi {
|
||||
}
|
||||
|
||||
public void getUserApi(IHttpApiCheckCallback<UserApi> callback) {
|
||||
List<LoginCookie> list = BiliBiliLoginDatabase.getInstance().get();
|
||||
if (!list.isEmpty()) {
|
||||
LoginCookie cookie = BiliBiliLoginDatabase.getInstance().get();
|
||||
if (cookie != null) {
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
LoginCookie cookie = list.get(0);
|
||||
JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(cookie));
|
||||
StringBuilder ck=new StringBuilder();
|
||||
StringBuilder ck = new StringBuilder();
|
||||
for (String key : json.keySet()) {
|
||||
ck.append(key).append("=").append(json.getString(key)).append("; ");
|
||||
}
|
||||
|
230
biliapi/src/main/java/com/yutou/bili/net/WebSocketManager.java
Normal file
230
biliapi/src/main/java/com/yutou/bili/net/WebSocketManager.java
Normal file
@ -0,0 +1,230 @@
|
||||
package com.yutou.bili.net;
|
||||
|
||||
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.inter.IHttpApiCheckCallback;
|
||||
import com.yutou.okhttp.HttpCallback;
|
||||
import jakarta.xml.bind.DatatypeConverter;
|
||||
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;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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;
|
||||
Map<LiveRoomConfig, WebSocketClientTh> roomMap;
|
||||
|
||||
private WebSocketManager() {
|
||||
roomMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public static WebSocketManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new WebSocketManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void addRoom(LiveRoomConfig roomConfig) {
|
||||
BiliLiveNetApiManager.getInstance().getApi(new IHttpApiCheckCallback<LiveApi>() {
|
||||
@Override
|
||||
public void onSuccess(LiveApi api) {
|
||||
api.getLiveRoomDanmuInfo(roomConfig.getRoomId()).enqueue(new HttpCallback<LiveDanmuInfo>() {
|
||||
@Override
|
||||
public void onResponse(Headers headers, int code, String status, LiveDanmuInfo response, String rawResponse) {
|
||||
if (!response.getHostList().isEmpty()) {
|
||||
LiveDanmuInfo.Host host = response.getHostList().get(0);
|
||||
String url = "wss://" + host.getHost() + ":" + host.getWssPort() + "/sub";
|
||||
// url="ws://127.0.0.1:8765";
|
||||
try {
|
||||
roomConfig.setLiveInfo(response);
|
||||
new WebSocketClientTh(new URI(url), roomConfig);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String error) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class WebSocketClientTh extends WebSocketClient {
|
||||
private LiveRoomConfig roomConfig;
|
||||
private HeartbeatTask heartbeatTask;
|
||||
|
||||
|
||||
public WebSocketClientTh(URI serverUri, LiveRoomConfig roomId) {
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake serverHandshake) {
|
||||
WebSocketManager.getInstance().roomMap.put(roomConfig, this);
|
||||
heartbeatTask.setSocket(this);
|
||||
heartbeatTask.sendInitAuthData();
|
||||
new Timer().schedule(heartbeatTask, 0, 30000);
|
||||
System.out.println("WebSocketClientTh.onOpen");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String s) {
|
||||
System.out.println("s = " + s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer bytes) {
|
||||
System.out.println("WebSocketClientTh.onMessage");
|
||||
super.onMessage(bytes);
|
||||
decompress(bytes.array());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int i, String s, boolean b) {
|
||||
System.out.println("WebSocketClientTh.onClose");
|
||||
System.out.println("i = " + i + ", s = " + s + ", b = " + b);
|
||||
WebSocketManager.getInstance().roomMap.remove(roomConfig);
|
||||
heartbeatTask.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
System.out.println("WebSocketClientTh.onError");
|
||||
e.printStackTrace();
|
||||
WebSocketManager.getInstance().roomMap.remove(roomConfig);
|
||||
heartbeatTask.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压缩
|
||||
*
|
||||
* @param data 待压缩的数据
|
||||
*/
|
||||
public void decompress(byte[] data) {
|
||||
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);
|
||||
}
|
||||
System.out.println("接收值:" + new String(out.toByteArray()));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private class HeartbeatTask extends TimerTask {
|
||||
WebSocketClientTh socket;
|
||||
|
||||
public void setSocket(WebSocketClientTh socket) {
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
}
|
||||
|
||||
public void sendInitAuthData() {
|
||||
JSONObject json = new JSONObject();
|
||||
if (roomConfig.isLogin()) {
|
||||
json.put("uid", roomConfig.getUid());
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
}
|
||||
System.out.println("\n\n\n");
|
||||
System.out.println(socket.isOpen());
|
||||
socket.send(outputStream.toByteArray());
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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,69 @@
|
||||
package com.yutou.bili.utils;
|
||||
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LiveHeartBeat {
|
||||
private static LiveHeartBeat instance;
|
||||
private HeartBeatThread thread;
|
||||
Map<String,HeartBeatThread> heartBeatMap=new HashMap<>();
|
||||
|
||||
public static LiveHeartBeat getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new LiveHeartBeat();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private LiveHeartBeat() {
|
||||
}
|
||||
|
||||
public void addHeartBeat(String roomId) {
|
||||
if(heartBeatMap.containsKey(roomId)){
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void removeHeartBeat(String roomId) {
|
||||
}
|
||||
|
||||
public void endAllHeartBeat() {
|
||||
|
||||
}
|
||||
|
||||
public class HeartBeatThread extends WebSocketClient {
|
||||
|
||||
|
||||
public HeartBeatThread(URI serverUri) {
|
||||
super(serverUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake serverHandshake) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String s) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int i, String s, boolean b) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
common/src/main/java/com/yutou/okhttp/FileBody.java
Normal file
11
common/src/main/java/com/yutou/okhttp/FileBody.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
@Data
|
||||
public class FileBody<T> {
|
||||
InputStream inputStream;
|
||||
T t;
|
||||
}
|
103
common/src/main/java/com/yutou/okhttp/FileCallback.java
Normal file
103
common/src/main/java/com/yutou/okhttp/FileCallback.java
Normal file
@ -0,0 +1,103 @@
|
||||
package com.yutou.okhttp;
|
||||
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.HttpUrl;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class FileCallback<T> implements Callback<FileBody<T>> {
|
||||
|
||||
private static ThreadPoolExecutor executor;
|
||||
private final T bean;
|
||||
|
||||
|
||||
public FileCallback(T bean) {
|
||||
this.bean = bean;
|
||||
if (executor == null) {
|
||||
executor = new ThreadPoolExecutor(2, 4, Long.MAX_VALUE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadTask implements Runnable {
|
||||
private T bean;
|
||||
private Headers headers;
|
||||
private HttpUrl url;
|
||||
private InputStream inputStream;
|
||||
|
||||
public DownloadTask(T bean, Headers headers, HttpUrl url, InputStream inputStream) {
|
||||
this.bean = bean;
|
||||
|
||||
this.headers = headers;
|
||||
this.url = url;
|
||||
this.inputStream = inputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println("开始下载");
|
||||
File file = new File("download" + File.separator + System.currentTimeMillis() + ".flv");
|
||||
onStart(bean);
|
||||
if (!file.exists()) {
|
||||
boolean mkdirs = file.getParentFile().mkdirs();
|
||||
System.out.println("mkdirs = " + mkdirs);
|
||||
}
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
int len;
|
||||
long total = 0;
|
||||
byte[] bytes = new byte[4096];
|
||||
boolean isDownload = true;
|
||||
long available = inputStream.available();
|
||||
while ((len = inputStream.read(bytes)) != -1 && isDownload) {
|
||||
total += len;
|
||||
outputStream.write(bytes, 0, len);
|
||||
outputStream.flush();
|
||||
isDownload = onDownload(headers, bean, total, available);
|
||||
}
|
||||
System.out.println("下载完成");
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
onFinish(bean);
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void onStart(T bean);
|
||||
|
||||
public abstract boolean onDownload(Headers headers, T bean, long len, long total);
|
||||
|
||||
public abstract void onFinish(T bean);
|
||||
|
||||
public abstract void onFailure(T bean, Throwable throwable);
|
||||
|
||||
@Override
|
||||
public void onResponse(Call<FileBody<T>> call, Response<FileBody<T>> response) {
|
||||
executor.execute(new DownloadTask(bean, response.headers(), call.request().url(), response.body().getInputStream()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<FileBody<T>> call, Throwable throwable) {
|
||||
onFailure(bean, throwable);
|
||||
call.cancel();
|
||||
}
|
||||
|
||||
}
|
@ -38,6 +38,7 @@ public class ParamsContext {
|
||||
break;
|
||||
}
|
||||
headerMap.remove("tableName");
|
||||
headerMap.put("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36");
|
||||
return iRequestParam.getRequest(headerMap, map, request);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.yutou.okhttp.api;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.internal.bind.DateTypeAdapter;
|
||||
@ -7,10 +8,7 @@ import com.yutou.okhttp.HttpLoggingInterceptor;
|
||||
import com.yutou.okhttp.ParamsContext;
|
||||
import com.yutou.okhttp.converter.JsonCallAdapter;
|
||||
import com.yutou.okhttp.converter.JsonConverterFactory;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.*;
|
||||
import retrofit2.CallAdapter;
|
||||
import retrofit2.Converter;
|
||||
import retrofit2.Retrofit;
|
||||
@ -21,8 +19,8 @@ import java.util.HashMap;
|
||||
|
||||
public class BaseApi {
|
||||
private String URL;
|
||||
private HashMap<String, String> params;
|
||||
private HashMap<String, String> headers;
|
||||
private HashMap<String, String> params = new HashMap<>();
|
||||
private HashMap<String, String> headers = new HashMap<>();
|
||||
|
||||
public BaseApi(String URL) {
|
||||
this.URL = URL;
|
||||
@ -42,16 +40,24 @@ public class BaseApi {
|
||||
this.params = params;
|
||||
return this;
|
||||
}
|
||||
public void useCookie(JSONObject json){
|
||||
StringBuilder ck = new StringBuilder();
|
||||
for (String key : json.keySet()) {
|
||||
ck.append(key).append("=").append(json.getString(key)).append("; ");
|
||||
}
|
||||
headers.put("Cookie", ck.toString());
|
||||
setHeaders(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个接口方法
|
||||
*
|
||||
* @param okHttpClient okhttp客户端
|
||||
* @param converterFactory 处理工厂类
|
||||
* @param okHttpClient okhttp客户端
|
||||
* @param converterFactory 处理工厂类
|
||||
* @param callAdapterFactory 请求适配器工厂
|
||||
* @param baseUrl 基础地质
|
||||
* @param service 接口
|
||||
* @param <T> 接口泛型
|
||||
* @param baseUrl 基础地质
|
||||
* @param service 接口
|
||||
* @param <T> 接口泛型
|
||||
* @return 接口
|
||||
*/
|
||||
public <T> T create(OkHttpClient okHttpClient, Converter.Factory converterFactory, CallAdapter.Factory callAdapterFactory, String baseUrl, Class<T> service) {
|
||||
@ -92,13 +98,14 @@ public class BaseApi {
|
||||
URL,
|
||||
apiClass);
|
||||
}
|
||||
|
||||
public Interceptor initQuery() {
|
||||
Interceptor addQueryParameterInterceptor = new Interceptor() {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
//配置公共参数
|
||||
request = new ParamsContext(headers,params,request).getInRequest();
|
||||
request = new ParamsContext(headers, params, request).getInRequest();
|
||||
return chain.proceed(request);
|
||||
}
|
||||
};
|
||||
|
@ -2,9 +2,9 @@ package com.yutou.okhttp.converter;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.JSONReader;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.yutou.okhttp.FileBody;
|
||||
import com.yutou.okhttp.HttpBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -27,19 +27,25 @@ public class JsonResponseBodyConverter<T> implements Converter<ResponseBody, T>
|
||||
@Nullable
|
||||
@Override
|
||||
public T convert(ResponseBody responseBody) throws IOException {
|
||||
String string = new String(responseBody.bytes());
|
||||
responseBody.close();
|
||||
HttpBody<T> body;
|
||||
try {
|
||||
body = JSONObject.parseObject(string, type, JSONReader.Feature.FieldBased);
|
||||
body.setSrc(string);
|
||||
if (type.getTypeName().contains(HttpBody.class.getSimpleName())) {
|
||||
String string = new String(responseBody.bytes());
|
||||
responseBody.close();
|
||||
HttpBody<T> body;
|
||||
try {
|
||||
body = JSONObject.parseObject(string, type, JSONReader.Feature.FieldBased);
|
||||
body.setSrc(string);
|
||||
return (T) body;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
body = new HttpBody();
|
||||
body.setSrc(string);
|
||||
}
|
||||
return (T) body;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
body = new HttpBody();
|
||||
body.setSrc(string);
|
||||
}
|
||||
return (T) body;
|
||||
|
||||
} else {
|
||||
FileBody<T> body=new FileBody<T>();
|
||||
body.setInputStream(responseBody.byteStream());
|
||||
return (T) body;
|
||||
}
|
||||
}
|
||||
}
|
136
common/src/main/java/com/yutou/utils/RSAUtils.java
Normal file
136
common/src/main/java/com/yutou/utils/RSAUtils.java
Normal file
@ -0,0 +1,136 @@
|
||||
package com.yutou.utils;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.*;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RSAUtils {
|
||||
/**
|
||||
* 加密算法RSA
|
||||
*/
|
||||
public static final String KEY_ALGORITHM = "RSA";
|
||||
|
||||
/**
|
||||
* 签名算法
|
||||
*/
|
||||
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
|
||||
|
||||
/**
|
||||
* 获取公钥的key
|
||||
*/
|
||||
private static final String PUBLIC_KEY = "RSAPublicKey";
|
||||
|
||||
/**
|
||||
* 获取私钥的key
|
||||
*/
|
||||
private static final String PRIVATE_KEY = "RSAPrivateKey";
|
||||
|
||||
/**
|
||||
* RSA 密钥位数
|
||||
*/
|
||||
private static final int KEY_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* RSA最大解密密文大小
|
||||
*/
|
||||
private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / 8;
|
||||
|
||||
/**
|
||||
* RSA最大加密明文大小
|
||||
*/
|
||||
private static final int MAX_ENCRYPT_BLOCK = MAX_DECRYPT_BLOCK - 11;
|
||||
private static Map<Integer,String> keyMap=new HashMap<>();
|
||||
|
||||
/**
|
||||
* 随机生成密钥对
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public static void getKeyPair() throws Exception {
|
||||
//KeyPairGenerator类用于生成公钥和密钥对,基于RSA算法生成对象
|
||||
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
|
||||
//初始化密钥对生成器,密钥大小为96-1024位
|
||||
keyPairGen.initialize(1024,new SecureRandom());
|
||||
//生成一个密钥对,保存在keyPair中
|
||||
KeyPair keyPair = keyPairGen.generateKeyPair();
|
||||
PrivateKey privateKey = keyPair.getPrivate();//得到私钥
|
||||
PublicKey publicKey = keyPair.getPublic();//得到公钥
|
||||
//得到公钥字符串
|
||||
String publicKeyString=new String(Base64.encodeBase64(publicKey.getEncoded()));
|
||||
//得到私钥字符串
|
||||
String privateKeyString=new String(Base64.encodeBase64(privateKey.getEncoded()));
|
||||
//将公钥和私钥保存到Map
|
||||
keyMap.put(0,publicKeyString);//0表示公钥
|
||||
keyMap.put(1,privateKeyString);//1表示私钥
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* 公钥加密
|
||||
* </p>
|
||||
*
|
||||
* @param str 源数据
|
||||
* @param publicKey 公钥(BASE64编码)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String encryptByPublicKey(String str, String publicKey) throws Exception {
|
||||
publicKey=publicKey.replace("-----BEGIN PUBLIC KEY-----","").replace("-----END PUBLIC KEY-----","");
|
||||
byte[] data=Base64.decodeBase64(str);
|
||||
byte[] keyBytes = Base64.decodeBase64(publicKey);
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
|
||||
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
|
||||
Key publicK = keyFactory.generatePublic(x509KeySpec);
|
||||
// 对数据加密
|
||||
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicK);
|
||||
int inputLen = data.length;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int offSet = 0;
|
||||
byte[] cache;
|
||||
int i = 0;
|
||||
// 对数据分段加密
|
||||
while (inputLen - offSet > 0) {
|
||||
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
|
||||
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
|
||||
} else {
|
||||
cache = cipher.doFinal(data, offSet, inputLen - offSet);
|
||||
}
|
||||
out.write(cache, 0, cache.length);
|
||||
i++;
|
||||
offSet = i * MAX_ENCRYPT_BLOCK;
|
||||
}
|
||||
byte[] encryptedData = out.toByteArray();
|
||||
out.close();
|
||||
return new String(Base64.encodeBase64(encryptedData));
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA私钥解密
|
||||
*
|
||||
* @param str
|
||||
* 加密字符串
|
||||
* @param privateKey
|
||||
* 私钥
|
||||
* @return 铭文
|
||||
* @throws Exception
|
||||
* 解密过程中的异常信息
|
||||
*/
|
||||
public static String decrypt(String str,String privateKey) throws Exception {
|
||||
//Base64解码加密后的字符串
|
||||
byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
|
||||
//Base64编码的私钥
|
||||
byte[] decoded = Base64.decodeBase64(privateKey);
|
||||
PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
|
||||
//RSA解密
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE,priKey);
|
||||
String outStr=new String(cipher.doFinal(inputByte));
|
||||
return outStr;
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user