修正 SEND_GIFT 数据包的结构

This commit is contained in:
czp 2018-03-14 11:23:08 +08:00
parent 2250f7003b
commit 6109d5f33e
12 changed files with 806 additions and 316 deletions

View File

@ -1,73 +1,85 @@
{ {
"cmd": "SEND_GIFT", "cmd": "SEND_GIFT",
"data": { "data": {
"giftName": "\u4ebf\u5706", "giftName": "节奏风暴",
"num": 1, "num": 1,
"uname": "\u30c5\u4ee3\u6211\u56de\u5bb6", "uname": "爱上熹",
"rcost": 106855699, "rcost": 569788,
"uid": 14146398, "uid": 230845505,
"top_list": [ "top_list": [
{ {
"uid": 10952886, "uid": 288348879,
"uname": "\u5b89\u4e36\u664b", "uname": "我爱我家一生",
"coin": 498900, "face": "http://i1.hdslb.com/bfs/face/dd52e4f2dfe881751816e45522f504f10458b514.jpg",
"face": "http://static.hdslb.com/images/member/noface.gif",
"guard_level": 0,
"rank": 1, "rank": 1,
"score": 498900 "score": 1852300,
},
{
"uid": 13174983,
"uname": "-\u56db\u5b63\u8c46-",
"coin": 384300,
"face": "http://i0.hdslb.com/bfs/face/23f9f57a69378736f68b50fc4cac4f6b01683e97.jpg",
"guard_level": "3",
"rank": 2,
"score": 384300
},
{
"uid": 87444977,
"uname": "\u964c\u964c\u821e\u98ce",
"coin": 377700,
"face": "http://i2.hdslb.com/bfs/face/c06c835bf8ed6401535847bf21e78d4d3b89d402.jpg",
"guard_level": 0, "guard_level": 0,
"isSelf": 0
},
{
"uid": 287551243,
"uname": "熹上城的专属天使菲",
"face": "http://i1.hdslb.com/bfs/face/c3ef04ba6c267c41067cd7708b7abd60c0c5c49f.jpg",
"rank": 2,
"score": 1245200,
"guard_level": 3,
"isSelf": 0
},
{
"uid": 32416351,
"uname": "镜子。。",
"face": "http://i1.hdslb.com/bfs/face/08c54c2c97434811a99e9d070d621ccbb5d3f2c4.jpg",
"rank": 3, "rank": 3,
"score": 377700 "score": 332862,
"guard_level": 3,
"isSelf": 0
} }
], ],
"timestamp": 1510565032, "timestamp": 1520992553,
"giftId": 6, "giftId": 39,
"giftType": 0, "giftType": 0,
"action": "\u8d60\u9001", "action": "赠送",
"super": 0, "super": 1,
"price": 1000, "price": 100000,
"rnd": "541907145", "rnd": "1980508331",
"newMedal": 0, "newMedal": 0,
"newTitle": 0, "newTitle": 0,
"medal": [], "medal": {
"medalId": "95723",
"medalName": "布丁诶",
"level": 1
},
"title": "", "title": "",
"beatId": "", "beatId": "4",
"biz_source": "live", "biz_source": "live",
"metadata": "", "metadata": "",
"remain": 0, "remain": 0,
"gold": 0, "gold": 88570,
"silver": 0, "silver": 127492,
"eventScore": 0, "eventScore": 0,
"eventNum": 0, "eventNum": 0,
"smalltv_msg": [], "smalltv_msg": [],
"specialGift": null, "specialGift": {
"id": 207945,
"time": 90,
"hadJoin": 0,
"num": 1,
"content": "你们城里人真会玩",
"action": "start",
"storm_gif": "http://static.hdslb.com/live-static/live-room/images/gift-section/mobilegift/2/jiezou.gif?2017011901"
},
"notice_msg": [], "notice_msg": [],
"capsule": { "capsule": {
"normal": { "normal": {
"coin": 6, "coin": 166,
"change": 0, "change": 10,
"progress": { "progress": {
"now": 4800, "now": 3630,
"max": 10000 "max": 10000
} }
}, },
"colorful": { "colorful": {
"coin": 0, "coin": 2,
"change": 0, "change": 0,
"progress": { "progress": {
"now": 0, "now": 0,
@ -75,6 +87,9 @@
} }
} }
}, },
"addFollow": 0 "addFollow": 0,
"effect_block": 0,
"coin_type": "gold",
"total_coin": 100000
} }
} }

View File

@ -1,11 +0,0 @@
{
"cmd": "SYS_GIFT",
"msg": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
"msg_text": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
"tips": "sakamakiryoryo\u5728\u76f4\u64ad\u95f471084\u5f00\u542f\u4e86\u4e30\u6536\u796d\u5178\uff0c\u4e00\u8d77\u6765\u5206\u4eab\u6536\u83b7\u7684\u798f\u5229\u5427\uff01",
"url": "http:\/\/live.bilibili.com\/71084",
"roomid": 71084,
"real_roomid": 71084,
"giftId": 102,
"msgTips": 0
}

View File

@ -1,11 +0,0 @@
{
"cmd": "SYS_GIFT",
"msg": "小螃海白翼OuO在直播间5540554开启了新春抽奖红包大派送啦一起来沾沾喜气吧",
"msg_text": "小螃海白翼OuO在直播间5540554开启了新春抽奖红包大派送啦一起来沾沾喜气吧",
"tips": "小螃海白翼OuO在直播间5540554开启了新春抽奖红包大派送啦一起来沾沾喜气吧",
"url": "http://live.bilibili.com/5540554 ",
"roomid": 5540554,
"real_roomid": 5540554,
"giftId": 113,
"msgTips": 0
}

View File

@ -0,0 +1,11 @@
{
"cmd": "SYS_GIFT",
"msg": "【情怀家的尹蓝ovo】在直播间【147191】洒下漫天花雨快来拾撷桃花邂逅你的缘分",
"msg_text": "【情怀家的尹蓝ovo】在直播间【147191】洒下漫天花雨快来拾撷桃花邂逅你的缘分",
"tips": "【情怀家的尹蓝ovo】在直播间【147191】洒下漫天花雨快来拾撷桃花邂逅你的缘分",
"url": "http://live.bilibili.com/147191",
"roomid": 147191,
"real_roomid": 147191,
"giftId": 116,
"msgTips": 0
}

View File

@ -1,12 +1,12 @@
{ {
"cmd": "SYS_MSG", "cmd": "SYS_MSG",
"msg": "\u3010\u5e7d\u5c0f\u591c\u5929\u5c0f\u52ab\u3011:?\u5728\u76f4\u64ad\u95f4:?\u3010392\u3011:?\u8d60\u9001 \u5c0f\u7535\u89c6\u4e00\u4e2a\uff0c\u8bf7\u524d\u5f80\u62bd\u5956", "msg": "【天南地狗-】:?在直播间:?【531】:?赠送 小电视一个,请前往抽奖",
"msg_text": "\u3010\u5e7d\u5c0f\u591c\u5929\u5c0f\u52ab\u3011:?\u5728\u76f4\u64ad\u95f4:?\u3010392\u3011:?\u8d60\u9001 \u5c0f\u7535\u89c6\u4e00\u4e2a\uff0c\u8bf7\u524d\u5f80\u62bd\u5956", "msg_text": "【天南地狗-】:?在直播间:?【531】:?赠送 小电视一个,请前往抽奖",
"rep": 1, "rep": 1,
"styleType": 2, "styleType": 2,
"url": "http:\/\/live.bilibili.com\/392", "url": "http://live.bilibili.com/531",
"roomid": 392, "roomid": 531,
"real_roomid": 71084, "real_roomid": 22237,
"rnd": 44332151, "rnd": 1520992662,
"tv_id": "29349" "tv_id": "40478"
} }

View File

@ -5,30 +5,50 @@ import com.hiczp.bilibili.api.live.entity.*;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.http.*; import retrofit2.http.*;
/* 常见参数含义 /**
mid: 用户 id, 也可能是指主播的用户 id * 常见参数含义
cid: 房间 id, 可以指 room_id 也可以指 show_room_id, 推荐所有 API 都使用 room_id 进行访问 * mid: 用户 id, 也可能是指主播的用户 id
*/ * cid: 房间 id, 可以指 room_id 也可以指 show_room_id, 推荐所有 API 都使用 room_id 进行访问
*/
public interface LiveService { public interface LiveService {
//type 必须是 "all", 否则返回的所有字段的值都是 0 /**
* 获取弹幕设置
*
* @param type 必须是 "all", 否则返回的所有字段的值都是 0
*/
@GET("AppRoom/danmuConfig") @GET("AppRoom/danmuConfig")
Call<BulletScreenConfigEntity> getBulletScreenConfig(@Query("type") String type); Call<BulletScreenConfigEntity> getBulletScreenConfig(@Query("type") String type);
/**
* 获取弹幕设置的快捷调用
*/
default Call<BulletScreenConfigEntity> getBulletScreenConfig() { default Call<BulletScreenConfigEntity> getBulletScreenConfig() {
return getBulletScreenConfig("all"); return getBulletScreenConfig("all");
} }
//获得房间的历史弹幕(十条) /**
* 获得房间的历史弹幕(十条)
*
* @param roomId 房间号
*/
@GET("AppRoom/msg") @GET("AppRoom/msg")
Call<LiveHistoryBulletScreensEntity> getHistoryBulletScreens(@Query("room_id") long roomId); Call<LiveHistoryBulletScreensEntity> getHistoryBulletScreens(@Query("room_id") long roomId);
//获取直播间信息 /**
//登录后访问该 API 将在服务器新增一条直播间观看历史 * 获取直播间信息
* 登录后访问该 API 将在服务器新增一条直播间观看历史
*
* @param roomId 房间号
*/
@GET("AppRoom/index") @GET("AppRoom/index")
Call<LiveRoomInfoEntity> getRoomInfo(@Query("room_id") long roomId); Call<LiveRoomInfoEntity> getRoomInfo(@Query("room_id") long roomId);
//获得是否关注了一个主播 /**
//未登录时返回 401 * 获得是否关注了一个主播
* 未登录时返回 401
*
* @param hostUserId 主播的用户 ID
*/
@POST("feed/v1/feed/isFollowed") @POST("feed/v1/feed/isFollowed")
Call<IsFollowedResponseEntity> isFollowed(@Query("follow") long hostUserId); Call<IsFollowedResponseEntity> isFollowed(@Query("follow") long hostUserId);
@ -37,34 +57,56 @@ public interface LiveService {
@GET("AppBag/sendDaily") @GET("AppBag/sendDaily")
Call<SendDailyResponseEntity> sendDaily(); Call<SendDailyResponseEntity> sendDaily();
//获得所有礼物的列表 /**
* 获得所有礼物的列表
*/
@GET("AppIndex/getAllItem") @GET("AppIndex/getAllItem")
Call<ItemsEntity> getAllItem(); Call<ItemsEntity> getAllItem();
//查看可用的小电视抽奖 /**
//当目标房间没有可用的小电视抽奖时返回 -400 * 查看可用的小电视抽奖
* 当目标房间没有可用的小电视抽奖时返回 -400
*
* @param roomId 房间号
*/
@GET("AppSmallTV/index") @GET("AppSmallTV/index")
Call<AppSmallTVEntity> getAppSmallTV(@Query("roomid") long roomId); Call<AppSmallTVEntity> getAppSmallTV(@Query("roomid") long roomId);
//参与小电视抽奖 /**
//房间号必须与小电视号对应 * 参与小电视抽奖
//目标小电视不存在时(房间号与小电视号不匹配时也视为不存在)返回 -400 "不存在小电视信息" * 房间号必须与小电视号对应
//SYS_MSG 里面取得的小电视编号是一个字符串, 实际上它肯定是一个数字 * 目标小电视不存在时(房间号与小电视号不匹配时也视为不存在)返回 -400 "不存在小电视信息"
* SYS_MSG 里面取得的小电视编号是一个字符串, 实际上它肯定是一个数字
*
* @param roomId 房间号
* @param tvId 小电视号
*/
@POST("AppSmallTV/join") @POST("AppSmallTV/join")
Call<JoinAppSmallTVResponseEntity> joinAppSmallTV(@Query("roomid") long roomId, @Query("id") String tvId); Call<JoinAppSmallTVResponseEntity> joinAppSmallTV(@Query("roomid") long roomId, @Query("id") String tvId);
//通过 getAppSmallTV 取得的小电视编号是一个数字 /**
* 通过 getAppSmallTV 取得的小电视编号是一个数字
*
* @param roomId 房间号
* @param tvId 小电视号
*/
default Call<JoinAppSmallTVResponseEntity> joinAppSmallTV(long roomId, long tvId) { default Call<JoinAppSmallTVResponseEntity> joinAppSmallTV(long roomId, long tvId) {
return joinAppSmallTV(roomId, String.valueOf(tvId)); return joinAppSmallTV(roomId, String.valueOf(tvId));
} }
//获得小电视抽奖结果(不访问这个 API, 奖励也会自动进入背包) /**
//其中的 status 0 , 表示返回正常开奖结果, 1 为没有参与抽奖或小电视已过期, 2 为正在开奖过程中. * 获得小电视抽奖结果(不访问这个 API, 奖励也会自动进入背包)
*
* @param tvId 小电视号
* @return 返回内容中的 status 0 , 表示返回正常开奖结果, 1 为没有参与抽奖或小电视已过期, 2 为正在开奖过程中
*/
@GET("AppSmallTV/getReward") @GET("AppSmallTV/getReward")
Call<GetAppSmallTVRewardResponseEntity> getAppSmallTVReward(@Query("id") long tvId); Call<GetAppSmallTVRewardResponseEntity> getAppSmallTVReward(@Query("id") long tvId);
//获得所有头衔的列表 /**
//这里的 Title 是头衔的意思 * 获得所有头衔的列表
* 这里的 Title 是头衔的意思
*/
@GET("appUser/getTitle") @GET("appUser/getTitle")
Call<TitlesEntity> getTitle(); Call<TitlesEntity> getTitle();
@ -73,33 +115,67 @@ public interface LiveService {
Call<SpecialGiftEntity> getSpecialGift(@Path("roomId") long roomId); Call<SpecialGiftEntity> getSpecialGift(@Path("roomId") long roomId);
//TODO 参与节奏风暴抽奖 //TODO 参与节奏风暴抽奖
//获取自己的用户信息(live 站的个人信息, 非总站) /**
//未登录时返回 3 * 获取自己的用户信息(live 站的个人信息, 非总站)
* 未登录时返回 3
*/
@GET("mobile/getUser") @GET("mobile/getUser")
Call<UserInfoEntity> getUserInfo(); Call<UserInfoEntity> getUserInfo();
//获取一个直播间的流地址(flv) /**
//这里的 cid 必须用实际的 room_id, 不能使用 show_room_id, 否则得不到 playUrl. 实际 room_id 要首先通过 getRoomInfo() 获取 * 获取一个直播间的流地址(flv)
//outputType 为固定值 "json", 否则返回一个空的 JsonArray (以前是返回一个 XML) *
* @param cid 必须用实际的 room_id, 不能使用 show_room_id, 否则得不到 playUrl. 实际 room_id 要首先通过 getRoomInfo() 获取
* @param outputType 为固定值 "json", 否则返回一个空的 JsonArray (以前是返回一个 XML)
*/
@GET("api/playurl") @GET("api/playurl")
Call<PlayUrlEntity> getPlayUrl(@Query("cid") long cid, @Query("otype") String outputType); Call<PlayUrlEntity> getPlayUrl(@Query("cid") long cid, @Query("otype") String outputType);
/**
* 获取直播间推流地址的快捷调用
*
* @param cid 房间号
*/
default Call<PlayUrlEntity> getPlayUrl(long cid) { default Call<PlayUrlEntity> getPlayUrl(long cid) {
return getPlayUrl(cid, "json"); return getPlayUrl(cid, "json");
} }
//发送一个 Restful 心跳包, 五分钟一次. 这被用于统计观看直播的时间, 可以提升观众等级 /**
//2018-03-06 开始, 只有老爷才能通过观看直播获得经验 * 发送一个 Restful 心跳包, 五分钟一次. 这被用于统计观看直播的时间, 可以提升观众等级
//未登录时返回 3 * 2018-03-06 开始, 只有老爷才能通过观看直播获得经验
* 未登录时返回 3
*
* @param roomId 房间号
* @param scale 屏幕大小
*/
@POST("mobile/userOnlineHeart") @POST("mobile/userOnlineHeart")
@FormUrlEncoded @FormUrlEncoded
Call<SendOnlineHeartResponseEntity> sendOnlineHeart(@Field("room_id") long roomId, @Field("scale") String scale); Call<SendOnlineHeartResponseEntity> sendOnlineHeart(@Field("room_id") long roomId, @Field("scale") String scale);
/**
* 发送心跳包的快捷调用
*
* @param roomId 房间号
*/
default Call<SendOnlineHeartResponseEntity> sendOnlineHeart(long roomId) { default Call<SendOnlineHeartResponseEntity> sendOnlineHeart(long roomId) {
return sendOnlineHeart(roomId, BilibiliClientProperties.defaultSetting().getScale()); return sendOnlineHeart(roomId, BilibiliClientProperties.defaultSetting().getScale());
} }
//发送一条弹幕 /**
* 发送一条弹幕
*
* @param cid 房间号
* @param mid 自己的用户 ID
* @param message 内容
* @param random 随机数
* @param mode 弹幕模式
* @param pool 弹幕池
* @param type 必须为 "json"
* @param color 颜色
* @param fontSize 字体大小
* @param playTime 播放时间
* @see BulletScreenEntity
*/
@POST("api/sendmsg") @POST("api/sendmsg")
@FormUrlEncoded @FormUrlEncoded
Call<SendBulletScreenResponseEntity> sendBulletScreen(@Field("cid") long cid, Call<SendBulletScreenResponseEntity> sendBulletScreen(@Field("cid") long cid,
@ -113,6 +189,11 @@ public interface LiveService {
@Field("fontsize") int fontSize, @Field("fontsize") int fontSize,
@Field("playTime") String playTime); @Field("playTime") String playTime);
/**
* 发送弹幕的快捷调用
*
* @param bulletScreenEntity 弹幕实体类
*/
default Call<SendBulletScreenResponseEntity> sendBulletScreen(BulletScreenEntity bulletScreenEntity) { default Call<SendBulletScreenResponseEntity> sendBulletScreen(BulletScreenEntity bulletScreenEntity) {
return sendBulletScreen( return sendBulletScreen(
bulletScreenEntity.getCid(), bulletScreenEntity.getCid(),
@ -128,23 +209,43 @@ public interface LiveService {
); );
} }
//获取下一个宝箱任务的信息 /**
* 获取下一个宝箱任务的信息
*/
@GET("mobile/freeSilverCurrentTask") @GET("mobile/freeSilverCurrentTask")
Call<FreeSilverCurrentTaskEntity> getFreeSilverCurrentTask(); Call<FreeSilverCurrentTaskEntity> getFreeSilverCurrentTask();
//领取宝箱 /**
* 领取宝箱
*/
@GET("mobile/freeSilverAward") @GET("mobile/freeSilverAward")
Call<FreeSilverAwardEntity> getFreeSilverAward(); Call<FreeSilverAwardEntity> getFreeSilverAward();
//查看自己的背包(礼物) /**
* 查看自己的背包(礼物)
*/
@GET("AppBag/playerBag") @GET("AppBag/playerBag")
Call<PlayerBagEntity> getPlayerBag(); Call<PlayerBagEntity> getPlayerBag();
//查看哪些礼物是活动礼物, 在客户端上, 活动礼物会有一个右上角标记 "活动" /**
* 查看哪些礼物是活动礼物, 在客户端上, 活动礼物会有一个右上角标记 "活动"
*
* @param roomId 房间号
*/
@GET("AppRoom/activityGift") @GET("AppRoom/activityGift")
Call<ActivityGiftsEntity> getActivityGifts(@Query("room_id") long roomId); Call<ActivityGiftsEntity> getActivityGifts(@Query("room_id") long roomId);
//送礼物 /**
* 送礼物
*
* @param giftId 礼物 ID
* @param number 数量
* @param roomUserId 主播的用户 ID
* @param roomId 房间号
* @param timeStamp 时间戳
* @param bagId 礼物在自己背包里的 ID
* @param random 随机数
*/
@POST("AppBag/send") @POST("AppBag/send")
@FormUrlEncoded @FormUrlEncoded
Call<SendGiftResponseEntity> sendGift(@Field("giftId") long giftId, Call<SendGiftResponseEntity> sendGift(@Field("giftId") long giftId,
@ -155,6 +256,11 @@ public interface LiveService {
@Field("bag_id") long bagId, @Field("bag_id") long bagId,
@Field("rnd") long random); @Field("rnd") long random);
/**
* 送礼物的快捷调用
*
* @param giftEntity 礼物实体类
*/
default Call<SendGiftResponseEntity> sendGift(GiftEntity giftEntity) { default Call<SendGiftResponseEntity> sendGift(GiftEntity giftEntity) {
return sendGift( return sendGift(
giftEntity.getGiftId(), giftEntity.getGiftId(),
@ -167,32 +273,56 @@ public interface LiveService {
); );
} }
//获得礼物榜(七日榜) /**
* 获得礼物榜(七日榜)
*
* @param roomId 房间号
*/
@GET("AppRoom/getGiftTop") @GET("AppRoom/getGiftTop")
Call<GiftTopEntity> getGiftTop(@Query("room_id") int roomId); Call<GiftTopEntity> getGiftTop(@Query("room_id") int roomId);
//"直播" 页面(这个页面对应的后台数据, 包括 banner, 推荐主播, 各种分区的推荐等) /**
//这个 API 会读取 "_device"(固定参数) 或者 "device" 来判断平台, 只需要有一个就能正常工作, 客户端上是两个都有, 且值都为 "android" * "直播" 页面(这个页面对应的后台数据, 包括 banner, 推荐主播, 各种分区的推荐等)
*
* @param device 这个 API 会读取 "_device"(固定参数) 或者 "device" 来判断平台, 只需要有一个就能正常工作, 客户端上是两个都有, 且值都为 "android"
*/
@GET("room/v1/AppIndex/getAllList") @GET("room/v1/AppIndex/getAllList")
Call<AllListEntity> getAllList(@Query("device") String device); Call<AllListEntity> getAllList(@Query("device") String device);
/**
* 获取 "直播" 页面数据的快捷调用
*/
default Call<AllListEntity> getAllList() { default Call<AllListEntity> getAllList() {
return getAllList("android"); return getAllList("android");
} }
//刷新 "推荐主播" 区域, 必须有 device, platform, scala /**
//scala xxhdpi 时返回 12 , 客户端显示六个, 刷新两次后再次访问该 API * 刷新 "推荐主播" 区域, 必须有 device, platform, scala
// API 返回的内容结构与 getAllList 返回的内容中的 recommend_data 字段是一样的 * scala xxhdpi 时返回 12 , 客户端显示六个, 刷新两次后再次访问该 API
// API 返回的 banner_data 是在普通分区的推荐的上面的那个 banner, 在新版 APP , 点击这个 banner 会固定的跳转到 bilibili 相簿的 画友 标签页 * API 返回的内容结构与 getAllList 返回的内容中的 recommend_data 字段是一样的
* API 返回的 banner_data 是在普通分区的推荐的上面的那个 banner, 在新版 APP , 点击这个 banner 会固定的跳转到 bilibili 相簿的 画友 标签页
*
* @param device 设备类型
*/
@GET("room/v1/AppIndex/recRefresh") @GET("room/v1/AppIndex/recRefresh")
Call<RecommendRoomRefreshResponseEntity> recommendRefresh(@Query("device") String device); Call<RecommendRoomRefreshResponseEntity> recommendRefresh(@Query("device") String device);
/**
* 刷新 "推荐主播" 区域 的快捷调用
*/
default Call<RecommendRoomRefreshResponseEntity> recommendRefresh() { default Call<RecommendRoomRefreshResponseEntity> recommendRefresh() {
return recommendRefresh("android"); return recommendRefresh("android");
} }
//获取对应分类和状态的直播间 /**
//cate_id 不明确其含义 * 获取对应分类和状态的直播间
*
* @param areaId 分区 ID
* @param categoryId 不明确其含义
* @param parentAreaId 父分区 ID
* @param sortType 排序方式
* @param page 页码, 可以为 null(第一页)
*/
@GET("room/v1/Area/getRoomList") @GET("room/v1/Area/getRoomList")
Call<RoomListEntity> getRoomList( Call<RoomListEntity> getRoomList(
@Query("area_id") int areaId, @Query("area_id") int areaId,
@ -202,102 +332,179 @@ public interface LiveService {
@Query("page") Long page @Query("page") Long page
); );
//直播页面 下面的 普通分区(复数) 的刷新, 一次会返回 20 个结果, 客户端显示 6 , 数据用完了之后再次访问该 API /**
* 直播页面 下面的 普通分区(复数) 的刷新, 一次会返回 20 个结果, 客户端显示 6 , 数据用完了之后再次访问该 API
*
* @param parentAreaId 父分区 ID
*/
default Call<RoomListEntity> getRoomList(int parentAreaId) { default Call<RoomListEntity> getRoomList(int parentAreaId) {
return getRoomList(0, 0, parentAreaId, "dynamic", null); return getRoomList(0, 0, parentAreaId, "dynamic", null);
} }
//直播 -> 某个分区 -> 查看更多 /**
//获取该页面上方的分类标签 * 直播 -> 某个分区 -> 查看更多
* 获取该页面上方的分类标签
*
* @param parentAreaId 父分区 ID
*/
@GET("room/v1/Area/getList") @GET("room/v1/Area/getList")
Call<AreaListEntity> getAreaList(@Query("parent_id") int parentAreaId); Call<AreaListEntity> getAreaList(@Query("parent_id") int parentAreaId);
//获取该页面下的的直播间(areaId 0 表示选择了 "全部"(上方的分类标签), areaId 如果和 parentAreaId 不匹配将返回空的 data 字段) /**
* 获取该页面下的的直播间(areaId 0 表示选择了 "全部"(上方的分类标签), areaId 如果和 parentAreaId 不匹配将返回空的 data 字段)
*
* @param areaId 分区 ID
* @param parentAreaId 父分区 ID
* @param page 页码
*/
default Call<RoomListEntity> getRoomList(int areaId, int parentAreaId, long page) { default Call<RoomListEntity> getRoomList(int areaId, int parentAreaId, long page) {
return getRoomList(areaId, 0, parentAreaId, "online", page); return getRoomList(areaId, 0, parentAreaId, "online", page);
} }
//直播 -> 全部直播(直播页面的最下面的一个按钮) /**
* 直播 -> 全部直播(直播页面的最下面的一个按钮)
*
* @param areaId 分区 ID
* @param page 页码
* @param sort 分类
*/
@GET("mobile/rooms") @GET("mobile/rooms")
Call<RoomsEntity> getRooms(@Query("area_id") int areaId, @Query("page") int page, @Query("sort") String sort); Call<RoomsEntity> getRooms(@Query("area_id") int areaId, @Query("page") int page, @Query("sort") String sort);
//推荐直播 /**
* 推荐直播
*
* @param page 页码
*/
default Call<RoomsEntity> getSuggestionRooms(int page) { default Call<RoomsEntity> getSuggestionRooms(int page) {
return getRooms(0, page, "suggestion"); return getRooms(0, page, "suggestion");
} }
//最热直播 /**
* 最热直播
*
* @param page 页码
*/
default Call<RoomsEntity> getHottestRooms(int page) { default Call<RoomsEntity> getHottestRooms(int page) {
return getRooms(0, page, "hottest"); return getRooms(0, page, "hottest");
} }
//最新直播 /**
* 最新直播
*
* @param page 页码
*/
default Call<RoomsEntity> getLatestRooms(int page) { default Call<RoomsEntity> getLatestRooms(int page) {
return getRooms(0, page, "latest"); return getRooms(0, page, "latest");
} }
//视频轮播 /**
* 视频轮播
*
* @param page 页码
*/
default Call<RoomsEntity> getRoundRooms(int page) { default Call<RoomsEntity> getRoundRooms(int page) {
return getRooms(0, page, "roundroom"); return getRooms(0, page, "roundroom");
} }
//live 站的搜索("直播" 页面) /**
//type room 时只返回 房间 的搜索结果 * live 站的搜索("直播" 页面)
//type user 时只返回 用户 的搜索结果 *
//type all 房间 用户 的搜索结果都有 * @param keyword 关键字
* @param page 页码
* @param pageSize 页容量
* @param type room 时只返回 房间 的搜索结果, user 时只返回 用户 的搜索结果, all 房间 用户 的搜索结果都有
*/
@GET("AppSearch/index") @GET("AppSearch/index")
Call<SearchResponseEntity> search(@Query("keyword") String keyword, @Query("page") long page, @Query("pagesize") long pageSize, @Query("type") String type); Call<SearchResponseEntity> search(@Query("keyword") String keyword, @Query("page") long page, @Query("pagesize") long pageSize, @Query("type") String type);
/**
* 搜索的快捷调用
*
* @param keyword 关键字
* @param page 页码
* @param pageSize 页容量
*/
default Call<SearchResponseEntity> search(String keyword, long page, long pageSize) { default Call<SearchResponseEntity> search(String keyword, long page, long pageSize) {
return search(keyword, page, pageSize, "all"); return search(keyword, page, pageSize, "all");
} }
//侧拉抽屉 -> 直播中心 -> 右上角日历图标 /**
//签到(live 站签到, 非总站(虽然我也不知道总站有没有签到功能)) * 侧拉抽屉 -> 直播中心 -> 右上角日历图标
//无论是否已经签到, 返回的 code 都是 0. 除了字符串比对, 要想知道是否已经签到要通过 getUserInfo().getIsSign() * 签到(live 站签到, 非总站(虽然我也不知道总站有没有签到功能))
* 无论是否已经签到, 返回的 code 都是 0. 除了字符串比对, 要想知道是否已经签到要通过 getUserInfo().getIsSign()
*/
@GET("AppUser/getSignInfo") @GET("AppUser/getSignInfo")
Call<SignInfoEntity> getSignInfo(); Call<SignInfoEntity> getSignInfo();
//侧拉抽屉 -> 直播中心 -> 我的关注 /**
//获得关注列表 * 侧拉抽屉 -> 直播中心 -> 我的关注
//未登录时返回 32205 * 获得关注列表
* 未登录时返回 32205
*
* @param page 页码
* @param pageSize 页容量
*/
@GET("AppFeed/index") @GET("AppFeed/index")
Call<FollowedHostsEntity> getFollowedHosts(@Query("page") long page, @Query("pagesize") long pageSize); Call<FollowedHostsEntity> getFollowedHosts(@Query("page") long page, @Query("pagesize") long pageSize);
//侧拉抽屉 -> 直播中心 -> 观看历史 /**
* 侧拉抽屉 -> 直播中心 -> 观看历史
*
* @param page 页码
* @param pageSize 页容量
*/
@GET("AppUser/history") @GET("AppUser/history")
Call<HistoryEntity> getHistory(@Query("page") long page, @Query("pagesize") long pageSize); Call<HistoryEntity> getHistory(@Query("page") long page, @Query("pagesize") long pageSize);
//佩戴中心 /**
//侧拉抽屉 -> 直播中心 -> 佩戴中心 -> 粉丝勋章 * 佩戴中心
//获得用户拥有的粉丝勋章 * 侧拉抽屉 -> 直播中心 -> 佩戴中心 -> 粉丝勋章
* 获得用户拥有的粉丝勋章
*/
@GET("AppUser/medal") @GET("AppUser/medal")
Call<MyMedalListEntity> getMyMedalList(); Call<MyMedalListEntity> getMyMedalList();
//佩戴粉丝勋章 /**
* 佩戴粉丝勋章
*
* @param medalId 勋章 ID
*/
@POST("AppUser/wearMedal") @POST("AppUser/wearMedal")
Call<WearMedalResponseEntity> wearMedal(@Query("medal_id") int medalId); Call<WearMedalResponseEntity> wearMedal(@Query("medal_id") int medalId);
//取消佩戴粉丝勋章(取消佩戴当前佩戴着的粉丝勋章) /**
//URL 上的 canel 不是拼写错误, 它原本就是这样的 * 取消佩戴粉丝勋章(取消佩戴当前佩戴着的粉丝勋章)
* URL 上的 canel 不是拼写错误, 它原本就是这样的
*/
@GET("AppUser/canelMedal") @GET("AppUser/canelMedal")
Call<CancelMedalResponseEntity> cancelMedal(); Call<CancelMedalResponseEntity> cancelMedal();
//侧拉抽屉 -> 直播中心 -> 佩戴中心 -> 我的头衔 /**
//获得用户拥有的头衔 * 侧拉抽屉 -> 直播中心 -> 佩戴中心 -> 我的头衔
* 获得用户拥有的头衔
*/
@GET("appUser/myTitleList") @GET("appUser/myTitleList")
Call<MyTitleListEntity> getMyTitleList(); Call<MyTitleListEntity> getMyTitleList();
//获得当前佩戴着的头衔的详情 /**
//当前未佩戴任何东西时, 返回的 code -1, message "nodata" * 获得当前佩戴着的头衔的详情
* 当前未佩戴任何东西时, 返回的 code -1, message "nodata"
*/
@GET("appUser/getWearTitle") @GET("appUser/getWearTitle")
Call<WearTitleEntity> getWearTitle(); Call<WearTitleEntity> getWearTitle();
//佩戴头衔 /**
* 佩戴头衔
*
* @param title 头衔名
*/
@POST("AppUser/wearTitle") @POST("AppUser/wearTitle")
Call<WearTitleResponseEntity> wearTitle(@Query("title") String title); Call<WearTitleResponseEntity> wearTitle(@Query("title") String title);
//取消佩戴头衔(取消佩戴当前佩戴着的头衔) /**
* 取消佩戴头衔(取消佩戴当前佩戴着的头衔)
*/
@GET("appUser/cancelTitle") @GET("appUser/cancelTitle")
Call<CancelTitleResponseEntity> cancelTitle(); Call<CancelTitleResponseEntity> cancelTitle();
@ -308,46 +515,70 @@ public interface LiveService {
@GET("AppUser/awards") @GET("AppUser/awards")
Call<AwardsEntity> getAwards(); Call<AwardsEntity> getAwards();
//瓜子商店 /**
//侧拉抽屉 -> 直播中心 -> 瓜子商店 -> 银瓜子兑换 -> 硬币银瓜子互换 -> 兑换硬币 * 瓜子商店
// 700 银瓜子兑换为 1 硬币, 每个用户每天只能换一次 * 侧拉抽屉 -> 直播中心 -> 瓜子商店 -> 银瓜子兑换 -> 硬币银瓜子互换 -> 兑换硬币
//已经兑换过时返回 403 * 700 银瓜子兑换为 1 硬币, 每个用户每天只能换一次
* 已经兑换过时返回 403
*/
@POST("AppExchange/silver2coin") @POST("AppExchange/silver2coin")
Call<Silver2CoinResponseEntity> silver2Coin(); Call<Silver2CoinResponseEntity> silver2Coin();
//扭蛋机 /**
//侧拉抽屉 -> 直播中心 -> 扭蛋机 -> 普通扭蛋 * 扭蛋机
//获得 扭蛋机(普通扭蛋) 这个页面对应的后台数据 * 侧拉抽屉 -> 直播中心 -> 扭蛋机 -> 普通扭蛋
* 获得 扭蛋机(普通扭蛋) 这个页面对应的后台数据
*/
@GET("AppUser/capsuleInfo") @GET("AppUser/capsuleInfo")
Call<CapsuleInfoEntity> getCapsuleInfo(); Call<CapsuleInfoEntity> getCapsuleInfo();
//抽扭蛋 /**
//count 只能为 1, 10, 100 * 抽扭蛋
*
* @param count 数量, 只能为 1, 10, 100
* @param type 扭蛋类型, 只能为 "normal" "colorful"
*/
@POST("AppUser/capsuleInfoOpen") @POST("AppUser/capsuleInfoOpen")
@FormUrlEncoded @FormUrlEncoded
Call<OpenCapsuleResponseEntity> openCapsule(@Field("count") int count, @Field("type") String type); Call<OpenCapsuleResponseEntity> openCapsule(@Field("count") int count, @Field("type") String type);
//抽普通扭蛋 /**
//侧拉抽屉 -> 直播中心 -> 扭蛋机 -> 普通扭蛋 -> * 抽普通扭蛋
//普通扭蛋的 type "normal" * 侧拉抽屉 -> 直播中心 -> 扭蛋机 -> 普通扭蛋 ->
* 普通扭蛋的 type "normal"
*
* @param count 数量, 只能为 1, 10, 100
*/
default Call<OpenCapsuleResponseEntity> openNormalCapsule(int count) { default Call<OpenCapsuleResponseEntity> openNormalCapsule(int count) {
return openCapsule(count, "normal"); return openCapsule(count, "normal");
} }
//梦幻扭蛋 /**
* 抽梦幻扭蛋
*
* @param count 数量, 只能为 1, 10, 100
*/
default Call<OpenCapsuleResponseEntity> openColorfulCapsule(int count) { default Call<OpenCapsuleResponseEntity> openColorfulCapsule(int count) {
return openCapsule(count, "colorful"); return openCapsule(count, "colorful");
} }
//房间设置 /**
//侧拉抽屉 -> 直播中心 -> 房间设置 -> (上面的个人信息, 包括 房间号, 粉丝数, UP 经验) * 房间设置
//根据用户 ID 来获取房间信息, 通常用于获取自己的直播间信息(可以用来获取他人的房间信息) * 侧拉抽屉 -> 直播中心 -> 房间设置 -> (上面的个人信息, 包括 房间号, 粉丝数, UP 经验)
// API 不会增加直播间观看历史 * 根据用户 ID 来获取房间信息, 通常用于获取自己的直播间信息(可以用来获取他人的房间信息)
* API 不会增加直播间观看历史
*
* @param userId 用户 ID
*/
@GET("assistant/getRoomInfo") @GET("assistant/getRoomInfo")
Call<AssistantRoomInfoEntity> getAssistantRoomInfo(@Query("uId") long userId); Call<AssistantRoomInfoEntity> getAssistantRoomInfo(@Query("uId") long userId);
//侧拉抽屉 -> 直播中心 -> 房间设置 -> 我的封面 /**
//获取自己的直播间的封面(获取其他人的封面会 -403) * 侧拉抽屉 -> 直播中心 -> 房间设置 -> 我的封面
* 获取自己的直播间的封面(获取其他人的封面会 -403)
*
* @param roomId 房间号
*/
@GET("mhand/assistant/getCover") @GET("mhand/assistant/getCover")
Call<CoverEntity> getCover(@Query("roomId") long roomId); Call<CoverEntity> getCover(@Query("roomId") long roomId);

View File

@ -7,26 +7,35 @@ public class BulletScreenEntity {
private long mid; private long mid;
//弹幕长度限制为 LiveRoomInfoEntity.getData().getMsgLength(), 对于每个用户而言, 每个房间都一样 /**
//通过完成 B站 有关任务, 获得成就, 可以加大这个限制(舰长, 老爷等可以直接加大限制), 最长好像是 40 个字 * 弹幕长度限制为 LiveRoomInfoEntity.getData().getMsgLength(), 对于每个用户而言, 每个房间都一样
* 通过完成 B站 有关任务, 获得成就, 可以加大这个限制(舰长, 老爷等可以直接加大限制), 最长好像是 40 个字
*/
@SerializedName("msg") @SerializedName("msg")
private String message; private String message;
// web 端发送弹幕, 该字段是固定的, 为用户进入直播页面的时间的时间戳. 但是在 Android , 这是一个随机数 /**
//该随机数不包括符号位有 9 * web 端发送弹幕, 该字段是固定的, 为用户进入直播页面的时间的时间戳. 但是在 Android , 这是一个随机数
* 该随机数不包括符号位有 9
*/
@SerializedName("rnd") @SerializedName("rnd")
private long random = (long) (Math.random() * (999999999 - (-999999999)) + (-999999999)); private long random = (long) (Math.random() * (999999999 - (-999999999)) + (-999999999));
//1 普通 /**
//4 底端 * 1 普通
//5 顶端 * 4 底端
//6 逆向 * 5 顶端
//7 特殊 * 6 逆向
//9 高级 * 7 特殊
//一些模式需要 VIP * 9 高级
* 一些模式需要 VIP
*/
private int mode = 1; private int mode = 1;
//尚且只见过为 0 的情况 /**
* 弹幕池
* 尚且只见过为 0 的情况
*/
private int pool = 0; private int pool = 0;
private String type = "json"; private String type = "json";
@ -38,7 +47,9 @@ public class BulletScreenEntity {
private String playTime = "0.0"; private String playTime = "0.0";
//实际上并不需要包含 mid 就可以正常发送弹幕, 但是真实的 Android 客户端确实发送了 mid /**
* 实际上并不需要包含 mid 就可以正常发送弹幕, 但是真实的 Android 客户端确实发送了 mid
*/
public BulletScreenEntity(long cid, long mid, String message) { public BulletScreenEntity(long cid, long mid, String message) {
this.cid = cid; this.cid = cid;
this.mid = mid; this.mid = mid;

View File

@ -41,68 +41,94 @@ public class DanMuMsgEntity implements DataEntity {
this.info = info; this.info = info;
} }
//pool 发布的弹幕池 (0 普通 1 字幕 2 特殊) /**
* 弹幕池 (0 普通 1 字幕 2 特殊)
*/
public int getPool() { public int getPool() {
return info.get(0).getAsJsonArray().get(0).getAsInt(); return info.get(0).getAsJsonArray().get(0).getAsInt();
} }
//mode 弹幕的模式 (1 普通 4 底端 5 顶端 6 逆向 7 特殊 9 高级) /**
* 弹幕的模式 (1 普通 4 底端 5 顶端 6 逆向 7 特殊 9 高级)
*/
public int getMode() { public int getMode() {
return info.get(0).getAsJsonArray().get(1).getAsInt(); return info.get(0).getAsJsonArray().get(1).getAsInt();
} }
//fontSize 字体大小 /**
* 字体大小
*/
public int getFontSize() { public int getFontSize() {
return info.get(0).getAsJsonArray().get(2).getAsInt(); return info.get(0).getAsJsonArray().get(2).getAsInt();
} }
//color 字体颜色 /**
* 字体颜色
*/
public int getColor() { public int getColor() {
return info.get(0).getAsJsonArray().get(3).getAsInt(); return info.get(0).getAsJsonArray().get(3).getAsInt();
} }
//弹幕发送时间(Unix 时间戳)(其实是服务器接收到弹幕的时间) /**
* 弹幕发送时间(Unix 时间戳)(其实是服务器接收到弹幕的时间)
*/
public long getSendTime() { public long getSendTime() {
return info.get(0).getAsJsonArray().get(4).getAsInt(); return info.get(0).getAsJsonArray().get(4).getAsInt();
} }
//用户进入房间的时间(Unix 时间戳)(但是 Android 发送的弹幕, 这个值会是随机数) /**
* 用户进入房间的时间(Unix 时间戳)(但是 Android 发送的弹幕, 这个值会是随机数)
*/
public String getUserEnterTime() { public String getUserEnterTime() {
return info.get(0).getAsJsonArray().get(5).getAsString(); return info.get(0).getAsJsonArray().get(5).getAsString();
} }
//得到弹幕内容 /**
* 弹幕内容
*/
public String getMessage() { public String getMessage() {
return info.get(1).getAsString(); return info.get(1).getAsString();
} }
//得到发送者的用户 ID /**
* 发送者的用户 ID
*/
public long getUserId() { public long getUserId() {
return info.get(2).getAsJsonArray().get(0).getAsLong(); return info.get(2).getAsJsonArray().get(0).getAsLong();
} }
//得到发送者的用户名 /**
* 发送者的用户名
*/
public String getUsername() { public String getUsername() {
return info.get(2).getAsJsonArray().get(1).getAsString(); return info.get(2).getAsJsonArray().get(1).getAsString();
} }
//发送者是否是管理员 /**
* 发送者是否是管理员
*/
public boolean isAdmin() { public boolean isAdmin() {
return info.get(2).getAsJsonArray().get(2).getAsBoolean(); return info.get(2).getAsJsonArray().get(2).getAsBoolean();
} }
//发送者是否是 VIP /**
* 发送者是否是 VIP
*/
public boolean isVip() { public boolean isVip() {
return info.get(2).getAsJsonArray().get(3).getAsBoolean(); return info.get(2).getAsJsonArray().get(3).getAsBoolean();
} }
//发送者是否是 SVip /**
* 发送者是否是 SVip
*/
public boolean isSVip() { public boolean isSVip() {
return info.get(2).getAsJsonArray().get(4).getAsBoolean(); return info.get(2).getAsJsonArray().get(4).getAsBoolean();
} }
//表示粉丝勋章有关信息的 JsonArray 可能是空的 /**
//获取粉丝勋章等级 * 表示粉丝勋章有关信息的 JsonArray 可能是空的
* 获取粉丝勋章等级
*/
public Optional<Integer> getFansMedalLevel() { public Optional<Integer> getFansMedalLevel() {
if (info.get(3).getAsJsonArray().size() > 0) { if (info.get(3).getAsJsonArray().size() > 0) {
return Optional.of(info.get(3).getAsJsonArray().get(0).getAsInt()); return Optional.of(info.get(3).getAsJsonArray().get(0).getAsInt());
@ -111,7 +137,9 @@ public class DanMuMsgEntity implements DataEntity {
} }
} }
//获取粉丝勋章名称 /**
* 获取粉丝勋章名称
*/
public Optional<String> getFansMedalName() { public Optional<String> getFansMedalName() {
if (info.get(3).getAsJsonArray().size() > 0) { if (info.get(3).getAsJsonArray().size() > 0) {
return Optional.of(info.get(3).getAsJsonArray().get(1).getAsString()); return Optional.of(info.get(3).getAsJsonArray().get(1).getAsString());
@ -120,7 +148,9 @@ public class DanMuMsgEntity implements DataEntity {
} }
} }
//获取粉丝勋章对应的主播的名字 /**
* 粉丝勋章对应的主播的名字
*/
public Optional<String> getFansMedalOwnerName() { public Optional<String> getFansMedalOwnerName() {
if (info.get(3).getAsJsonArray().size() > 0) { if (info.get(3).getAsJsonArray().size() > 0) {
return Optional.of(info.get(3).getAsJsonArray().get(2).getAsString()); return Optional.of(info.get(3).getAsJsonArray().get(2).getAsString());
@ -129,7 +159,9 @@ public class DanMuMsgEntity implements DataEntity {
} }
} }
//获取粉丝勋章对应的主播的直播间 ID /**
* 粉丝勋章对应的主播的直播间 ID
*/
public Optional<String> getFansMedalOwnerRoomId() { public Optional<String> getFansMedalOwnerRoomId() {
if (info.get(3).getAsJsonArray().size() > 0) { if (info.get(3).getAsJsonArray().size() > 0) {
return Optional.of(info.get(3).getAsJsonArray().get(3).getAsString()); return Optional.of(info.get(3).getAsJsonArray().get(3).getAsString());
@ -138,22 +170,30 @@ public class DanMuMsgEntity implements DataEntity {
} }
} }
//获得用户的观众等级 /**
* 用户的观众等级
*/
public int getUserLevel() { public int getUserLevel() {
return info.get(4).getAsJsonArray().get(0).getAsInt(); return info.get(4).getAsJsonArray().get(0).getAsInt();
} }
//获得用户的观众等级排名 /**
* 用户的观众等级排名
*/
public String getUserRank() { public String getUserRank() {
return info.get(4).getAsJsonArray().get(3).getAsString(); return info.get(4).getAsJsonArray().get(3).getAsString();
} }
//获得用户头衔 /**
* 用户头衔
*/
public List<String> getUserTitles() { public List<String> getUserTitles() {
return GSON.fromJson(info.get(5), STRING_LIST_TYPE); return GSON.fromJson(info.get(5), STRING_LIST_TYPE);
} }
//获得用户名颜色 /**
* 用户名颜色
*/
public String getUsernameColor() { public String getUsernameColor() {
return info.get(8).getAsJsonObject().get("uname_color").getAsString(); return info.get(8).getAsJsonObject().get("uname_color").getAsString();
} }

View File

@ -1,7 +1,6 @@
package com.hiczp.bilibili.api.live.socket.entity; package com.hiczp.bilibili.api.live.socket.entity;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import java.util.List; import java.util.List;
@ -9,7 +8,7 @@ import java.util.List;
public class SendGiftEntity implements DataEntity { public class SendGiftEntity implements DataEntity {
/** /**
* cmd : SEND_GIFT * cmd : SEND_GIFT
* data : {"giftName":"辣条","num":64,"uname":"明暗纠结星","rcost":66347035,"uid":12768615,"top_list":[{"uid":9256,"userName":"SSR","coin":2905900,"face":"http://i0.hdslb.com/bfs/face/eba52abb1daaf3aecd7b986b9731451872d66613.jpg","guard_level":"3","rank":1,"score":2905900},{"uid":4986301,"userName":"乄夏沫丶","coin":1386000,"face":"http://i2.hdslb.com/bfs/face/b3969027a263d2610711317addf437fe59a9b97e.jpg","guard_level":0,"rank":2,"score":1386000},{"uid":5211302,"userName":"朝雾怜","coin":805700,"face":"http://i1.hdslb.com/bfs/face/d366be69d716469514d355642aa324ceba3fa122.jpg","guard_level":0,"rank":3,"score":805700}],"timestamp":1510498496,"giftId":1,"giftType":0,"action":"喂食","super":0,"price":100,"rnd":"1510498460","newMedal":0,"newTitle":0,"medal":[],"title":"","beatId":"0","biz_source":"live","metadata":"","remain":0,"gold":0,"silver":0,"eventScore":0,"eventNum":0,"smalltv_msg":[],"notice_msg":[],"capsule":{"normal":{"coin":13,"change":1,"progress":{"now":4000,"max":10000}},"colorful":{"coin":0,"change":0,"progress":{"now":0,"max":5000}}},"addFollow":0} * data : {"giftName":"节奏风暴","num":1,"uname":"爱上熹","rcost":569788,"uid":230845505,"top_list":[{"uid":288348879,"uname":"我爱我家一生","face":"http://i1.hdslb.com/bfs/face/dd52e4f2dfe881751816e45522f504f10458b514.jpg","rank":1,"score":1852300,"guard_level":0,"isSelf":0},{"uid":287551243,"uname":"熹上城的专属天使菲","face":"http://i1.hdslb.com/bfs/face/c3ef04ba6c267c41067cd7708b7abd60c0c5c49f.jpg","rank":2,"score":1245200,"guard_level":3,"isSelf":0},{"uid":32416351,"uname":"镜子。。","face":"http://i1.hdslb.com/bfs/face/08c54c2c97434811a99e9d070d621ccbb5d3f2c4.jpg","rank":3,"score":332862,"guard_level":3,"isSelf":0}],"timestamp":1520992553,"giftId":39,"giftType":0,"action":"赠送","super":1,"price":100000,"rnd":"1980508331","newMedal":0,"newTitle":0,"medal":{"medalId":"95723","medalName":"布丁诶","level":1},"title":"","beatId":"4","biz_source":"live","metadata":"","remain":0,"gold":88570,"silver":127492,"eventScore":0,"eventNum":0,"smalltv_msg":[],"specialGift":{"id":207945,"time":90,"hadJoin":0,"num":1,"content":"你们城里人真会玩","action":"start","storm_gif":"http://static.hdslb.com/live-static/live-room/images/gift-section/mobilegift/2/jiezou.gif?2017011901"},"notice_msg":[],"capsule":{"normal":{"coin":166,"change":10,"progress":{"now":3630,"max":10000}},"colorful":{"coin":2,"change":0,"progress":{"now":0,"max":5000}}},"addFollow":0,"effect_block":0,"coin_type":"gold","total_coin":100000}
*/ */
@SerializedName("cmd") @SerializedName("cmd")
@ -17,7 +16,6 @@ public class SendGiftEntity implements DataEntity {
@SerializedName("data") @SerializedName("data")
private DataEntity data; private DataEntity data;
@Override
public String getCmd() { public String getCmd() {
return cmd; return cmd;
} }
@ -36,35 +34,39 @@ public class SendGiftEntity implements DataEntity {
public static class DataEntity { public static class DataEntity {
/** /**
* giftName : 辣条 * giftName : 节奏风暴
* num : 64 * num : 1
* uname : 明暗纠结星 * uname : 爱上熹
* rcost : 66347035 * rcost : 569788
* uid : 12768615 * uid : 230845505
* top_list : [{"uid":9256,"uname":"SSR","coin":2905900,"face":"http://i0.hdslb.com/bfs/face/eba52abb1daaf3aecd7b986b9731451872d66613.jpg","guard_level":"3","rank":1,"score":2905900},{"uid":4986301,"userName":"乄夏沫丶","coin":1386000,"face":"http://i2.hdslb.com/bfs/face/b3969027a263d2610711317addf437fe59a9b97e.jpg","guard_level":0,"rank":2,"score":1386000},{"uid":5211302,"userName":"朝雾怜","coin":805700,"face":"http://i1.hdslb.com/bfs/face/d366be69d716469514d355642aa324ceba3fa122.jpg","guard_level":0,"rank":3,"score":805700}] * top_list : [{"uid":288348879,"uname":"我爱我家一生","face":"http://i1.hdslb.com/bfs/face/dd52e4f2dfe881751816e45522f504f10458b514.jpg","rank":1,"score":1852300,"guard_level":0,"isSelf":0},{"uid":287551243,"uname":"熹上城的专属天使菲","face":"http://i1.hdslb.com/bfs/face/c3ef04ba6c267c41067cd7708b7abd60c0c5c49f.jpg","rank":2,"score":1245200,"guard_level":3,"isSelf":0},{"uid":32416351,"uname":"镜子。。","face":"http://i1.hdslb.com/bfs/face/08c54c2c97434811a99e9d070d621ccbb5d3f2c4.jpg","rank":3,"score":332862,"guard_level":3,"isSelf":0}]
* timestamp : 1510498496 * timestamp : 1520992553
* giftId : 1 * giftId : 39
* giftType : 0 * giftType : 0
* action : 喂食 * action : 赠送
* super : 0 * super : 1
* price : 100 * price : 100000
* rnd : 1510498460 * rnd : 1980508331
* newMedal : 0 * newMedal : 0
* newTitle : 0 * newTitle : 0
* medal : [] * medal : {"medalId":"95723","medalName":"布丁诶","level":1}
* title : * title :
* beatId : 0 * beatId : 4
* biz_source : live * biz_source : live
* metadata : * metadata :
* remain : 0 * remain : 0
* gold : 0 * gold : 88570
* silver : 0 * silver : 127492
* eventScore : 0 * eventScore : 0
* eventNum : 0 * eventNum : 0
* smalltv_msg : [] * smalltv_msg : []
* specialGift : {"id":207945,"time":90,"hadJoin":0,"num":1,"content":"你们城里人真会玩","action":"start","storm_gif":"http://static.hdslb.com/live-static/live-room/images/gift-section/mobilegift/2/jiezou.gif?2017011901"}
* notice_msg : [] * notice_msg : []
* capsule : {"normal":{"coin":13,"change":1,"progress":{"now":4000,"max":10000}},"colorful":{"coin":0,"change":0,"progress":{"now":0,"max":5000}}} * capsule : {"normal":{"coin":166,"change":10,"progress":{"now":3630,"max":10000}},"colorful":{"coin":2,"change":0,"progress":{"now":0,"max":5000}}}
* addFollow : 0 * addFollow : 0
* effect_block : 0
* coin_type : gold
* total_coin : 100000
*/ */
@SerializedName("giftName") @SerializedName("giftName")
@ -72,9 +74,9 @@ public class SendGiftEntity implements DataEntity {
@SerializedName("num") @SerializedName("num")
private int num; private int num;
@SerializedName("uname") @SerializedName("uname")
private String userName; private String username;
@SerializedName("rcost") @SerializedName("rcost")
private int rCost; private int rcost;
@SerializedName("uid") @SerializedName("uid")
private long uid; private long uid;
@SerializedName("timestamp") @SerializedName("timestamp")
@ -95,6 +97,17 @@ public class SendGiftEntity implements DataEntity {
private int newMedal; private int newMedal;
@SerializedName("newTitle") @SerializedName("newTitle")
private int newTitle; private int newTitle;
/**
* medal 字段可能是一个空的 JsonArray, 也可能是 JsonObject
* JsonObject , 内部字段如下
* {
* "medalId": "95723",
* "medalName": "布丁诶",
* "level": 1
* }
*/
@SerializedName("medal")
private JsonElement medal;
@SerializedName("title") @SerializedName("title")
private String title; private String title;
@SerializedName("beatId") @SerializedName("beatId")
@ -113,18 +126,24 @@ public class SendGiftEntity implements DataEntity {
private int eventScore; private int eventScore;
@SerializedName("eventNum") @SerializedName("eventNum")
private int eventNum; private int eventNum;
@SerializedName("specialGift")
private SpecialGift specialGift;
@SerializedName("capsule") @SerializedName("capsule")
private CapsuleEntity capsule; private Capsule capsule;
@SerializedName("addFollow") @SerializedName("addFollow")
private int addFollow; private int addFollow;
@SerializedName("effect_block")
private int effectBlock;
@SerializedName("coin_type")
private String coinType;
@SerializedName("total_coin")
private int totalCoin;
@SerializedName("top_list") @SerializedName("top_list")
private List<TopListEntity> topList; private List<TopList> topList;
@SerializedName("medal")
private JsonElement medal;
@SerializedName("smalltv_msg") @SerializedName("smalltv_msg")
private JsonElement smallTVMsg; private JsonElement smalltvMsg;
@SerializedName("notice_msg") @SerializedName("notice_msg")
private List<?> noticeMsg; private JsonElement noticeMsg;
public String getGiftName() { public String getGiftName() {
return giftName; return giftName;
@ -142,20 +161,20 @@ public class SendGiftEntity implements DataEntity {
this.num = num; this.num = num;
} }
public String getUserName() { public String getUsername() {
return userName; return username;
} }
public void setUserName(String userName) { public void setUsername(String username) {
this.userName = userName; this.username = username;
} }
public int getrCost() { public int getRcost() {
return rCost; return rcost;
} }
public void setrCost(int rCost) { public void setRcost(int rcost) {
this.rCost = rCost; this.rcost = rcost;
} }
public long getUid() { public long getUid() {
@ -238,6 +257,14 @@ public class SendGiftEntity implements DataEntity {
this.newTitle = newTitle; this.newTitle = newTitle;
} }
public JsonElement getMedal() {
return medal;
}
public void setMedal(JsonElement medal) {
this.medal = medal;
}
public String getTitle() { public String getTitle() {
return title; return title;
} }
@ -310,11 +337,19 @@ public class SendGiftEntity implements DataEntity {
this.eventNum = eventNum; this.eventNum = eventNum;
} }
public CapsuleEntity getCapsule() { public SpecialGift getSpecialGift() {
return specialGift;
}
public void setSpecialGift(SpecialGift specialGift) {
this.specialGift = specialGift;
}
public Capsule getCapsule() {
return capsule; return capsule;
} }
public void setCapsule(CapsuleEntity capsule) { public void setCapsule(Capsule capsule) {
this.capsule = capsule; this.capsule = capsule;
} }
@ -326,70 +361,208 @@ public class SendGiftEntity implements DataEntity {
this.addFollow = addFollow; this.addFollow = addFollow;
} }
public List<TopListEntity> getTopList() { public int getEffectBlock() {
return effectBlock;
}
public void setEffectBlock(int effectBlock) {
this.effectBlock = effectBlock;
}
public String getCoinType() {
return coinType;
}
public void setCoinType(String coinType) {
this.coinType = coinType;
}
public int getTotalCoin() {
return totalCoin;
}
public void setTotalCoin(int totalCoin) {
this.totalCoin = totalCoin;
}
public List<TopList> getTopList() {
return topList; return topList;
} }
public void setTopList(List<TopListEntity> topList) { public void setTopList(List<TopList> topList) {
this.topList = topList; this.topList = topList;
} }
public JsonElement getMedal() { public JsonElement getSmalltvMsg() {
return medal; return smalltvMsg;
} }
public void setMedal(JsonElement medal) { public void setSmalltvMsg(JsonElement smalltvMsg) {
this.medal = medal; this.smalltvMsg = smalltvMsg;
} }
public JsonElement getSmallTVMsg() { public JsonElement getNoticeMsg() {
return smallTVMsg;
}
public void setSmallTVMsg(JsonObject smallTVMsg) {
this.smallTVMsg = smallTVMsg;
}
public List<?> getNoticeMsg() {
return noticeMsg; return noticeMsg;
} }
public void setNoticeMsg(List<?> noticeMsg) { public void setNoticeMsg(JsonElement noticeMsg) {
this.noticeMsg = noticeMsg; this.noticeMsg = noticeMsg;
} }
public static class CapsuleEntity { public static class Medal {
/** /**
* normal : {"coin":13,"change":1,"progress":{"now":4000,"max":10000}} * medalId : 95723
* colorful : {"coin":0,"change":0,"progress":{"now":0,"max":5000}} * medalName : 布丁诶
* level : 1
*/
@SerializedName("medalId")
private String medalId;
@SerializedName("medalName")
private String medalName;
@SerializedName("level")
private int level;
public String getMedalId() {
return medalId;
}
public void setMedalId(String medalId) {
this.medalId = medalId;
}
public String getMedalName() {
return medalName;
}
public void setMedalName(String medalName) {
this.medalName = medalName;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
}
public static class SpecialGift {
/**
* id : 207945
* time : 90
* hadJoin : 0
* num : 1
* content : 你们城里人真会玩
* action : start
* storm_gif : http://static.hdslb.com/live-static/live-room/images/gift-section/mobilegift/2/jiezou.gif?2017011901
*/
@SerializedName("id")
private int id;
@SerializedName("time")
private int time;
@SerializedName("hadJoin")
private int hadJoin;
@SerializedName("num")
private int num;
@SerializedName("content")
private String content;
@SerializedName("action")
private String action;
@SerializedName("storm_gif")
private String stormGif;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public int getHadJoin() {
return hadJoin;
}
public void setHadJoin(int hadJoin) {
this.hadJoin = hadJoin;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getStormGif() {
return stormGif;
}
public void setStormGif(String stormGif) {
this.stormGif = stormGif;
}
}
public static class Capsule {
/**
* normal : {"coin":166,"change":10,"progress":{"now":3630,"max":10000}}
* colorful : {"coin":2,"change":0,"progress":{"now":0,"max":5000}}
*/ */
@SerializedName("normal") @SerializedName("normal")
private NormalEntity normal; private Normal normal;
@SerializedName("colorful") @SerializedName("colorful")
private ColorfulEntity colorful; private Colorful colorful;
public NormalEntity getNormal() { public Normal getNormal() {
return normal; return normal;
} }
public void setNormal(NormalEntity normal) { public void setNormal(Normal normal) {
this.normal = normal; this.normal = normal;
} }
public ColorfulEntity getColorful() { public Colorful getColorful() {
return colorful; return colorful;
} }
public void setColorful(ColorfulEntity colorful) { public void setColorful(Colorful colorful) {
this.colorful = colorful; this.colorful = colorful;
} }
public static class NormalEntity { public static class Normal {
/** /**
* coin : 13 * coin : 166
* change : 1 * change : 10
* progress : {"now":4000,"max":10000} * progress : {"now":3630,"max":10000}
*/ */
@SerializedName("coin") @SerializedName("coin")
@ -397,7 +570,7 @@ public class SendGiftEntity implements DataEntity {
@SerializedName("change") @SerializedName("change")
private int change; private int change;
@SerializedName("progress") @SerializedName("progress")
private ProgressEntity progress; private Progress progress;
public int getCoin() { public int getCoin() {
return coin; return coin;
@ -415,17 +588,17 @@ public class SendGiftEntity implements DataEntity {
this.change = change; this.change = change;
} }
public ProgressEntity getProgress() { public Progress getProgress() {
return progress; return progress;
} }
public void setProgress(ProgressEntity progress) { public void setProgress(Progress progress) {
this.progress = progress; this.progress = progress;
} }
public static class ProgressEntity { public static class Progress {
/** /**
* now : 4000 * now : 3630
* max : 10000 * max : 10000
*/ */
@ -452,9 +625,9 @@ public class SendGiftEntity implements DataEntity {
} }
} }
public static class ColorfulEntity { public static class Colorful {
/** /**
* coin : 0 * coin : 2
* change : 0 * change : 0
* progress : {"now":0,"max":5000} * progress : {"now":0,"max":5000}
*/ */
@ -464,7 +637,7 @@ public class SendGiftEntity implements DataEntity {
@SerializedName("change") @SerializedName("change")
private int change; private int change;
@SerializedName("progress") @SerializedName("progress")
private ProgressEntityX progress; private ProgressX progress;
public int getCoin() { public int getCoin() {
return coin; return coin;
@ -482,15 +655,15 @@ public class SendGiftEntity implements DataEntity {
this.change = change; this.change = change;
} }
public ProgressEntityX getProgress() { public ProgressX getProgress() {
return progress; return progress;
} }
public void setProgress(ProgressEntityX progress) { public void setProgress(ProgressX progress) {
this.progress = progress; this.progress = progress;
} }
public static class ProgressEntityX { public static class ProgressX {
/** /**
* now : 0 * now : 0
* max : 5000 * max : 5000
@ -520,31 +693,31 @@ public class SendGiftEntity implements DataEntity {
} }
} }
public static class TopListEntity { public static class TopList {
/** /**
* uid : 9256 * uid : 288348879
* uname : SSR * uname : 我爱我家一生
* coin : 2905900 * face : http://i1.hdslb.com/bfs/face/dd52e4f2dfe881751816e45522f504f10458b514.jpg
* face : http://i0.hdslb.com/bfs/face/eba52abb1daaf3aecd7b986b9731451872d66613.jpg
* guard_level : 3
* rank : 1 * rank : 1
* score : 2905900 * score : 1852300
* guard_level : 0
* isSelf : 0
*/ */
@SerializedName("uid") @SerializedName("uid")
private int uid; private int uid;
@SerializedName("uname") @SerializedName("uname")
private String userName; private String uname;
@SerializedName("coin")
private int coin;
@SerializedName("face") @SerializedName("face")
private String face; private String face;
@SerializedName("guard_level")
private String guardLevel;
@SerializedName("rank") @SerializedName("rank")
private int rank; private int rank;
@SerializedName("score") @SerializedName("score")
private int score; private int score;
@SerializedName("guard_level")
private int guardLevel;
@SerializedName("isSelf")
private int isSelf;
public int getUid() { public int getUid() {
return uid; return uid;
@ -554,20 +727,12 @@ public class SendGiftEntity implements DataEntity {
this.uid = uid; this.uid = uid;
} }
public String getUserName() { public String getUname() {
return userName; return uname;
} }
public void setUserName(String userName) { public void setUname(String uname) {
this.userName = userName; this.uname = uname;
}
public int getCoin() {
return coin;
}
public void setCoin(int coin) {
this.coin = coin;
} }
public String getFace() { public String getFace() {
@ -578,14 +743,6 @@ public class SendGiftEntity implements DataEntity {
this.face = face; this.face = face;
} }
public String getGuardLevel() {
return guardLevel;
}
public void setGuardLevel(String guardLevel) {
this.guardLevel = guardLevel;
}
public int getRank() { public int getRank() {
return rank; return rank;
} }
@ -601,6 +758,22 @@ public class SendGiftEntity implements DataEntity {
public void setScore(int score) { public void setScore(int score) {
this.score = score; this.score = score;
} }
public int getGuardLevel() {
return guardLevel;
}
public void setGuardLevel(int guardLevel) {
this.guardLevel = guardLevel;
}
public int getIsSelf() {
return isSelf;
}
public void setIsSelf(int isSelf) {
this.isSelf = isSelf;
}
} }
} }
} }

View File

@ -8,22 +8,51 @@ import retrofit2.http.POST;
import retrofit2.http.Query; import retrofit2.http.Query;
public interface PassportService { public interface PassportService {
/**
* 获得公钥
*/
@POST("api/oauth2/getKey") @POST("api/oauth2/getKey")
Call<KeyEntity> getKey(); Call<KeyEntity> getKey();
/**
* 登录
*
* @param username 用户名
* @param password 密码
*/
@POST("api/oauth2/login") @POST("api/oauth2/login")
Call<LoginResponseEntity> login(@Query("username") String username, @Query("password") String password); Call<LoginResponseEntity> login(@Query("username") String username, @Query("password") String password);
//在一段时间内进行多次错误的登录, 将被要求输入验证码 /**
* 带验证码的登录
* 在一段时间内进行多次错误的登录, 将被要求输入验证码
* @param username 用户名
* @param password 密码
* @param captcha 验证码
* @param cookies cookies
*/
@POST("api/oauth2/login") @POST("api/oauth2/login")
Call<LoginResponseEntity> login(@Query("username") String username, @Query("password") String password, @Query("captcha") String captcha, @Header("Cookie") String cookies); Call<LoginResponseEntity> login(@Query("username") String username, @Query("password") String password, @Query("captcha") String captcha, @Header("Cookie") String cookies);
/**
* 获得账户信息
* @param accessToken token
*/
@GET("api/oauth2/info") @GET("api/oauth2/info")
Call<InfoEntity> getInfo(@Query("access_token") String accessToken); Call<InfoEntity> getInfo(@Query("access_token") String accessToken);
/**
* 刷新 token
* @param accessToken token
* @param refreshToken refreshToken
*/
@POST("api/oauth2/refreshToken") @POST("api/oauth2/refreshToken")
Call<RefreshTokenResponseEntity> refreshToken(@Query("access_token") String accessToken, @Query("refresh_token") String refreshToken); Call<RefreshTokenResponseEntity> refreshToken(@Query("access_token") String accessToken, @Query("refresh_token") String refreshToken);
/**
* 注销
* @param accessToken token
*/
@POST("api/oauth2/revoke") @POST("api/oauth2/revoke")
Call<LogoutResponseEntity> logout(@Query("access_token") String accessToken); Call<LogoutResponseEntity> logout(@Query("access_token") String accessToken);
} }

View File

@ -7,9 +7,11 @@ import retrofit2.http.Query;
import javax.annotation.Nullable; import javax.annotation.Nullable;
//sso 很特别, 它可能返回的是一个 HTML 页面, 所以单独分出来 /**
//sso 会经过两次 302 跳转, 需要保存其中的 cookie, 然后才能抵达最终页面并且进入 cookie 登录状态 * sso 很特别, 它可能返回的是一个 HTML 页面, 所以单独分出来
//如果 gourl null, 则会跳转到 B站 首页 * sso 会经过两次 302 跳转, 需要保存其中的 cookie, 然后才能抵达最终页面并且进入 cookie 登录状态
* 如果 gourl null, 则会跳转到 B站 首页
*/
public interface SsoService { public interface SsoService {
@GET("api/login/sso") @GET("api/login/sso")
Call<ResponseBody> sso(@Nullable @Query("gourl") String goUrl); Call<ResponseBody> sso(@Nullable @Query("gourl") String goUrl);

View File

@ -128,7 +128,7 @@ public class LiveClientTest {
public void sendGift(SendGiftPackageEvent sendGiftPackageEvent) { public void sendGift(SendGiftPackageEvent sendGiftPackageEvent) {
SendGiftEntity.DataEntity dataEntity = sendGiftPackageEvent.getEntity().getData(); SendGiftEntity.DataEntity dataEntity = sendGiftPackageEvent.getEntity().getData();
LOGGER.info("[SendGift] {} give {}*{}", LOGGER.info("[SendGift] {} give {}*{}",
dataEntity.getUserName(), dataEntity.getUsername(),
dataEntity.getGiftName(), dataEntity.getGiftName(),
dataEntity.getNum() dataEntity.getNum()
); );