From c62fa9b8707b5fd4d7f9c1480196babfd9f95b42 Mon Sep 17 00:00:00 2001 From: czp3009 Date: Wed, 26 Jun 2019 15:54:29 +0800 Subject: [PATCH] refactor --- .gitignore | 1 - README.md | 510 +------ build.gradle | 230 ++- gradle/wrapper/gradle-wrapper.properties | 2 +- .../ROOM_REAL_TIME_MESSAGE_UPDATE.json | 5 +- rest/.gitignore | 1 + rest/build.gradle | 19 + .../kotlin/com/hiczp/bilibili/rest/Empty.kt | 2 + {src => rest/src}/test/resources/_config.json | 0 settings.gradle | 5 +- .../kotlin/com/hiczp/bilibili/api/BaseUrl.kt | 41 - .../com/hiczp/bilibili/api/BilibiliClient.kt | 325 ----- .../bilibili/api/BilibiliClientProperties.kt | 74 - .../com/hiczp/bilibili/api/CipherExtension.kt | 23 - .../hiczp/bilibili/api/CollectionExtension.kt | 10 - .../com/hiczp/bilibili/api/GlobalConstant.kt | 8 - .../com/hiczp/bilibili/api/GsonExtension.kt | 9 - .../com/hiczp/bilibili/api/IOExtension.kt | 56 - .../com/hiczp/bilibili/api/app/AppAPI.kt | 383 ----- .../bilibili/api/app/model/AddCoinResponse.kt | 21 - .../bilibili/api/app/model/FavoriteArticle.kt | 46 - .../bilibili/api/app/model/FavoritePage.kt | 84 -- .../bilibili/api/app/model/FavoriteVideo.kt | 44 - .../hiczp/bilibili/api/app/model/HomePage.kt | 375 ----- .../bilibili/api/app/model/LikeResponse.kt | 22 - .../com/hiczp/bilibili/api/app/model/Mine.kt | 60 - .../hiczp/bilibili/api/app/model/MyInfo.kt | 67 - .../bilibili/api/app/model/PopularPage.kt | 88 -- .../api/app/model/SearchArticleResult.kt | 58 - .../api/app/model/SearchBangumiResult.kt | 100 -- .../api/app/model/SearchDefaultWords.kt | 25 - .../hiczp/bilibili/api/app/model/SearchHot.kt | 30 - .../api/app/model/SearchLiveResult.kt | 82 -- .../api/app/model/SearchMovieResult.kt | 92 -- .../bilibili/api/app/model/SearchResult.kt | 186 --- .../bilibili/api/app/model/SearchSuggest.kt | 36 - .../api/app/model/SearchUserResult.kt | 86 -- .../hiczp/bilibili/api/app/model/Sidebar.kt | 33 - .../com/hiczp/bilibili/api/app/model/Space.kt | 500 ------- .../com/hiczp/bilibili/api/app/model/Tab.kt | 29 - .../com/hiczp/bilibili/api/app/model/View.kt | 449 ------ .../com/hiczp/bilibili/api/danmaku/Danmaku.kt | 66 - .../hiczp/bilibili/api/danmaku/DanmakuAPI.kt | 26 - .../bilibili/api/danmaku/DanmakuParser.kt | 120 -- .../com/hiczp/bilibili/api/live/LiveAPI.kt | 233 --- .../bilibili/api/live/model/AnchorInRoom.kt | 103 -- .../hiczp/bilibili/api/live/model/AreaList.kt | 39 - .../bilibili/api/live/model/DanmakuConfig.kt | 67 - .../hiczp/bilibili/api/live/model/Follow.kt | 19 - .../bilibili/api/live/model/GiftConfig.kt | 88 -- .../hiczp/bilibili/api/live/model/HomePage.kt | 393 ------ .../bilibili/api/live/model/MobileRoom.kt | 58 - .../api/live/model/MobileRoomBanner.kt | 74 - .../bilibili/api/live/model/MobileTab.kt | 36 - .../hiczp/bilibili/api/live/model/RoomInfo.kt | 105 -- .../hiczp/bilibili/api/live/model/RoomList.kt | 136 -- .../bilibili/api/live/model/RoomMessage.kt | 116 -- .../hiczp/bilibili/api/live/model/RoomRank.kt | 29 - .../hiczp/bilibili/api/live/model/Title.kt | 37 - .../com/hiczp/bilibili/api/live/model/User.kt | 55 - .../bilibili/api/live/model/UserInfoInRoom.kt | 181 --- .../bilibili/api/live/websocket/LiveClient.kt | 219 --- .../bilibili/api/live/websocket/Packet.kt | 66 - .../com/hiczp/bilibili/api/main/MainAPI.kt | 373 ----- .../api/main/model/ArticleCategories.kt | 25 - .../bilibili/api/main/model/BangumiMore.kt | 43 - .../bilibili/api/main/model/BangumiPage.kt | 80 -- .../hiczp/bilibili/api/main/model/ChatList.kt | 227 --- .../bilibili/api/main/model/ChildReply.kt | 403 ------ .../model/CreateFavoriteFolderResponse.kt | 19 - .../main/model/CreateRelationTagResponse.kt | 20 - .../bilibili/api/main/model/DeleteLog.kt | 37 - .../bilibili/api/main/model/FavoriteFolder.kt | 50 - .../bilibili/api/main/model/MyBangumiNews.kt | 74 - .../bilibili/api/main/model/Recommend.kt | 89 -- .../bilibili/api/main/model/RelationTags.kt | 38 - .../hiczp/bilibili/api/main/model/Reply.kt | 1247 ----------------- .../hiczp/bilibili/api/main/model/Season.kt | 283 ---- .../api/main/model/SendDanmakuResponse.kt | 20 - .../api/main/model/SendReplyResponse.kt | 33 - .../hiczp/bilibili/api/member/MemberAPI.kt | 18 - .../hiczp/bilibili/api/member/model/Pre.kt | 78 -- .../hiczp/bilibili/api/message/MessageAPI.kt | 26 - .../bilibili/api/message/model/NotifyCount.kt | 38 - .../bilibili/api/message/model/UplmList.kt | 27 - .../bilibili/api/passport/PassportAPI.kt | 78 -- .../api/passport/model/GetKeyResponse.kt | 21 - .../api/passport/model/LoginResponse.kt | 59 - .../bilibili/api/passport/model/OAuth2Info.kt | 21 - .../hiczp/bilibili/api/player/PlayerAPI.kt | 69 - .../bilibili/api/player/PlayerInterceptor.kt | 84 -- .../api/player/model/BangumiPlayUrl.kt | 89 -- .../bilibili/api/player/model/VideoPlayUrl.kt | 80 -- .../bilibili/api/retrofit/CommonResponse.kt | 36 - .../bilibili/api/retrofit/HttpConstant.kt | 62 - .../api/retrofit/RetrofitExtension.kt | 54 - .../exception/BilibiliApiException.kt | 11 - .../interceptor/CommonHeaderInterceptor.kt | 22 - .../interceptor/CommonParamInterceptor.kt | 76 - .../interceptor/FailureResponseInterceptor.kt | 52 - .../interceptor/SortAndSignInterceptor.kt | 62 - .../thirdpart/commons/BoundedInputStream.java | 253 ---- .../kotlin/com/hiczp/bilibili/api/vc/VcAPI.kt | 30 - .../bilibili/api/vc/model/AttentionList.kt | 19 - .../bilibili/api/vc/model/DynamicNumber.kt | 25 - .../com/hiczp/bilibili/api/test/Config.kt | 29 - .../hiczp/bilibili/api/test/DanmakuTest.kt | 21 - .../hiczp/bilibili/api/test/EnterRoomTest.kt | 32 - .../hiczp/bilibili/api/test/FetchReplyTest.kt | 86 -- .../hiczp/bilibili/api/test/LiveClientTest.kt | 64 - .../com/hiczp/bilibili/api/test/LoginTest.kt | 21 - .../hiczp/bilibili/api/test/PlayUrlTest.kt | 27 - .../com/hiczp/bilibili/api/test/SearchTest.kt | 41 - .../com/hiczp/bilibili/api/test/SeasonTest.kt | 13 - .../bilibili/api/test/SendDanmakuTest.kt | 13 - .../bilibili/api/test/SendLiveMessageTest.kt | 14 - .../hiczp/bilibili/api/test/SendReplyTest.kt | 16 - .../hiczp/bilibili/api/test/TestExtension.kt | 11 - .../hiczp/bilibili/api/test/UserInfoTest.kt | 20 - websocket/build.gradle | 15 + .../hiczp/bilibili/websocket/LiveClient.kt | 99 ++ .../com/hiczp/bilibili/websocket/Packet.kt | 103 ++ .../hiczp/bilibili}/websocket/PacketType.kt | 4 +- .../hiczp/bilibili}/websocket/PresetPacket.kt | 12 +- .../websocket/model/DanmakuMessage.kt | 91 +- .../bilibili/websocket/LiveClientTest.kt | 92 ++ .../test/resources/simplelogger.properties | 1 + 127 files changed, 553 insertions(+), 11206 deletions(-) create mode 100644 rest/.gitignore create mode 100644 rest/build.gradle create mode 100644 rest/src/main/kotlin/com/hiczp/bilibili/rest/Empty.kt rename {src => rest/src}/test/resources/_config.json (100%) delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/BaseUrl.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/BilibiliClient.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/BilibiliClientProperties.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/CipherExtension.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/CollectionExtension.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/GlobalConstant.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/GsonExtension.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/IOExtension.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/AppAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/AddCoinResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoriteArticle.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoritePage.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoriteVideo.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/HomePage.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/LikeResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/Mine.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/MyInfo.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/PopularPage.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchArticleResult.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchBangumiResult.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchDefaultWords.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchHot.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchLiveResult.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchMovieResult.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchResult.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchSuggest.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchUserResult.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/Sidebar.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/Space.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/Tab.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/app/model/View.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/danmaku/Danmaku.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/danmaku/DanmakuAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/danmaku/DanmakuParser.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/LiveAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/AnchorInRoom.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/AreaList.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/DanmakuConfig.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/Follow.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/GiftConfig.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/HomePage.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/MobileRoom.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/MobileRoomBanner.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/MobileTab.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/RoomInfo.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/RoomList.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/RoomMessage.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/RoomRank.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/Title.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/User.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/model/UserInfoInRoom.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/websocket/LiveClient.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/live/websocket/Packet.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/MainAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/ArticleCategories.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/BangumiMore.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/BangumiPage.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/ChatList.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/ChildReply.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/CreateFavoriteFolderResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/CreateRelationTagResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/DeleteLog.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/FavoriteFolder.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/MyBangumiNews.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/Recommend.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/RelationTags.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/Reply.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/Season.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/SendDanmakuResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/main/model/SendReplyResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/member/MemberAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/member/model/Pre.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/message/MessageAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/message/model/NotifyCount.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/message/model/UplmList.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/passport/PassportAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/passport/model/GetKeyResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/passport/model/LoginResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/passport/model/OAuth2Info.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/player/PlayerAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/player/PlayerInterceptor.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/player/model/BangumiPlayUrl.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/player/model/VideoPlayUrl.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/retrofit/CommonResponse.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/retrofit/HttpConstant.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/retrofit/RetrofitExtension.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/retrofit/exception/BilibiliApiException.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/retrofit/interceptor/CommonHeaderInterceptor.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/retrofit/interceptor/CommonParamInterceptor.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/retrofit/interceptor/FailureResponseInterceptor.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/retrofit/interceptor/SortAndSignInterceptor.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/thirdpart/commons/BoundedInputStream.java delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/vc/VcAPI.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/vc/model/AttentionList.kt delete mode 100644 src/main/kotlin/com/hiczp/bilibili/api/vc/model/DynamicNumber.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/Config.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/DanmakuTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/EnterRoomTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/FetchReplyTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/LiveClientTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/LoginTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/PlayUrlTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/SearchTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/SeasonTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/SendDanmakuTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/SendLiveMessageTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/SendReplyTest.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/TestExtension.kt delete mode 100644 src/test/kotlin/com/hiczp/bilibili/api/test/UserInfoTest.kt create mode 100644 websocket/build.gradle create mode 100644 websocket/src/main/kotlin/com/hiczp/bilibili/websocket/LiveClient.kt create mode 100644 websocket/src/main/kotlin/com/hiczp/bilibili/websocket/Packet.kt rename {src/main/kotlin/com/hiczp/bilibili/api/live => websocket/src/main/kotlin/com/hiczp/bilibili}/websocket/PacketType.kt (69%) rename {src/main/kotlin/com/hiczp/bilibili/api/live => websocket/src/main/kotlin/com/hiczp/bilibili}/websocket/PresetPacket.kt (67%) rename src/main/kotlin/com/hiczp/bilibili/api/live/websocket/Parser.kt => websocket/src/main/kotlin/com/hiczp/bilibili/websocket/model/DanmakuMessage.kt (61%) create mode 100644 websocket/src/test/kotlin/com/hiczp/bilibili/websocket/LiveClientTest.kt create mode 100644 websocket/src/test/resources/simplelogger.properties diff --git a/.gitignore b/.gitignore index f89eeb7..136dbb4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,5 @@ target out build -src/test/resources/config.json .gradle gradlew.bat diff --git a/README.md b/README.md index ce3090c..920d546 100644 --- a/README.md +++ b/README.md @@ -1,490 +1,70 @@ -# Bilibili API JVM 调用库 -该项目提供 Bilibili API 的 JVM 调用, 协议来自 Bilibili Android APP 的逆向工程以及截包分析. +# Bilibili API library for Kotlin +本项目封装一些 Bilibili API 以方便在 Kotlin 中使用(也可用于其他 JVM 语言). + +协议来自对 Bilibili Android APP 的逆向工程以及截包分析. -使用一台虚拟的 `Pixel 2` 设备来截取数据包, 一些固定参数可能与真实设备不一致. - -# 使用 +# 引入依赖 +RestFul API ```groovy -compile group: 'com.hiczp', name: 'bilibili-api', version: '0.1.0' +compile group: 'com.hiczp', name: 'bilibili-api-rest', version: '0.2.0' ``` -# 技术说明 -`BilibiliClient` 类表示一个模拟的客户端, 实例化此类即表示打开了 Bilibili APP. +Websocket(用于连接直播间弹幕推送服务器以获取实时弹幕) +```groovy +compile group: 'com.hiczp', name: 'bilibili-api-websocket', version: '0.2.0' +``` -所有调用从这个类开始, 包括登陆以及访问其他各种 API. - -使用协程来实现异步, 由于 [kotlin coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) 为编译器实现, 因此并非所有 JVM 语言都能正确调用 `suspend` 方法. - -本项目尽可能的兼容其他 JVM 语言和 Android, 不要问, 问就没测试过. - -`BilibiliClient` 实例化时会记录一些信息, 例如初始化的事件, 用于更逼真的模拟真实客户端发送的请求. 因此请不要每次都实例化一个新的 `BilibiliClient` 实例, 而应该保存其引用. - -一个客户端下各种不同类型的 API (代理类)都是惰性初始化的, 并且只初始化一次, 因此不需要保存 API 的引用, 例如以下代码是被推荐的: +全部引入 +```groovy +compile group: 'com.hiczp', name: 'bilibili-api', version: '0.2.0' +``` +# 获取直播间实时弹幕 +举个例子 ```kotlin -runBlocking { - val bilibiliClient = BilibiliClient().apply { - login(username, password) - } - val myInfo = bilibiliClient.appAPI.myInfo().await() - val reply = bilibiliClient.mainAPI.reply(oid = 44154463).await() -} -``` - -如果一个请求的返回内容中的 `code`(code 是 BODY 的内容, 并非 HttpStatus) 不为 0, 将抛出异常 `BilibiliApiException`, 通过以下代码来获取服务器原始返回的 `code`: - -```kotlin -val code = bilibiliApiException.commonResponse.code -``` - -一个错误返回的原始 `JSON` 如下所示: - -```json -{ - "code": -629, - "message": "用户名与密码不匹配", - "ts": 1550730464 -} -``` - -每种不同的 API 在错误时返回的 `code` 丰富多彩(确信), 可能是正数也可能是负数, 可能上万也可能是个位数, 不要问, 问就是你菜. - -# 登录和登出 -(Bilibili oauth2 v3) - -登陆和登出均为异步方法, 需要在协程上下文中执行(接下去不会特地强调这一点). - -```kotlin -runBlocking { - BilibiliClient().run { - login(username, password) - logout() - } -} -``` - -`login` 方法返回一个 `LoginResponse` 实例, 下次可以直接赋值到没有登陆的 `BilibiliClient` 实例中来恢复登陆状态. - -```kotlin -BilibiliClient().apply { - this.loginResponse = loginResponse -} -``` - -`LoginResponse` 继承 `Serializable`, 可被序列化(JVM 序列化). - -可能的错误返回有两种: - - -629 用户名与密码不匹配 - -105 验证码错误 - -如果仅使用用户名与密码进行登陆并且得到了 `-105` 的结果, 那么说明需要验证码(通常是由于多次错误的登陆尝试导致的). - -原始返回如下所示 - - {"ts":1550569982,"code":-105,"data":{"url":"https://passport.bilibili.com/register/verification.html?success=1>=b6e5b7fad7ecd37f465838689732e788&challenge=9a67afa4d42ede71a93aeaaa54a4b6fe&ct=1&hash=105af2e7cc6ea829c4a95205f2371dc5"},"message":"验证码错误!"} - -自行访问 `commonResponse.data.obj.url.string` 打开一个极验弹窗, 完成滑动验证码后再次调用登陆接口: - -```kotlin -login(username, password, challenge, secCode, validate) -``` - -`challenge` 为本次极验的唯一标识(在一开始给出的 url 中) - -`validate` 为极验返回值 - -`secCode` 为 `"$validate|jordan"` - -(注意, 极验会根据滑动的轨迹来识别人机, 所以要为最终用户打开一个 WebView 来进行真人操作而不能自动完成. 极验最终返回的是一个 jsonp, 里面包含以上三个参数, 详见极验接入文档). - -注意, `BilibiliClient` 不能严格保证线程安全, 如果在登出的同时进行登录操作可能引发错误(想要这么做的人一定脑子瓦特了). - -登陆后, 可以访问全部 API(注意, 有一些明显不需要登录的 API 也有可能需要登录). - -由于各种需要登陆的 API 在未登录时返回的 `code` 并不统一, 因此没有办法做自动 `token` 刷新, 自己看着办. - -在真实的客户端上, 每次一打开 APP 就会访问[个人信息 API](#获取个人信息)来确定 `token` 是否仍然可用, 这就是 B站 自己的解决方案. - -# 访问 API -不要问文档, 用自动补全(心)来感受. 以下给出几个示例 - -## 获取个人信息 -(首先要登陆) - -```kotlin -val myInfo = bilibiliClient.appAPI.myInfo().await() -``` - -返回用户 ID, vip 信息等. - -## 搜索 -当我们想看某些内容时, 我们会首先使用搜索功能, 例如 - -```kotlin -val searchResult = bilibiliClient.appAPI.search(keyword = "刀剑神域").await() -``` - -实际上这对应客户端上的 搜索 -> 综合. - -如果要搜索番剧则使用 `bilibiliClient.appAPI.searchBangumi`. - -同理, 搜索直播, 用户, 影视, 专栏分别使用 `searchLive`, `searchUser`, `searchMovie`, `searchArticle`. - -所有的搜索都使用 `pageNumber` 参数来控制翻页(从 1 开始). - -## 获取视频播放地址 -获取视频实际播放地址的 API 比较特殊, 被单独分了出来, 示例如下 - -```kotlin -val videoPlayUrl = bilibiliClient.playerAPI.videoPlayUrl(aid = 41517911, cid = 72913641).await() -``` - -`aid` 即 av 号, 只能表示视频播放的那个页面, 如果一个视频有多个 `p`, 那么每个 `p` 都有单独的 `cid`. - -在 Web 端, URL 通常是这样的 - - https://www.bilibili.com/video/av44541340/?p=2 - -实际上就是选择了该 `aid` 下的第二个 `cid`(注意, 参数里使用的 `cid` 不是这个 p 的序号, 它也是一个很长的数字). - -简单的来说, `aid` 和 `cid` 加在一起才能表示一个视频流(为什么 `cid` 不能直接表示一个视频我也不知道). - -因此无论是获取视频播放地址, 还是获取弹幕列表, 都要同时传入 `aid` 与 `cid`. - -而 `cid` 在哪里获得呢, 如下所示 - -```kotlin -val view = bilibiliClient.appAPI.view(aid = 41517911).await() -``` - -该接口返回对一个视频页面的描述信息(甚至包含广告和推荐), 客户端根据这些信息生成视频页面. - -其中 `data.cid` 为默认 `p` 的 `cid`. `data.pages[n].cid` 为每个 `p` 的 `cid`. 如果只有一个 `p` 那么说明视频没有分 `p`. - -请求视频地址将访问如下结构的内容 - -```json -{ - "code": 0, - "data": { - "accept_description": [ - "高清 1080P+", - "高清 1080P", - "高清 720P", - "清晰 480P", - "流畅 360P" - ], - "accept_format": "hdflv2,flv,flv720,flv480,flv360", - "accept_quality": [ - 112, - 80, - 64, - 32, - 16 - ], - "dash": { - "audio": [ - { - "bandwidth": 319173, - "base_url": "http://upos-hz-mirrorks3u.acgvideo.com/upgcxcode/18/58/77995818/77995818-1-30280.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_&deadline=1551113319&gen=playurl&nbs=1&oi=3670888782&os=ks3u&platform=android&trid=925269b941bf4883ac9ec92c6ab5af4e&uipk=5&upsig=33273eaf403739d9f51304509f55589e", - "codecid": 0, - "id": 30280 - }, - { - "bandwidth": 67326, - "base_url": "http://upos-hz-mirrorkodou.acgvideo.com/upgcxcode/18/58/77995818/77995818-1-30216.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_&deadline=1551113319&gen=playurl&nbs=1&oi=3670888782&os=kodou&platform=android&trid=925269b941bf4883ac9ec92c6ab5af4e&uipk=5&upsig=3d1f9b836430bb8033b2f318faf42f9b", - "codecid": 0, - "id": 30216 - } - ], - "video": [ - { - "bandwidth": 376693, - "base_url": "http://upos-hz-mirrorks3u.acgvideo.com/upgcxcode/18/58/77995818/77995818-1-30015.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_&deadline=1551113319&gen=playurl&nbs=1&oi=3670888782&os=ks3u&platform=android&trid=925269b941bf4883ac9ec92c6ab5af4e&uipk=5&upsig=82bc845bce9f22b731b062bf83fa000f", - "codecid": 7, - "id": 16 - }, - ... - { - "bandwidth": 2615324, - "base_url": "http://upos-hz-mirrorcosu.acgvideo.com/upgcxcode/18/58/77995818/77995818-1-30080.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_&deadline=1551113319&dynamic=1&gen=playurl&oi=3670888782&os=cosu&platform=android&rate=0&trid=925269b941bf4883ac9ec92c6ab5af4e&uipk=5&uipv=5&um_deadline=1551113319&um_sign=22fef3c0efa0d23388429f6926fad298&upsig=c4768c036beb667ba4648369770f8de8", - "codecid": 7, - "id": 80 - } - ] - }, - "fnval": 16, - "fnver": 0, - "format": "flv480", - "from": "local", - "quality": 32, - "result": "suee", - "seek_param": "start", - "seek_type": "offset", - "timelength": 175332, - "video_codecid": 7, - "video_project": true - }, - "message": "0", - "ttl": 1 -} -``` - -(由于内容太长, 去除了一部分内容) - -注意, 视频下载地址有好几个(以上返回内容中被折叠成了两个), 但是实际上他们都是一样的内容, 只是清晰度不同. `data.dash.video.id` 实际上代表 `data.accept_quality`. - -视频和音频是分开的, 视频和音频都返回 `m4s` 文件, 将其合并即可得到完整的 `mp4` 文件. - -`data.quality` 指默认选择的清晰度, 通常情况下移动网络会自动选择 `32`, 即 "清晰 480P"(在 `data.accept_description` 中对应). - -对于番剧来说, 也使用 `aid` 与 `cid` 来获得播放地址 - -```kotlin -val bangumiPlayUrl = bilibiliClient.playerAPI.bangumiPlayUrl(aid = 42714241, cid = 74921228).await() -``` - -返回内容差不多是一个原理, 这里就不赘述了. - -如何获得番剧的 `aid` 与 `cid` 呢. 我们都知道, 实际上番剧那个页面的唯一标识是 "季", 同一个番的不同 "季" 其实是不同的东西. - -我们在番剧搜索页面可以得到番剧的 `season`, 这代表了一个番剧的某一季的页面. - -然后我们用 `season` 来打开番剧页面. - -```kotlin -val season = bilibiliClient.mainAPI.season(seasonId = 25617).await() -``` - -返回值中的 `result.seasons[n].season_id` 为该番所有季的 id(包含用来作为查询条件的 `seasonId`). - -该 API 还可以用 `episodeId` 作为查询条件, 即以集为条件打开一个番剧页面(会跳转到对应的季). - -返回值中的 `result.episodes` 包含了当前所选择的季的全部集的 `aid` 与 `cid`. - -## 查看视频下面的评论 -看完了视频当然要看一下傻吊网友都在说些什么. 使用以下 API 获取一个视频的评论. - -```kotlin -val reply = bilibiliClient.mainAPI.reply(oid = 44154463).await() -``` - -这里的 `oid` 指 `aid`(其他一些 API 中 `oid` 也可能指 `cid` 详见方法上面的注释). - -评论是不分 `p` 的, 所有评论都是在一起的. - -可以额外使用一个 `next` 参数来指定返回的起始楼层(即翻页). - -楼层是越翻越小的, 所以 `next` 也要越来越小. - -看到了傻吊网友们的评论是不够的, 我们还想看到杠精与其隔着屏幕对喷的场景, 因此我们要获取评论的子评论, 即评论的评论 - -```kotlin -val childReply = bilibiliClient.mainAPI.childReply(oid = 16622855, root = 1405602348).await() -``` - -其中的 `root` 表示根评论的 id. - -每个评论都有自己的 `replyId`, `parentId` 以及 `rootId`. - -假如一个人在一个评论的子评论里发布了一个评论并且 at 了其他人发的评论, 那么其 `parentId` 是他所 at 的评论, 其 `rootId` 为所在的根评论. - -如果不满足对应的层级逻辑关系(例如本身为根评论), `parentId` 或 `rootId` 可能为 0. - -用额外的 `minId` 参数来指定返回的起始子楼层. - -注意, 子楼层是越翻越大的. - -如果一个根评论下面有很多个喷子在互喷, 会导致看不清, 客户端上有一个按钮 "查看对话" 就是解决这个问题的. - -```kotlin -val chatList = bilibiliClient.mainAPI.chatList(oid = 34175504, root = 1136310360, dialog = 1136351035).await() -``` - -`root` 为根评论 ID, `dialog` 为父评论 ID. - -用 `minFloor` 控制分页, 原理同上. - -番剧下面的评论用一样的方式获取. - -## 获得一个视频的弹幕 -看评论自然不够刺激, 我们想看到弹幕! - -获取弹幕非常简单 - -```kotlin -val danmakuFile = bilibiliClient.danmakuAPI.list(aid = 810872, oid = 1176840).await() -``` - -弹幕是一个文件, 可能非常大, 里面是二进制内容. - -为了解析弹幕, 我们要用到另一个类 - -```kotlin -val (flagMap, danmakuList) = DanmakuParser.parser(danmakuFile.byteStream()) -``` - -`flagMap` 类型为 `Map` 键和值分别表示 弹幕ID 与 弹幕等级. - -弹幕等级在区间 \[1, 10\] 内, 低于客户端设置的 "弹幕云屏蔽等级" 的弹幕将不会显示出来. - -`danmakuList` 类型为 `List`, 内含所有解析得到的弹幕. - -使用以下代码来输出全部弹幕的内容 - -```kotlin -danmakuList.forEach { - println(it.content) -} -``` - -注意, 弹幕的解析是惰性的, `danmakuList` 是一个 `Sequence`. 如果同时持有很多未用完的 `danmakuList` 的引用可能会造成大量内存浪费. - -客户端的弹幕屏蔽设置是对弹幕中的 `user` 属性做的. 而实际上 `danmaku.user` 是一个字符串. - -这个字符串是 用户ID 的 `CRC32` 的校验和. - -众所周知, 一切 hash 算法都有冲突的问题. 这也就意味着, 屏蔽一个用户的同时可能屏蔽掉了多个与该用户 hash 值相同的用户. - -在另一方面, 通过这个 `CRC32` 校验和进行用户 ID 反查, 将查询到多个可能的用户, 因此无法完全确定一条弹幕到底是哪个用户发送的. - -如果想获得发送这条弹幕的所有可能的用户的 ID, 可以通过以下方法: - -```kotlin -val possibleUserIds = danmaku.calculatePossibleUserIds() -``` - -返回一个 `List`, 内容为所有可能的用户 ID(至少有一个). - -注意, 第一次使用 `CRC反查` 功能将花费大约 `300ms` 来生成彩虹表, 如果想手动初始化请使用以下代码 - -```kotlin -Crc32Cracker -``` - -(`Crc32Cracker` 是一个惰性初始化的单例) - -通常情况下, 一次 `CRC反查` 耗时大约 `1ms`. - -由于这是一个比较耗时的操作, 请不要每条弹幕都如此操作(相比较 6000 条弹幕的解析只需要 `150ms`). - -番剧的弹幕同理. - -## 发送视频弹幕 -光看不发憋着慌, 我们来发送一条视频弹幕: - -```kotlin -bilibiliClient.mainAPI.sendDanmaku(aid = 40675923, cid = 71438168, progress = 2297, message = "2333").await() -``` - -其中 `progress` 是播放器时间, 其他观众将看到你的弹幕在视频的此处出现, 单位为毫秒. - -`message` 应该是有长度限制的, 但是没有测过. - -如果不确定视频的长度, 需要从[视频播放地址的 API](#获取视频播放地址) 中的 `data.timelength` 来获得, 单位也是毫秒. - -## 获取直播弹幕 -刚进入直播间时, 立即看到的十条弹幕实际上是最近的历史弹幕, 通过以下方式来获取 - -```kotlin -bilibiliClient.liveAPI.roomMessage(roomId).await() -``` - -接下来的弹幕都是实时弹幕, 直播间实时弹幕通过 `Websocket` 来推送. - -```kotlin -val job = bilibiliClient.liveClient(roomId = 3) { - onConnect = { - println("Connected") - } - - onPopularityPacket = { _, popularity -> - println("Current popularity: $popularity") - } - - onCommandPacket = { _, jsonObject -> - println(jsonObject) - } - - onClose = { _, closeReason -> - println(closeReason) - } -}.launch() -``` - -服务器推送的 `Message` 有两种, 一种是 `人气值` 数据, 另一种是 `Command` 数据. - -`Command` 数据包用于控制客户端渲染何种内容. 弹幕, 送礼, 系统公告等全部都是由 `Command` 数据包控制的, 其本体为一个 `JsonObject`. - -例如一个弹幕数据是这样的(`cmd` 字段的值为 `DANMU_MSG`): - -```json -{"cmd":"DANMU_MSG","info":[[0,1,25,16777215,1553417856,1553414245,0,"9e539d78",0,0,0],"记得存档!",[3432444,"喵的叫一声",0,0,0,10000,1,""],[6,"日常","奶粉の日常",35399,5805790,""],[22,0,5805790,">50000"],["",""],0,0,null,{"ts":1553417856,"ct":"87255D9C"}]} -``` - -`Welcome` 的数据是这样的 -```json -{"cmd":"WELCOME","data":{"uid":110208099,"uname":"霸刀宋壹i","is_admin":false,"svip":1}} -``` - -各种 `Command` 数据包的结构经常改变, 因此不提供实体类. - -由于 `DANMU_MSG` 的数据结构太过意识流, 因此提供了额外的辅助工具来方便地解析它. - -`DanmakuMessage` 是一个 `inline class` 请不要对其进行太过复杂的操作. - -```kotlin -onCommandPacket = { _, jsonObject -> - val cmd by jsonObject.byString - println( - if (cmd == "DANMU_MSG") { - with(DanmakuMessage(jsonObject)) { - "${if (fansMedalInfo.isNotEmpty()) "[$fansMedalName $fansMedalLevel] " else ""}[UL$userLevel] $nickname: $message" +val liveClient = LiveClient(roomId = 23058) { + resolvedPackets.consumeEach { + when (it) { + is CommandPacket -> { + val command = it.content + println("[${command.cmd}] $command") + } + is PopularityPacket -> { + println("Popularity: ${it.content}") } - } else { - jsonObject.toString() } - ) + } +} +runBlocking { + liveClient.connect() } ``` -输出: +`resolvedPackets` 是一个输送解析后的数据包的 `Channel`, 解析后的数据包有 `CommandPacket` 以及 `PopularityPacket` 两种类型. -``` -[甜甜天 7] [UL25] czp3009: 233 -``` +`CommandPacket` 的本体是一段 JSON, 由于其内容经常发生改变, 所以不提供 POJO. -更多 `Command` 数据包的数据结构详见本项目的 [/record/直播弹幕](record/直播弹幕) 文件夹. +`Command.cmd` 是一个快捷方式, 可以快速取得其中的 `cmd` 字段从而判断其类别. -注意, `onPopularityPacket`, `onCommandPacket` 这些回调不能进行耗时操作. +作为样本的 JSON 数据在本项目 `/record` 文件夹下. -关闭连接 +大部分 JSON 都有光怪陆离的数据结构. 其中 `DANMU_MSG` 尤为恶劣, 通篇都是数组. 为了方便对其解析, 故提供内联类 `DanmakuMessage`. + +使用方法如下 ```kotlin -job.cancel() +val command = commandPacket.content +val danmakuMessage = command.asDanmakuMessage() +with(danmakuMessage) { + println("$nickname: $message") +} ``` -## 发送直播弹幕 -在直播间里发送弹幕也非常简单(必须先登陆) +`PopularityPacket` 的本体是一个 `Int` 数字, 表示当前房间的人气值. 该数据包每 30秒 收到一次. -```kotlin -liveClient.sendMessage("我上我也行").await() -``` +如果要为读取操作设定超时, 可以设定为 40秒. -注意, 除了弹幕超长(普通用户为 20 个 Unicode 字符, 老爷, 会员可以额外加长)会导致抛出异常, 其他情况都会正常返回(`code` 为 0). - -完全正常返回时(弹幕正确的被发送了), 返回内容中的 `message` 为一个空字符串. - -如果不为空字符串, 则表示不完全正常 - -例如返回内容的 `message` 为 "msg repeat" 则表示短时间重复发送相同的弹幕而被服务器拒绝, 但是返回的 `code` 确实是 0. - -其他情况诸如包含特殊字符, 包含不文明词语等均会导致不完全正常的返回. - -正常返回时, 就算不完全正常, 客户端也会将这条弹幕显示到屏幕上, 如果不是完全正常的, 那么这条弹幕就只有自己能看见(刷新后也会消失). - -需要额外判断返回的 `message` 是否为空字符串来确认这条弹幕有没有被正确发送. +注意: 如果使用短房间号来连接弹幕推送服务器, 可能会得不到正确的人气值信息(一直为 0 或者一直为 1). 因此在连接弹幕推送服务器前应当首先获取直播间基本信息. 同时, 弹幕服务器不是唯一的, 在构造 `LiveClient` 时可以传入从房间基本信息中获取到的其他服务器地址. # License GPL V3 diff --git a/build.gradle b/build.gradle index ef7fade..d3da033 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,9 @@ buildscript { ext { - kotlin_version = '1.3.21' - kotlin_coroutines_version = '1.1.1' - ktor_version = '1.1.3' + kotlin_version = '1.3.31' + kotlin_coroutines_version = '1.2.1' jvm_target = JavaVersion.VERSION_1_8 + ktor_version = '1.1.4' } repositories { @@ -15,136 +15,132 @@ buildscript { } } -group = 'com.hiczp' -version = '0.1.0' -description = 'Bilibili Android client API library for Kotlin' +allprojects { + group = 'com.hiczp' + version = '0.2.0' + description = 'Bilibili API library for Kotlin' -apply plugin: 'kotlin' -apply plugin: 'maven-publish' -apply plugin: 'signing' + apply plugin: 'kotlin' + apply plugin: 'maven-publish' + apply plugin: 'signing' -repositories { - mavenCentral() - mavenLocal() -} - -//kotlin -dependencies { - // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8 - compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8' - // https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core - compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: kotlin_coroutines_version -} -compileKotlin { - kotlinOptions { - jvmTarget = jvm_target - freeCompilerArgs = ["-Xjvm-default=enable", "-Xuse-experimental=kotlin.Experimental", "-XXLanguage:+InlineClasses"] - } -} -compileTestKotlin { - kotlinOptions.jvmTarget = jvm_target -} - -//logging -dependencies { - // https://mvnrepository.com/artifact/io.github.microutils/kotlin-logging - compile group: 'io.github.microutils', name: 'kotlin-logging', version: '1.6.25' - // https://mvnrepository.com/artifact/org.slf4j/slf4j-simple - testCompile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.26' -} - -//http -dependencies { - // https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit - compile group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.5.0' - // https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson - compile group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.5.0' - // https://mvnrepository.com/artifact/com.github.salomonbrys.kotson/kotson - compile group: 'com.github.salomonbrys.kotson', name: 'kotson', version: '2.5.0' - // https://mvnrepository.com/artifact/com.jakewharton.retrofit/retrofit2-kotlin-coroutines-adapter - compile group: 'com.jakewharton.retrofit', name: 'retrofit2-kotlin-coroutines-adapter', version: '0.9.2' - // https://mvnrepository.com/artifact/com.squareup.okhttp3/logging-interceptor - compile group: 'com.squareup.okhttp3', name: 'logging-interceptor', version: '3.14.0' -} - -//ktor -dependencies { - // https://mvnrepository.com/artifact/io.ktor/ktor-client-websocket - compile group: 'io.ktor', name: 'ktor-client-websocket', version: ktor_version - // https://mvnrepository.com/artifact/io.ktor/ktor-client-cio - compile group: 'io.ktor', name: 'ktor-client-cio', version: ktor_version -} - -//checksum -dependencies { - // https://mvnrepository.com/artifact/com.hiczp/crc32-crack - compile group: 'com.hiczp', name: 'crc32-crack', version: '1.0' -} - -//unit test -dependencies { - // https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter - testCompile group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.4.1' -} - -task sourcesJar(type: Jar) { - from sourceSets.main.allSource - archiveClassifier = 'sources' -} - -task javadocJar(type: Jar) { - from javadoc - archiveClassifier = 'javadoc' -} - -publishing { repositories { - maven { - url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - credentials { - username = project.properties.ossUsername - password = project.properties.ossPassword - } + mavenCentral() + } + + configurations.all { + resolutionStrategy { + force "io.ktor:ktor-client-cio:$ktor_version" + } + } +} + +subprojects { + //kotlin + dependencies { + // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8 + api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8' + // https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core + api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: kotlin_coroutines_version + } + compileKotlin { + kotlinOptions { + jvmTarget = jvm_target + freeCompilerArgs = ["-Xjvm-default=enable", "-Xuse-experimental=kotlin.Experimental", "-XXLanguage:+InlineClasses"] + } + } + compileTestKotlin { + kotlinOptions { + jvmTarget = jvm_target + freeCompilerArgs = ["-Xjvm-default=enable", "-Xuse-experimental=kotlin.Experimental", "-XXLanguage:+InlineClasses"] } } - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar + //logging + dependencies { + // https://mvnrepository.com/artifact/io.github.microutils/kotlin-logging + api group: 'io.github.microutils', name: 'kotlin-logging', version: '1.6.26' + // https://mvnrepository.com/artifact/org.slf4j/slf4j-simple + testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.26' + } - pom { - name = project.name - description = project.description - url = 'https://github.com/czp3009/bilibili-api' + //unit test + dependencies { + // https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.4.2' + } - licenses { - license { - name = 'GNU GENERAL PUBLIC LICENSE Version 3' - url = 'https://www.gnu.org/licenses/gpl-3.0.txt' - } + task sourcesJar(type: Jar) { + from sourceSets.main.allSource + archiveClassifier = 'sources' + } + + task javadocJar(type: Jar) { + from javadoc + archiveClassifier = 'javadoc' + } + + publishing { + def moduleName = "${rootProject.name}-${project.name}" + + repositories { + maven { + url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + credentials { + username = project.properties.ossUsername + password = project.properties.ossPassword } + } + } - developers { - developer { - id = 'czp3009' - name = 'czp3009' - email = 'czp3009@gmail.com' - url = 'https://www.hiczp.com' - } - } + publications { + mavenJava(MavenPublication) { + from components.java + artifact sourcesJar + artifact javadocJar + artifactId moduleName - scm { - connection = 'scm:git:git://github.com/czp3009/bilibili-api.git' - developerConnection = 'scm:git:ssh://github.com/czp3009/bilibili-api.git' + pom { + name = moduleName + description = project.description url = 'https://github.com/czp3009/bilibili-api' + + licenses { + license { + name = 'GNU GENERAL PUBLIC LICENSE Version 3' + url = 'https://www.gnu.org/licenses/gpl-3.0.txt' + } + } + + developers { + developer { + id = 'czp3009' + name = 'czp3009' + email = 'czp3009@gmail.com' + url = 'https://www.hiczp.com' + } + } + + scm { + connection = 'scm:git:git://github.com/czp3009/bilibili-api.git' + developerConnection = 'scm:git:ssh://github.com/czp3009/bilibili-api.git' + url = 'https://github.com/czp3009/bilibili-api' + } } } } } + + signing { + sign publishing.publications.mavenJava + } } -signing { - sign publishing.publications.mavenJava +dependencies { + api project(':rest') + api project(':websocket') +} + +jar { + enabled = false } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b9d51f3..e78cfef 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/record/直播弹幕/ROOM_REAL_TIME_MESSAGE_UPDATE.json b/record/直播弹幕/ROOM_REAL_TIME_MESSAGE_UPDATE.json index bcfcf5b..6f3ebcc 100644 --- a/record/直播弹幕/ROOM_REAL_TIME_MESSAGE_UPDATE.json +++ b/record/直播弹幕/ROOM_REAL_TIME_MESSAGE_UPDATE.json @@ -2,6 +2,7 @@ "cmd": "ROOM_REAL_TIME_MESSAGE_UPDATE", "data": { "roomid": 23058, - "fans": 300958 + "fans": 297141, + "red_notice": -1 } -} \ No newline at end of file +} diff --git a/rest/.gitignore b/rest/.gitignore new file mode 100644 index 0000000..a9fc75b --- /dev/null +++ b/rest/.gitignore @@ -0,0 +1 @@ +src/test/resources/config.json diff --git a/rest/build.gradle b/rest/build.gradle new file mode 100644 index 0000000..67775e2 --- /dev/null +++ b/rest/build.gradle @@ -0,0 +1,19 @@ +//http +dependencies { + // https://mvnrepository.com/artifact/com.hiczp/caeruleum + api group: 'com.hiczp', name: 'caeruleum', version: '1.1.0' +} + +//json +dependencies { + // https://mvnrepository.com/artifact/com.google.code.gson/gson + api group: 'com.google.code.gson', name: 'gson', version: '2.8.5' + // https://mvnrepository.com/artifact/com.github.salomonbrys.kotson/kotson + api group: 'com.github.salomonbrys.kotson', name: 'kotson', version: '2.5.0' +} + +//checksum +dependencies { + // https://mvnrepository.com/artifact/com.hiczp/crc32-crack + api group: 'com.hiczp', name: 'crc32-crack', version: '1.0' +} diff --git a/rest/src/main/kotlin/com/hiczp/bilibili/rest/Empty.kt b/rest/src/main/kotlin/com/hiczp/bilibili/rest/Empty.kt new file mode 100644 index 0000000..2ea2615 --- /dev/null +++ b/rest/src/main/kotlin/com/hiczp/bilibili/rest/Empty.kt @@ -0,0 +1,2 @@ +package com.hiczp.bilibili.rest + diff --git a/src/test/resources/_config.json b/rest/src/test/resources/_config.json similarity index 100% rename from src/test/resources/_config.json rename to rest/src/test/resources/_config.json diff --git a/settings.gradle b/settings.gradle index 6bfff3c..f36d231 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,4 @@ -rootProject.name='bilibili-api' +rootProject.name = 'bilibili-api' + +include 'rest' +include 'websocket' diff --git a/src/main/kotlin/com/hiczp/bilibili/api/BaseUrl.kt b/src/main/kotlin/com/hiczp/bilibili/api/BaseUrl.kt deleted file mode 100644 index ed8bd4d..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/BaseUrl.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.hiczp.bilibili.api - -/** - * 各个站点的域名 - */ -object BaseUrl { - /** - * 用户鉴权 - */ - const val passport = "https://passport.bilibili.com" - - /** - * 消息 - */ - const val message = "https://message.bilibili.com" - - /** - * 主站 - */ - const val app = "https://app.bilibili.com" - - /** - * 这也是主站 - */ - const val main = "https://api.bilibili.com" - - /** - * 小视频 - */ - const val vc = "https://api.vc.bilibili.com" - - /** - * 创作中心 - */ - const val member = "https://member.bilibili.com" - - /** - * 直播 - */ - const val live = "https://api.live.bilibili.com" -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/BilibiliClient.kt b/src/main/kotlin/com/hiczp/bilibili/api/BilibiliClient.kt deleted file mode 100644 index edbdcec..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/BilibiliClient.kt +++ /dev/null @@ -1,325 +0,0 @@ -package com.hiczp.bilibili.api - -import com.hiczp.bilibili.api.app.AppAPI -import com.hiczp.bilibili.api.danmaku.DanmakuAPI -import com.hiczp.bilibili.api.live.LiveAPI -import com.hiczp.bilibili.api.main.MainAPI -import com.hiczp.bilibili.api.member.MemberAPI -import com.hiczp.bilibili.api.message.MessageAPI -import com.hiczp.bilibili.api.passport.PassportAPI -import com.hiczp.bilibili.api.passport.model.LoginResponse -import com.hiczp.bilibili.api.player.PlayerAPI -import com.hiczp.bilibili.api.player.PlayerInterceptor -import com.hiczp.bilibili.api.retrofit.Header -import com.hiczp.bilibili.api.retrofit.Param -import com.hiczp.bilibili.api.retrofit.exception.BilibiliApiException -import com.hiczp.bilibili.api.retrofit.interceptor.CommonHeaderInterceptor -import com.hiczp.bilibili.api.retrofit.interceptor.CommonParamInterceptor -import com.hiczp.bilibili.api.retrofit.interceptor.FailureResponseInterceptor -import com.hiczp.bilibili.api.retrofit.interceptor.SortAndSignInterceptor -import com.hiczp.bilibili.api.vc.VcAPI -import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory -import okhttp3.ConnectionPool -import okhttp3.Interceptor -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import java.security.KeyFactory -import java.security.spec.X509EncodedKeySpec -import java.text.SimpleDateFormat -import java.time.Instant -import java.util.* -import javax.crypto.Cipher - -/** - * 此类表示一个模拟的 Bilibili 客户端(Android), 所有调用由此开始. - * 多个 BilibiliClient 实例之间不共享登陆状态. - * 不能严格保证线程安全. - * - * @param billingClientProperties 客户端的固有属性, 是一种常量 - * @param logLevel 日志打印等级 - */ -@Suppress("unused") -class BilibiliClient( - @Suppress("MemberVisibilityCanBePrivate") - val billingClientProperties: BilibiliClientProperties = BilibiliClientProperties(), - private val logLevel: HttpLoggingInterceptor.Level = HttpLoggingInterceptor.Level.NONE -) { - /** - * 客户端被打开的时间(BilibiliClient 被实例化的时间) - */ - private val initTime = Instant.now().epochSecond - - /** - * 登陆操作得到的 Response - */ - var loginResponse: LoginResponse? = null - - /** - * 是否已登录 - */ - val isLogin - get() = loginResponse != null - - //快捷方式 - @Suppress("MemberVisibilityCanBePrivate") - val userId - get() = loginResponse?.userId - @Suppress("MemberVisibilityCanBePrivate") - val token - get() = loginResponse?.token - - @Suppress("SpellCheckingInspection") - private val defaultCommonHeaderInterceptor = CommonHeaderInterceptor( - Header.DISPLAY_ID to { "${billingClientProperties.buildVersionId}-$initTime" }, - Header.BUILD_VERSION_ID to { billingClientProperties.buildVersionId }, - Header.USER_AGENT to { billingClientProperties.defaultUserAgent }, - Header.DEVICE_ID to { billingClientProperties.hardwareId } - ) - - @Suppress("SpellCheckingInspection") - private val defaultCommonParamArray = arrayOf( - Param.ACCESS_KEY to { token }, - Param.APP_KEY to { billingClientProperties.appKey }, - Param.BUILD to { billingClientProperties.build }, - Param.CHANNEL to { billingClientProperties.channel }, - Param.MOBILE_APP to { billingClientProperties.platform }, - Param.PLATFORM to { billingClientProperties.platform }, - Param.TIMESTAMP to { Instant.now().epochSecond.toString() } - ) - - private val defaultCommonParamInterceptor = CommonParamInterceptor(*defaultCommonParamArray) - - /** - * 用户鉴权相关的接口 - */ - @Suppress("SpellCheckingInspection") - val passportAPI by lazy { - createAPI(BaseUrl.passport, - defaultCommonHeaderInterceptor, - CommonParamInterceptor( - Param.APP_KEY to { billingClientProperties.appKey }, - Param.BUILD to { billingClientProperties.build }, - Param.CHANNEL to { billingClientProperties.channel }, - Param.MOBILE_APP to { billingClientProperties.platform }, - Param.PLATFORM to { billingClientProperties.platform }, - Param.TIMESTAMP to { Instant.now().epochSecond.toString() } - ) - ) - } - - /** - * 消息通知有关的接口 - */ - @Suppress("SpellCheckingInspection") - val messageAPI by lazy { - createAPI(BaseUrl.message, - defaultCommonHeaderInterceptor, - CommonParamInterceptor(*defaultCommonParamArray, - Param.ACTION_KEY to { Param.APP_KEY }, - "has_up" to { "1" } - ) - ) - } - - /** - * 总站 API - */ - @Suppress("SpellCheckingInspection") - val appAPI by lazy { - createAPI(BaseUrl.app, - defaultCommonHeaderInterceptor, - defaultCommonParamInterceptor - ) - } - - /** - * 这也是总站 API - */ - @Suppress("SpellCheckingInspection") - val mainAPI by lazy { - createAPI(BaseUrl.main, - CommonHeaderInterceptor( - //如果未登陆则没有 Display-ID - Header.DISPLAY_ID to { userId?.let { "$it-$initTime" } }, - Header.BUILD_VERSION_ID to { billingClientProperties.buildVersionId }, - Header.USER_AGENT to { billingClientProperties.defaultUserAgent }, - Header.DEVICE_ID to { billingClientProperties.hardwareId } - ), - defaultCommonParamInterceptor - ) - } - - /** - * 小视频相关接口 - */ - @Suppress("SpellCheckingInspection") - val vcAPI by lazy { - createAPI(BaseUrl.vc, - defaultCommonHeaderInterceptor, - CommonParamInterceptor(*defaultCommonParamArray, - Param._DEVICE to { billingClientProperties.platform }, - Param._HARDWARE_ID to { billingClientProperties.hardwareId }, - Param.SOURCE to { billingClientProperties.channel }, - Param.TRACE_ID to { generateTraceId() }, - Param.USER_ID to { userId?.toString() }, - Param.VERSION to { billingClientProperties.version } - ) - ) - } - - /** - * 创作中心 - */ - val memberAPI by lazy { - createAPI(BaseUrl.member, - defaultCommonHeaderInterceptor, - defaultCommonParamInterceptor - ) - } - - /** - * 播放器所需的 API, 用于获取视频播放地址 - */ - val playerAPI: PlayerAPI by lazy { - Retrofit.Builder() - .baseUrl("https://bilibili.com") //这里的 baseUrl 是没用的 - .addConverterFactory(gsonConverterFactory) - .addCallAdapterFactory(coroutineCallAdapterFactory) - .client(OkHttpClient.Builder().apply { - addInterceptor(PlayerInterceptor(billingClientProperties) { loginResponse }) - addInterceptor(FailureResponseInterceptor) - addNetworkInterceptor(httpLoggingInterceptor) - connectionPool(connectionPool) - }.build()) - .build() - .create(PlayerAPI::class.java) - } - - /** - * 获取弹幕所用的 API - */ - val danmakuAPI: DanmakuAPI by lazy { - Retrofit.Builder() - .baseUrl(BaseUrl.main) - .addCallAdapterFactory(coroutineCallAdapterFactory) - .client(OkHttpClient.Builder().apply { - addInterceptor(CommonHeaderInterceptor( - Header.ACCEPT to { "application/xhtml+xml,application/xml" }, - Header.ACCEPT_ENCODING to { "gzip, deflate" }, - Header.USER_AGENT to { billingClientProperties.defaultUserAgent } - )) - addInterceptor(defaultCommonParamInterceptor) - addInterceptor(sortAndSignInterceptor) - addNetworkInterceptor(httpLoggingInterceptor) - connectionPool(connectionPool) - }.build()) - .build() - .create(DanmakuAPI::class.java) - } - - /** - * 直播站 - */ - val liveAPI by lazy { - createAPI(BaseUrl.live, - CommonHeaderInterceptor( - //如果未登陆则没有 Display-ID - Header.DISPLAY_ID to { userId?.let { "$it-$initTime" } }, - Header.BUILD_VERSION_ID to { billingClientProperties.buildVersionId }, - Header.USER_AGENT to { billingClientProperties.defaultUserAgent }, - Header.DEVICE_ID to { billingClientProperties.hardwareId } - ), - CommonParamInterceptor(*defaultCommonParamArray, - Param.ACTION_KEY to { Param.APP_KEY }, - Param.DEVICE to { billingClientProperties.platform } - ) - ) - } - - /** - * 登陆 - * v3 登陆接口会同时返回 cookies 和 token - * 如果要求验证码, 访问 data 中提供的 url 将打开一个弹窗, 里面会加载 js 并显示极验 - * 极验会调用 https://api.geetest.com/ajax.php 上传滑动轨迹, 然后获得 validate 的值 - * secCode 的值为 "$validate|jordan" - * - * @throws BilibiliApiException 用户名与密码不匹配(-629)或者需要验证码(极验)(-105) - */ - @Throws(BilibiliApiException::class) - suspend fun login( - username: String, password: String, - //如果登陆请求返回了 "验证码错误!"(-105) 的结果, 那么下一次发送登陆请求就需要带上验证码 - challenge: String? = null, - secCode: String? = null, - validate: String? = null - ): LoginResponse { - //取得 hash 和 RSA 公钥 - val (hash, key) = passportAPI.getKey().await().data.let { data -> - data.hash to data.key.split('\n').filterNot { it.startsWith('-') }.joinToString(separator = "") - } - - //解析 RSA 公钥 - val publicKey = X509EncodedKeySpec(Base64.getDecoder().decode(key)).let { - KeyFactory.getInstance("RSA").generatePublic(it) - } - //加密密码 - //兼容 Android - val cipheredPassword = Cipher.getInstance("RSA/ECB/PKCS1Padding").apply { - init(Cipher.ENCRYPT_MODE, publicKey) - }.doFinal((hash + password).toByteArray()).let { - Base64.getEncoder().encode(it) - }.let { - String(it) - } - - return passportAPI.login(username, cipheredPassword, challenge, secCode, validate).await().also { - this.loginResponse = it - } - } - - /** - * 登出 - * 这个方法不一定是线程安全的, 登出的同时如果进行登陆操作可能引发错误 - */ - suspend fun logout() { - val response = loginResponse ?: return - val cookieMap = response.data.cookieInfo.cookies - .associate { - it.name to it.value - } - passportAPI.revoke(cookieMap, response.token).await() - loginResponse = null - } - - private val sortAndSignInterceptor = SortAndSignInterceptor(billingClientProperties.appSecret) - private val httpLoggingInterceptor = HttpLoggingInterceptor().setLevel(logLevel) - private inline fun createAPI( - baseUrl: String, - vararg interceptors: Interceptor - ) = Retrofit.Builder() - .baseUrl(baseUrl) - .addConverterFactory(gsonConverterFactory) - .addCallAdapterFactory(coroutineCallAdapterFactory) - .client(OkHttpClient.Builder().apply { - interceptors.forEach { - addInterceptor(it) - } - addInterceptor(sortAndSignInterceptor) - addInterceptor(FailureResponseInterceptor) - addNetworkInterceptor(httpLoggingInterceptor) - connectionPool(connectionPool) - }.build()) - .build() - .create(T::class.java) - - companion object { - @Suppress("SpellCheckingInspection") - private val gsonConverterFactory = GsonConverterFactory.create() - private val coroutineCallAdapterFactory = CoroutineCallAdapterFactory() - private val connectionPool = ConnectionPool() - private val traceIdFormat = SimpleDateFormat("yyyyMMddHHmm000ss") - private fun generateTraceId() = traceIdFormat.format(Date()) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/BilibiliClientProperties.kt b/src/main/kotlin/com/hiczp/bilibili/api/BilibiliClientProperties.kt deleted file mode 100644 index d294155..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/BilibiliClientProperties.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.hiczp.bilibili.api - -/** - * 客户端固有属性. 包括版本号, 密钥以及硬件编码. - * 默认值对应 5.37.0(release-b220051) 版本. - */ -class BilibiliClientProperties { - /** - * 默认 UA, 用于大多数访问 - */ - @Suppress("SpellCheckingInspection") - var defaultUserAgent = "Mozilla/5.0 BiliDroid/5.37.0 (bbcallen@gmail.com)" - - /** - * Android 平台的 appKey(该默认值为普通版客户端, 非概念版) - */ - var appKey = "1d8b6e7d45233436" - - /** - * 由反编译 so 文件得到的 appSecret, 与 appKey 必须匹配 - */ - @Suppress("SpellCheckingInspection") - var appSecret = "560c52ccd288fed045859ed18bffd973" - - /** - * 获取视频播放地址使用的 appKey, 与访问其他 RestFulAPI 所用的 appKey 是不一样的 - */ - @Suppress("SpellCheckingInspection") - var videoAppKey = "iVGUTjsxvpLeuDCf" - - /** - * 获取视频播放地址所用的 appSecret - */ - @Suppress("SpellCheckingInspection") - var videoAppSecret = "aHRmhWMLkdeMuILqORnYZocwMBpMEOdt" - - /** - * 客户端平台 - */ - var platform = "android" - - /** - * 客户端类型 - * 此属性在旧版客户端不存在 - */ - var channel = "html5_app_bili" - - /** - * 硬件 ID, 尚不明确生成算法 - */ - @Suppress("SpellCheckingInspection") - var hardwareId = "aBRoDWAVeRhsA3FDewMzS3lLMwM" - - /** - * 屏幕尺寸, 大屏手机(已经没有小屏手机了)统一为 xxhdpi - * 此参数在新版客户端已经较少使用 - */ - var scale = "xxhdpi" - - /** - * 版本号 - */ - var version = "5.37.0.5370000" - - /** - * 构建版本号 - */ - var build = "5370000" - - /** - * 构建版本 ID, 可能是某种 Hash - */ - var buildVersionId = "XXD9E43D7A1EBB6669597650E3EE417D9E7F5" -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/CipherExtension.kt b/src/main/kotlin/com/hiczp/bilibili/api/CipherExtension.kt deleted file mode 100644 index c81bb55..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/CipherExtension.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.hiczp.bilibili.api - -import java.security.MessageDigest - -//MD5 -private val md5Instance = MessageDigest.getInstance("MD5") - -fun String.md5() = - StringBuilder(32).apply { - //优化过的 md5 字符串生成算法 - md5Instance.digest(toByteArray()).forEach { - val value = it.toInt() and 0xFF - val high = value / 16 - val low = value % 16 - append(if (high <= 9) '0' + high else 'a' - 10 + high) - append(if (low <= 9) '0' + low else 'a' - 10 + low) - } - }.toString() - -/** - * 签名算法为 "$排序后的参数字符串$appSecret".md5() - */ -internal fun calculateSign(sortedQuery: String, appSecret: String) = (sortedQuery + appSecret).md5() diff --git a/src/main/kotlin/com/hiczp/bilibili/api/CollectionExtension.kt b/src/main/kotlin/com/hiczp/bilibili/api/CollectionExtension.kt deleted file mode 100644 index 171781d..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/CollectionExtension.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.hiczp.bilibili.api - -import kotlin.experimental.ExperimentalTypeInference - -@UseExperimental(ExperimentalTypeInference::class) -internal inline fun list(@BuilderInference block: MutableList.() -> Unit): List { - val list = ArrayList() - block(list) - return list -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/GlobalConstant.kt b/src/main/kotlin/com/hiczp/bilibili/api/GlobalConstant.kt deleted file mode 100644 index 092a00d..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/GlobalConstant.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.hiczp.bilibili.api - -import com.google.gson.Gson -import com.google.gson.JsonParser - -internal val gson = Gson() - -internal val jsonParser = JsonParser() diff --git a/src/main/kotlin/com/hiczp/bilibili/api/GsonExtension.kt b/src/main/kotlin/com/hiczp/bilibili/api/GsonExtension.kt deleted file mode 100644 index e9a26c4..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/GsonExtension.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.hiczp.bilibili.api - -import com.google.gson.JsonArray - -@Suppress("NOTHING_TO_INLINE") -inline fun JsonArray.isEmpty() = size() == 0 - -@Suppress("NOTHING_TO_INLINE") -inline fun JsonArray.isNotEmpty() = size() != 0 diff --git a/src/main/kotlin/com/hiczp/bilibili/api/IOExtension.kt b/src/main/kotlin/com/hiczp/bilibili/api/IOExtension.kt deleted file mode 100644 index c978d65..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/IOExtension.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.hiczp.bilibili.api - -import com.hiczp.bilibili.api.thirdpart.commons.BoundedInputStream -import io.ktor.util.InternalAPI -import kotlinx.io.errors.EOFException -import java.io.InputStream - -//减少包引入 -//https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/IOUtils.java -fun InputStream.readFully(length: Int): ByteArray { - if (length < 0) { - throw IllegalArgumentException("Length must not be negative: $length") - } - - val byteArray = ByteArray(length) - var remaining = length - - while (remaining > 0) { - val count = read(byteArray, length - remaining, remaining) - if (count == -1) break - remaining -= count - } - - val actual = length - remaining - if (actual != length) { - throw EOFException("Length to read: $length actual: $actual") - } - - return byteArray -} - -/** - * 以大端模式从流中读取一个 int - */ -@UseExperimental(ExperimentalUnsignedTypes::class) -fun InputStream.readInt(): Int { - val byteArray = readFully(4) - return (byteArray[0].toUByte().toInt() shl 24) or - (byteArray[1].toUByte().toInt() shl 16) or - (byteArray[2].toUByte().toInt() shl 8) or - (byteArray[3].toUByte().toInt()) -} - -/** - * 以大端模式从流中读取一个 unsigned int - */ -@UseExperimental(ExperimentalUnsignedTypes::class) -fun InputStream.readUInt() = readInt().toUInt() - -fun InputStream.bounded(size: Long) = BoundedInputStream(this, size) - -@UseExperimental(ExperimentalUnsignedTypes::class) -fun InputStream.bounded(size: UInt) = bounded(size.toLong()) - -@UseExperimental(InternalAPI::class) -internal fun ByteArray.toPrettyPrintString() = joinToString(prefix = "[", postfix = "]") { "0x%02x".format(it) } diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/AppAPI.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/AppAPI.kt deleted file mode 100644 index d0bff12..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/AppAPI.kt +++ /dev/null @@ -1,383 +0,0 @@ -package com.hiczp.bilibili.api.app - -import com.google.gson.JsonObject -import com.hiczp.bilibili.api.app.model.* -import com.hiczp.bilibili.api.retrofit.CommonResponse -import kotlinx.coroutines.Deferred -import retrofit2.http.* -import java.time.Instant - -/** - * 总站 API - */ -@Suppress("DeferredIsResult") -interface AppAPI { - /** - * 打开 APP 时将访问此接口来获得 UI 排布顺序 - * 包括下方 tab(首页, 频道, 动态, 会员购), 首页的上方 tab(直播, 推荐, 热门, 追番) 以及右上角的 游戏中心, 离线下载, 消息 - */ - @GET("/x/resource/show/tab") - fun tab(): Deferred - - /** - * 登陆完成后将请求一次此接口以获得个人资料 - * 如果未登录将返回 {"code":-101,"message":"账号未登录","ttl":1} - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/account/myinfo") - fun myInfo(): Deferred - - /** - * 登陆后也会访问此接口, 返回内容大致与 myInfo() 相同 - */ - @GET("/x/v2/account/mine") - fun mine(): Deferred - - /** - * 侧边栏中动态增加的按钮, 返回信息包含 URI 地址(到对应的 activity) - * 侧拉抽屉 - */ - @GET("/x/resource/sidebar") - fun sidebar(): Deferred - - /** - * 首页内容(客户端通过解析返回的内容来生成页面内容, 下同) - * 该 API 没有翻页参数, 同样的参数每次请求都会返回不一样的内容. 刷新和下拉只是简单的重新访问此接口. - * 首页 -> 推荐 - * - * @param pull 如果是通过滑动到最顶端来刷新页面的, 那么将是 true, 将页面滑动到最底端来获取更多内容将是 false - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/feed/index") - fun homePage( - @Query("ad_extra") adExtra: String? = null, - @Query("autoplay_card") autoplayCard: Int = 0, - @Query("banner_hash") bannerHash: String? = null, - @Query("column") column: Int = 2, - @Query("device_type") deviceType: Int = 0, - @Query("flush") flush: Int = 0, - @Query("fnval") fnVal: Int = 16, - @Query("fnver") fnVer: Int = 0, - @Query("force_host") forceHost: Int = 0, - @Query("idx") index: Long = Instant.now().epochSecond, - @Query("login_event") loginEvent: Int = 0, - @Query("network") network: String = "mobile", - @Query("open_event") openEvent: String? = null, - @Query("pull") pull: Boolean = true, - @Query("qn") qn: Int = 32, - @Query("recsys_mode") recsysMode: Int = 0 - ): Deferred - - /** - * 热门页面 - * 首页 -> 热门 - * - * @param index 翻页参数, 一开始为 0, 然后每次滑动到底端就会加 10 - * @param ver 第一次请求时没有这个参数, 第二次开始这个参数为上一次请求此接口时的返回值中的 `ver` - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/show/popular/index") - fun popularPage( - @Query("fnval") fnVal: Int = 16, - @Query("fnver") fnVer: Int = 0, - @Query("force_host") forceHost: Int = 0, - @Query("idx") index: Long = 0, - @Query("last_param") lastParam: String? = null, - @Query("login_event") loginEvent: Int = 0, - @Query("qn") qn: Int = 32, - @Query("ver") ver: Long? = null - ): Deferred - - /** - * 视频页面(普通视频, 非番剧) - * 包含视频基本信息, 推荐和广告 - * 从这个接口得到视频的 cid - * 如果返回内容里的 pages 有多个表明有多个 p, 每个 p 有自己的 cid(外层的 cid 为默认的那个 p 的 cid) - * - * @param aid av 号 - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/view") - fun view( - @Query("ad_extra") adExtra: String? = null, - @Query("aid") aid: Long, - @Query("autoplay") autoplay: Int = 0, - @Query("fnval") fnVal: Int = 16, - @Query("fnver") fnVer: Int = 0, - @Query("force_host") forceHost: Int = 0, - @Query("from") from: Int? = null, - @Query("plat") plat: Int = 0, - @Query("qn") qn: Int = 32, - @Query("trackid") trackId: String? = null //all_10.shylf-ai-recsys-120.1550674524909.237 - ): Deferred - - /** - * 点赞(视频) - * - * @param aid 视频的唯一标识 - * @param like 为 0 时表示点赞, 为 1 时表示取消点赞 - * @param dislike 正常为 0, 为 1 时(like 为 0)表示 取消不喜欢的同时为该视频点赞(等于做了两个操作, 下同) - */ - @POST("/x/v2/view/like") - @FormUrlEncoded - fun like( - @Field("aid") aid: Long, - @Field("like") like: Int = 0, - @Field("dislike") dislike: Int = 0, - @Field("from") from: Int? = null - ): Deferred - - /** - * 不喜欢(视频) - * - * @param aid 视频的唯一标识 - * @param dislike 为 0 时表示不喜欢, 为 1 时表示取消不喜欢 - * @param like 正常为 0, 为 1 时(dislike 为 0)表示 取消点赞的同时不喜欢该视频 - */ - @POST("/x/v2/view/dislike") - @FormUrlEncoded - fun dislike( - @Field("aid") aid: Long, - @Field("like") like: Int = 0, - @Field("dislike") dislike: Int = 0, - @Field("from") from: Int? = null - ): Deferred - - /** - * 投币 - * 自制视频能投两个, 转载视频只能投一个. 是转载还是自制在获取视频页面的 API 的 copyright. - * - * @param multiply 投币数量 - * @param selectLike 为 1 表示投币的同时为视频点赞, 对番剧投币时, 该值总为 0 - * @param upId 该值似乎总为 0 - * - * @see view - */ - @Suppress("SpellCheckingInspection") - @POST("/x/v2/view/coin/add") - @FormUrlEncoded - fun addCoin( - @Field("aid") aid: Long, - @Field("avtype") avType: Int = 1, - @Field("from") from: Int? = null, - @Field("multiply") multiply: Int, - @Field("select_like") selectLike: Int = 0, - @Field("upid") upId: Long? = 0 - ): Deferred - - /** - * 查看某个用户的主页(也可以查看自己) - * - * @param vmId 欲查看的用户的 id - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/space") - fun space( - @Query("from") from: Int? = 0, - @Query("ps") pageSize: Int = 10, - @Query("vmid") vmId: Long - ): Deferred - - /** - * 收藏页面 - * 侧拉抽屉 -> 收藏 - * - * @param vmId 所查看的用户的 id(看自己的收藏也要有该参数) - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/favorite") - fun favoritePage( - @Query("aid") aid: Long = 0, - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("vmid") vmId: Long - ): Deferred - - /** - * 收藏的视频 - * 侧拉抽屉 -> 收藏 -> 视频 -> (打开一个收藏夹) - * - * @param fid 收藏夹的 id, 在拉取收藏页面时获得 - * @param tid 不明确 - * @param vmId 用户 id - * - * @see favoritePage - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/favorite/video") - fun favoriteVideo( - @Query("fid") fid: Long, - @Query("order") order: String = "ftime", - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("tid") tid: Long = 0, - @Query("vmid") vmId: Long - ): Deferred - - /** - * 收藏的文章 - * 这个 API 的返回内容里没有总页数, 真实的客户端会直接访问下一页来确认当前页是不是最后一页 - * 侧拉抽屉 -> 收藏 -> 专栏 - */ - @GET("/x/v2/favorite/article") - fun favoriteArticle( - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20 - ): Deferred - - /** - * 大家都在搜(热搜关键字列表) - * - * 上方搜索栏 -> 搜索提示 - * - * @param limit 分页大小 - */ - @GET("/x/v2/search/hot") - fun searchHot(@Query("limit") limit: Int = 50): Deferred - - /** - * 默认搜索词, 当点击搜索框但是没输入内容时就会显示该词条. - * - * 上方搜索框 -> placeholder - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/search/defaultwords") - fun searchDefaultWords(): Deferred - - /** - * 搜索联想 - * - * 上方搜索框 -> 搜索时的显示的候选项 - */ - @GET("/x/v2/search/suggest3") - fun searchSuggest( - @Query("highlight") highlight: Int = 1, - @Query("keyword") keyword: String - ): Deferred - - /** - * 搜索(综合) - * - * 上方搜索栏 - * - * @param order 排序. null/default 默认排序, view 播放多, pubdate 新发布, danmaku 弹幕多 - * @param duration 视频时长. 0 全部时长, 1 0-10分钟, 2 10-30分钟, 3 30-60分钟, 4 60+分钟 - * @param rid 按某种分区搜索, 编号为数字. null 全部分区. - * @param keyword 搜索的关键字, 下同 - * @param from_source 来源, 如果是直接搜索的则为 app_search, 在历史记录里点击的则为 apphistory_search, 从搜索时的候选项里点的为 appsuggest_search - * @param pageNumber 分页, 从 1 开始 - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/search") - fun search( - @Query("duration") duration: Int = 0, - @Query("from_source") from_source: String = "app_search", - @Query("highlight") highlight: Int = 1, - @Query("keyword") keyword: String, - @Query("order") order: String? = null, - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("recommend") recommend: Int = 1, - @Query("rid") rid: Int? = null - ): Deferred - - /** - * 搜索直播间 - * - * 上方搜索栏 -> 直播 - * - * @param type 搜索的内容的类型, 每种搜索的 type 都是固定的, 下同 - */ - @GET("/x/v2/search/live") - fun searchLive( - @Query("keyword") keyword: String, - @Suppress("SpellCheckingInspection") - @Query("order") order: String = "totalrank", - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("type") type: Int = 4 - ): Deferred - - /** - * 根据某个类型来进行搜索(自定义) - */ - @GET("/x/v2/search/type") - fun searchType( - @Query("keyword") keyword: String, - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("type") type: Int, - @QueryMap additionParam: Map - ): Deferred - - /** - * 搜索番剧 - * - * 上方搜索栏 -> 番剧 - */ - @GET("/x/v2/search/type") - fun searchBangumi( - @Query("keyword") keyword: String, - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("type") type: Int = 7 - ): Deferred - - /** - * 搜索用户 - * - * 上方搜索栏 -> 用户 - * - * @param order 排序维度. totalrank 默认排序,fans 粉丝, level 等级. - * @param orderSort 排序顺序. 0 从高到低, 1 从低到高. - * @param userType 用户类型. 0 全部用户, 1 up主, 2 普通用户, 3 认证用户. - * - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/search/type") - fun searchUser( - @Query("highlight") highlight: Int = 1, - @Query("keyword") keyword: String, - @Query("order") order: String = "totalrank", - @Query("order_sort") orderSort: Int? = null, - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("type") type: Int = 2, - @Query("user_type") userType: Int = 0 - ): Deferred - - /** - * 搜索影视(包括动漫的剧场版和纪录片) - * - * 上方搜索栏 -> 影视 - */ - @GET("/x/v2/search/type") - fun searchMovie( - @Query("keyword") keyword: String, - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("type") type: Int = 8 - ): Deferred - - /** - * 搜索文章 - * - * 上方搜索栏 -> 专栏 - * - * @param order 排序. null 默认排序, pubdate 发布时间, click 按阅读数, scores 按评论数, attention 按点赞数. - * @param categoryId 分类, 编号为数字. 0 全部分类. - * - * @see com.hiczp.bilibili.api.main.MainAPI.articleCategories - */ - @Suppress("SpellCheckingInspection") - @GET("/x/v2/search/type") - fun searchArticle( - @Query("category_id") categoryId: Int = 0, - @Query("highlight") highlight: Int = 1, - @Query("keyword") keyword: String, - @Query("order") order: String? = null, - @Query("pn") pageNumber: Int = 1, - @Query("ps") pageSize: Int = 20, - @Query("type") type: Int = 6 - ): Deferred -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/AddCoinResponse.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/AddCoinResponse.kt deleted file mode 100644 index ef511a5..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/AddCoinResponse.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class AddCoinResponse( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("like") - var like: Boolean, // false - @SerializedName("prompt") - var prompt: Boolean? // true - ) -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoriteArticle.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoriteArticle.kt deleted file mode 100644 index 0f90cd0..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoriteArticle.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class FavoriteArticle( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("count") - var count: Int, // 1 - @SerializedName("items") - var items: List - ) { - data class Item( - @SerializedName("banner_url") - var bannerUrl: String, // https://i0.hdslb.com/bfs/article/97cddc6d048297aedcc5cc498cbfb090358567eb.jpg - @SerializedName("favorite_time") - var favoriteTime: Int, // 1551348963 - @SerializedName("goto") - var goto: String, // article - @SerializedName("id") - var id: Long, // 2165049 - @SerializedName("image_urls") - var imageUrls: List, - @SerializedName("name") - var name: String, // 京八贱 - @SerializedName("param") - var `param`: String, // 2165049 - @SerializedName("summary") - var summary: String, // 相信不少玩家在完破了《荒野大镖客:救赎2》的单人剧情模式后,就开始了线上模式。近期官方推出的更新给大家带来了不少新内容,比如新的对决模式、竞速、衣物和表情动作等等,还强化了游戏内的通缉和小地图等系统,尝试给予玩家更加多样的体验。不过更新上线后所带来的改变反而激起了玩家的怒火,首当其冲的便是打猎相关的更动,在游戏中玩家可把肢解完毕的猎物尸体卖给肉贩,而经历了这次的更新后,多人线上模式这项打猎物品的价格直接被砍半,玩家也发现不少猎物的掉落物数量有减少的迹象,让不少喜爱悠闲打猎生活的玩家大感不满。猎人 - @SerializedName("template_id") - var templateId: Int, // 4 - @SerializedName("title") - var title: String, // 《荒野大镖客2》线上模式的近期更新引起玩家强烈不满,引发争议 - @SerializedName("uri") - var uri: String // bilibili://article/2165049 - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoritePage.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoritePage.kt deleted file mode 100644 index 10eb5a1..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoritePage.kt +++ /dev/null @@ -1,84 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class FavoritePage( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("favorite") - var favorite: Favorite, - @SerializedName("tab") - var tab: Tab - ) { - data class Favorite( - @SerializedName("count") - var count: Int, // 1 - @SerializedName("items") - var items: List - ) { - data class Item( - /** - * 如果该收藏夹最后一个视频被删除了, 那么将没有封面 - */ - @SerializedName("cover") - var cover: List?, // null - @SerializedName("cur_count") - var curCount: Int, // 1 - @SerializedName("fid") - var fid: Long, // 795158 - @SerializedName("media_id") - var mediaId: Long, // 79515830 - @SerializedName("mid") - var mid: Long, // 20293030 - @SerializedName("name") - var name: String, // 默认收藏夹 - @SerializedName("state") - var state: Int // 0 - ) { - data class Cover( - @SerializedName("aid") - var aid: Long, // 9498716 - @SerializedName("pic") - var pic: String, // http://i2.hdslb.com/bfs/archive/3536b8de71da4dd7bf01200db1e6c710b5f4aa0e.png - @SerializedName("type") - var type: Int // 2 - ) - } - } - - data class Tab( - @SerializedName("albums") - var albums: Boolean, // false - @SerializedName("article") - var article: Boolean, // true - @SerializedName("audios") - var audios: Boolean, // false - @SerializedName("cinema") - var cinema: Boolean, // true - @SerializedName("clips") - var clips: Boolean, // false - @SerializedName("favorite") - var favorite: Boolean, // true - @SerializedName("menu") - var menu: Boolean, // false - @SerializedName("pgc_menu") - var pgcMenu: Boolean, // false - @SerializedName("product") - var product: Boolean, // false - @SerializedName("specil") - var specil: Boolean, // false - @SerializedName("ticket") - var ticket: Boolean, // false - @SerializedName("topic") - var topic: Boolean // false - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoriteVideo.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoriteVideo.kt deleted file mode 100644 index 1ad8cd5..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/FavoriteVideo.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class FavoriteVideo( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("count") - var count: Int, // 1 - @SerializedName("items") - var items: List - ) { - data class Item( - @SerializedName("aid") - var aid: Int, // 30702 - @SerializedName("danmaku") - var danmaku: Int, // 19363 - @SerializedName("goto") - var goto: String, // av - @SerializedName("name") - var name: String, // ⑨搬运君 - @SerializedName("param") - var `param`: String, // 30702 - @SerializedName("pic") - var pic: String, // http://i1.hdslb.com/bfs/archive/76a045020b6aaa830121132d4a6536d6b82660f4.jpg - @SerializedName("play_num") - var playNum: Long, // 371718 - @SerializedName("title") - var title: String, // 【整理发布】妄想学生会 - @SerializedName("ugc_pay") - var ugcPay: Long, // 0 - @SerializedName("uri") - var uri: String // bilibili://video/30702 - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/HomePage.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/HomePage.kt deleted file mode 100644 index d060718..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/HomePage.kt +++ /dev/null @@ -1,375 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.JsonElement -import com.google.gson.annotations.SerializedName - -data class HomePage( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("config") - var config: Config, - @SerializedName("items") - var items: List - ) { - data class Item( - @SerializedName("ad_info") - var adInfo: AdInfo, - @SerializedName("args") - var args: Args, - @SerializedName("badge") - var badge: String, // 直播 - @SerializedName("banner_item") - var bannerItem: List, - @SerializedName("can_play") - var canPlay: Int, // 1 - @SerializedName("card_goto") - var cardGoto: String, // av - @SerializedName("card_type") - var cardType: String, // small_cover_v2 - @SerializedName("cover") - var cover: String, // http://i0.hdslb.com/bfs/archive/884e982379b32ef1dc3281e0da1864e62cf74cc3.jpg - @SerializedName("cover_left_icon_1") - var coverLeftIcon1: Int, // 1 - @SerializedName("cover_left_icon_2") - var coverLeftIcon2: Int, // 3 - @SerializedName("cover_left_text_1") - var coverLeftText1: String, // 2.9万 - @SerializedName("cover_left_text_2") - var coverLeftText2: String, // 471 - @SerializedName("cover_right_text") - var coverRightText: String, // 33:33 - @SerializedName("desc") - var desc: String, // 少年歌行11 - @SerializedName("desc_button") - var descButton: DescButton, - @SerializedName("goto") - var goto: String, // av - @SerializedName("hash") - var hash: String, // 674069931701357536 - @SerializedName("idx") - var idx: Int, // 1550559507 - @SerializedName("official_icon") - var officialIcon: Int, // 17 - @SerializedName("param") - var `param`: String, // 43804922 - @SerializedName("player_args") - var playerArgs: PlayerArgs, - @SerializedName("rcmd_reason") - var rcmdReason: String, // 已关注 - @SerializedName("rcmd_reason_style") - var rcmdReasonStyle: RcmdReasonStyle, - @SerializedName("three_point") - var threePoint: ThreePoint, - @SerializedName("three_point_v2") - var threePointV2: List, - @SerializedName("title") - var title: String, // 宇宙沙盘2娱乐,给地球加1000个月亮,先要准备好灭火器 - @SerializedName("title_right_pic") - var titleRightPic: Int, // 14 - @SerializedName("title_right_text") - var titleRightText: String, // 1 - @SerializedName("uri") - var uri: String // bilibili://video/43804922?page=1&player_preload=%7B%22cid%22%3A76731390%2C%22expire_time%22%3A1550649542%2C%22file_info%22%3A%7B%22112%22%3A%5B%7B%22timelength%22%3A2012565%2C%22filesize%22%3A1416010611%7D%5D%2C%2216%22%3A%5B%7B%22timelength%22%3A2012565%2C%22filesize%22%3A72842412%7D%5D%2C%2232%22%3A%5B%7B%22timelength%22%3A2012565%2C%22filesize%22%3A163018544%7D%5D%2C%2264%22%3A%5B%7B%22timelength%22%3A2012565%2C%22filesize%22%3A360516756%7D%5D%2C%2280%22%3A%5B%7B%22timelength%22%3A2012565%2C%22filesize%22%3A540132030%7D%5D%7D%2C%22support_quality%22%3A%5B112%2C80%2C64%2C32%2C16%5D%2C%22support_formats%22%3A%5B%22hdflv2%22%2C%22flv%22%2C%22flv720%22%2C%22flv480%22%2C%22flv360%22%5D%2C%22support_description%22%3A%5B%22%E9%AB%98%E6%B8%85%201080P%2B%22%2C%22%E9%AB%98%E6%B8%85%201080P%22%2C%22%E9%AB%98%E6%B8%85%20720P%22%2C%22%E6%B8%85%E6%99%B0%20480P%22%2C%22%E6%B5%81%E7%95%85%20360P%22%5D%2C%22quality%22%3A32%2C%22video_codecid%22%3A7%2C%22video_project%22%3Atrue%2C%22fnver%22%3A0%2C%22fnval%22%3A16%2C%22dash%22%3A%7B%22video%22%3A%5B%7B%22id%22%3A16%2C%22base_url%22%3A%22http%3A%2F%2F58.243.177.135%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30015.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3D42OA30l6zhf_btPLBI8CGw%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A391965%2C%22codecid%22%3A7%7D%2C%7B%22id%22%3A32%2C%22base_url%22%3A%22http%3A%2F%2F60.12.119.69%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30032.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3Dx1acEg918HekzZ7feezBAA%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A878269%2C%22codecid%22%3A7%7D%2C%7B%22id%22%3A64%2C%22base_url%22%3A%22http%3A%2F%2F58.243.177.134%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30064.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3Dg2Ryt0_xwF-bQop6Bers1g%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A1947512%2C%22codecid%22%3A7%7D%2C%7B%22id%22%3A80%2C%22base_url%22%3A%22http%3A%2F%2F58.243.177.135%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30080.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3DCe4MJYd4Q8tb1zDiPZ2NPw%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A2920113%2C%22codecid%22%3A7%7D%2C%7B%22id%22%3A16%2C%22base_url%22%3A%22http%3A%2F%2F60.12.119.71%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30011.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3DtVLJ9Xy56D8zBIHQpeHnOA%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A289550%2C%22codecid%22%3A12%7D%2C%7B%22id%22%3A32%2C%22base_url%22%3A%22http%3A%2F%2F60.12.119.68%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30033.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3DU3bKyOYXHxJDPDsFyTSYRw%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A648003%2C%22codecid%22%3A12%7D%2C%7B%22id%22%3A64%2C%22base_url%22%3A%22http%3A%2F%2F60.12.119.69%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30066.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3DQmia_xv_261EEanMCMDLBg%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A1433063%2C%22codecid%22%3A12%7D%2C%7B%22id%22%3A80%2C%22base_url%22%3A%22http%3A%2F%2F60.12.119.70%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30077.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3D7KKLcfPoYOtggLt2B8OpSw%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A2147039%2C%22codecid%22%3A12%7D%2C%7B%22id%22%3A112%2C%22base_url%22%3A%22http%3A%2F%2Fupos-hz-mirrorwcsu.acgvideo.com%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30112.m4s%3Fe%3Dig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEuENvNC8aNEVEtEvE9IMvXBvE2ENvNCImNEVEIj0Y2J_aug859r1qXg8xNEVE5XREto8GuFGv2U7SuxI72X6fTr859IB_%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026oi%3D1699214834%5Cu0026platform%3Dandroid%5Cu0026gen%3Dplayurl%5Cu0026uipk%3D5%5Cu0026os%3Dwcsu%5Cu0026nbs%3D1%5Cu0026deadline%3D1550653142%5Cu0026upsig%3Db1a2c5c4587c9d62c62328fd5fbf5e5d%22%2C%22bandwidth%22%3A5628680%2C%22codecid%22%3A7%7D%5D%2C%22audio%22%3A%5B%7B%22id%22%3A30280%2C%22base_url%22%3A%22http%3A%2F%2F58.243.177.131%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30280.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3DfoKPdZpezm90iRFrxXyj5A%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A167107%2C%22codecid%22%3A0%7D%2C%7B%22id%22%3A30216%2C%22base_url%22%3A%22http%3A%2F%2F222.161.224.6%2Fupgcxcode%2F90%2F13%2F76731390%2F76731390-1-30216.m4s%3Fexpires%3D1550652900%5Cu0026platform%3Dandroid%5Cu0026ssig%3Dfd9cXg9GDLF8Ci-EvSTuXQ%5Cu0026oi%3D1699214834%5Cu0026hfa%3D2120103141%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3D8fae8885111d4e9bacbcdf70a3021572%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A67216%2C%22codecid%22%3A0%7D%5D%7D%7D&player_width=1920&player_height=1080&player_rotate=0&trackid=all_3.shylf-ai-recsys-120.1550645942519.77 - ) { - data class ThreePoint( - @SerializedName("dislike_reasons") - var dislikeReasons: List, - @SerializedName("feedbacks") - var feedbacks: List, - @SerializedName("watch_later") - var watchLater: Int // 1 - ) { - data class DislikeReason( - @SerializedName("id") - var id: Int, // 1 - @SerializedName("name") - var name: String // 不感兴趣 - ) - - data class Feedback( - @SerializedName("id") - var id: Int, // 4 - @SerializedName("name") - var name: String // 标题党/封面党 - ) - } - - data class PlayerArgs( - @SerializedName("aid") - var aid: Int, // 43804922 - @SerializedName("cid") - var cid: Int // 76731390 - ) - - data class Args( - @SerializedName("rid") - var rid: Int, // 17 - @SerializedName("rname") - var rname: String, // 单机游戏 - @SerializedName("tid") - var tid: Int, // 9264 - @SerializedName("tname") - var tname: String, // 宇宙 - @SerializedName("up_id") - var upId: Int, // 131565338 - @SerializedName("up_name") - var upName: String // 的夏游戏模拟 - ) - - data class AdInfo( - @SerializedName("ad_cb") - var adCb: String, // CMyzBBDInQwYl7+RAyAeKAEw6Ro46w5CHzE1NTA2NDU5NDI1MTlxMTcyYTIzYTU2YTE0NXE1NjFI97HNzZAtUgbmna3lt55aBua1meaxn2IG5Lit5Zu9aAFwAHiAgICA4ASAAQOIAQCSAQ4xMDEuNzEuMjQ1LjI0MpoBiwNhbGw6Y3BjX2Nyb3dkX3RhcmdldCxlY3BtOmRlZmF1bHQsY3BjVGFnRmlsdGVyOnVuZGVmaW5lZCxlbmhhbmNlQ3RyUUZhY3RvcjpkZWZhdWx0LGFkTWVjaGFuaXNtTW9uaXRvcjpvdGhlcixwbGF5cGFnZWN0cjpkaXNhYmxlLHVwX3JlY19mbG93X2NvbnRyb2w6dW5kZWZpbmVkLGJydXNoX2R1cGxpY2F0ZTpkZWZhdWx0LHBjdHJfY3BtOmNwbSxkZnhfc3BlY2lmaWNfcmF0aW86dW5kZWZpbmVkLHBjdHJfdjI6a2Fma2EsZHluYW1pY19mbG93X2NvbnRyb2w6c3BsaXQgdGhlIGZsb3cgYnkgbWlkLHBjdnI6ZGxkLGZyZXFMaW1pdDpkZWZhdWx0LHNtYWxsQ29uc3VtZVVuaXQ6ZnJlcUxpbWl0TG9vc2Usb3V0ZXJCZWF0SW5uZXI6ZW5hYmxlLG91dGVyUXVpdDpkZWZhdWx0LGZkc19ydHQ6ZGVmYXVsdKABHqgB4QSyASBXbHnmbpOszwTXdVHn7Ki/qhzsnkZKkYFNZgfpS815cLoBLmh0dHBzOi8vbS53ZWliby5jbi82MTkyODc3MjQyLzQzMzM1NDIxMjI4NzM3MTLCAYUBMzA3Ml8xNDI3Xzg0Nl83MjRfNDU3XzQ1MV80MzRfMzg1XzE3NF8xNTBfMTQ4XzE0OF8xNDhfMTQ4XzE0OF8xNDdfMTQ3XzE0N18xNDdfMTQ3XzE0N18xNDdfMTM5XzEzOV8xMzlfMTM5XzEzOV8xMzlfMTM5XzEzOV8xMzlfMTM5XzEzOMoBANIBANgBJuABgIyNngLoAYCMjZ4C8AEA+AEegAICiAIAkgLlAjE4MDIyNl8xNTUwNTM0OTIxLDE5NjEzNV8xNTUwNTM0OTMxLDc3NzA3XzE1NTA1MzQ5MzgsMjAwMzkyXzE1NTA1MzUxNDUsMTc2NzgwXzE1NTA1MzUxNTMsMTgwMjI1XzE1NTA1MzUxNjYsMjA0MDMzXzE1NTA1MzUyMzMsMjAyNDQ5XzE1NTA1MzUyMzMsNzc3MjNfMTU1MDUzNTIzNywyMDA0MTNfMTU1MDUzNTI0MywxMDE3MDNfMTU1MDUzNTczOCwyMDAxNDFfMTU1MDU5MTE1MSwxOTU3MzlfMTU1MDU5MTE1NywxNzY3NDhfMTU1MDYwMTU5OSwyMDA0MTFfMTU1MDYwMTYwMCwxNTE2NTJfMTU1MDYwMTYxMCwxNTE2NTBfMTU1MDYwMTczNiwyMDI0NDVfMTU1MDYwMTc1MCwyMDUyNjBfMTU1MDYxOTAyNiwyMDUyNjNfMTU1MDYxOTAyN5gCrqCjBqAC8qUHqALu/gSwAp8EuAIAwAIAyAIA0AIA2AIA4gISLCzmna3lt54t5LiK5Z+O5Yy6 - @SerializedName("card_index") - var cardIndex: Int, // 5 - @SerializedName("card_type") - var cardType: Int, // 3 - @SerializedName("client_ip") - var clientIp: String, // 101.71.245.242 - @SerializedName("cm_mark") - var cmMark: Int, // 1 - @SerializedName("creative_content") - var creativeContent: CreativeContent, - @SerializedName("creative_id") - var creativeId: Int, // 6578071 - @SerializedName("creative_type") - var creativeType: Int, // 2 - @SerializedName("extra") - var extra: Extra, - @SerializedName("index") - var index: Int, // 2 - @SerializedName("is_ad") - var isAd: Boolean, // true - @SerializedName("is_ad_loc") - var isAdLoc: Boolean, // true - @SerializedName("request_id") - var requestId: String, // 1550645942519q172a23a56a145q561 - @SerializedName("resource") - var resource: Int, // 1897 - @SerializedName("source") - var source: Int // 1899 - ) { - data class CreativeContent( - @SerializedName("description") - var description: String, // 恶搞·剪辑 - @SerializedName("image_md5") - var imageMd5: String, // 23f4d623b4348e86890411f29688fb58 - @SerializedName("image_url") - var imageUrl: String, // https://i0.hdslb.com/bfs/sycp/creative_img/201902/9097a17ff77a3dc03ea4b8841f46078f.jpg_640x400.jpg - @SerializedName("title") - var title: String, // 往老鼠洞里打氢气和氧气,场面瞬间失控 - @SerializedName("url") - var url: String // https://cm.bilibili.com/cm/api/fees/wise/redirect?ad_cb=CMyzBBDInQwYl7%2BRAyAeKAEw6Ro46w5CHzE1NTA2NDU5NDI1MTlxMTcyYTIzYTU2YTE0NXE1NjFI97HNzZAtUgbmna3lt55aBua1meaxn2IG5Lit5Zu9aAFwAHiAgICA4ASAAQOIAQCSAQ4xMDEuNzEuMjQ1LjI0MpoBiwNhbGw6Y3BjX2Nyb3dkX3RhcmdldCxlY3BtOmRlZmF1bHQsY3BjVGFnRmlsdGVyOnVuZGVmaW5lZCxlbmhhbmNlQ3RyUUZhY3RvcjpkZWZhdWx0LGFkTWVjaGFuaXNtTW9uaXRvcjpvdGhlcixwbGF5cGFnZWN0cjpkaXNhYmxlLHVwX3JlY19mbG93X2NvbnRyb2w6dW5kZWZpbmVkLGJydXNoX2R1cGxpY2F0ZTpkZWZhdWx0LHBjdHJfY3BtOmNwbSxkZnhfc3BlY2lmaWNfcmF0aW86dW5kZWZpbmVkLHBjdHJfdjI6a2Fma2EsZHluYW1pY19mbG93X2NvbnRyb2w6c3BsaXQgdGhlIGZsb3cgYnkgbWlkLHBjdnI6ZGxkLGZyZXFMaW1pdDpkZWZhdWx0LHNtYWxsQ29uc3VtZVVuaXQ6ZnJlcUxpbWl0TG9vc2Usb3V0ZXJCZWF0SW5uZXI6ZW5hYmxlLG91dGVyUXVpdDpkZWZhdWx0LGZkc19ydHQ6ZGVmYXVsdKABHqgB4QSyASBXbHnmbpOszwTXdVHn7Ki%2FqhzsnkZKkYFNZgfpS815cLoBLmh0dHBzOi8vbS53ZWliby5jbi82MTkyODc3MjQyLzQzMzM1NDIxMjI4NzM3MTLCAYUBMzA3Ml8xNDI3Xzg0Nl83MjRfNDU3XzQ1MV80MzRfMzg1XzE3NF8xNTBfMTQ4XzE0OF8xNDhfMTQ4XzE0OF8xNDdfMTQ3XzE0N18xNDdfMTQ3XzE0N18xNDdfMTM5XzEzOV8xMzlfMTM5XzEzOV8xMzlfMTM5XzEzOV8xMzlfMTM5XzEzOMoBANIBANgBJuABgIyNngLoAYCMjZ4C8AEA%2BAEegAICiAIAkgLlAjE4MDIyNl8xNTUwNTM0OTIxLDE5NjEzNV8xNTUwNTM0OTMxLDc3NzA3XzE1NTA1MzQ5MzgsMjAwMzkyXzE1NTA1MzUxNDUsMTc2NzgwXzE1NTA1MzUxNTMsMTgwMjI1XzE1NTA1MzUxNjYsMjA0MDMzXzE1NTA1MzUyMzMsMjAyNDQ5XzE1NTA1MzUyMzMsNzc3MjNfMTU1MDUzNTIzNywyMDA0MTNfMTU1MDUzNTI0MywxMDE3MDNfMTU1MDUzNTczOCwyMDAxNDFfMTU1MDU5MTE1MSwxOTU3MzlfMTU1MDU5MTE1NywxNzY3NDhfMTU1MDYwMTU5OSwyMDA0MTFfMTU1MDYwMTYwMCwxNTE2NTJfMTU1MDYwMTYxMCwxNTE2NTBfMTU1MDYwMTczNiwyMDI0NDVfMTU1MDYwMTc1MCwyMDUyNjBfMTU1MDYxOTAyNiwyMDUyNjNfMTU1MDYxOTAyN5gCrqCjBqAC8qUHqALu%2FgSwAp8EuAIAwAIAyAIA0AIA2AIA4gISLCzmna3lt54t5LiK5Z%2BO5Yy6 - ) - - data class Extra( - @SerializedName("card") - var card: Card, - @SerializedName("click_urls") - var clickUrls: List, - @SerializedName("download_whitelist") - var downloadWhitelist: List, - @SerializedName("open_whitelist") - var openWhitelist: List, - @SerializedName("preload_landingpage") - var preloadLandingpage: Int, // 0 - @SerializedName("report_time") - var reportTime: Int, // 2000 - @SerializedName("sales_type") - var salesType: Int, // 12 - @SerializedName("show_urls") - var showUrls: List, - @SerializedName("special_industry") - var specialIndustry: Boolean, // false - @SerializedName("special_industry_tips") - var specialIndustryTips: String, - @SerializedName("use_ad_web_v2") - var useAdWebV2: Boolean // true - ) { - data class Card( - @SerializedName("ad_tag") - var adTag: String, - @SerializedName("callup_url") - var callupUrl: String, // sinaweibo://cardlist?containerid=102803&luicode=10000404&lfid=jixinshengbo_9999_001 - @SerializedName("card_type") - var cardType: Int, // 3 - @SerializedName("covers") - var covers: List, - @SerializedName("desc") - var desc: String, // 恶搞·剪辑 - @SerializedName("jump_url") - var jumpUrl: String, // https://cm.bilibili.com/cm/api/fees/wise/redirect?ad_cb=CMyzBBDInQwYl7%2BRAyAeKAEw6Ro46w5CHzE1NTA2NDU5NDI1MTlxMTcyYTIzYTU2YTE0NXE1NjFI97HNzZAtUgbmna3lt55aBua1meaxn2IG5Lit5Zu9aAFwAHiAgICA4ASAAQOIAQCSAQ4xMDEuNzEuMjQ1LjI0MpoBiwNhbGw6Y3BjX2Nyb3dkX3RhcmdldCxlY3BtOmRlZmF1bHQsY3BjVGFnRmlsdGVyOnVuZGVmaW5lZCxlbmhhbmNlQ3RyUUZhY3RvcjpkZWZhdWx0LGFkTWVjaGFuaXNtTW9uaXRvcjpvdGhlcixwbGF5cGFnZWN0cjpkaXNhYmxlLHVwX3JlY19mbG93X2NvbnRyb2w6dW5kZWZpbmVkLGJydXNoX2R1cGxpY2F0ZTpkZWZhdWx0LHBjdHJfY3BtOmNwbSxkZnhfc3BlY2lmaWNfcmF0aW86dW5kZWZpbmVkLHBjdHJfdjI6a2Fma2EsZHluYW1pY19mbG93X2NvbnRyb2w6c3BsaXQgdGhlIGZsb3cgYnkgbWlkLHBjdnI6ZGxkLGZyZXFMaW1pdDpkZWZhdWx0LHNtYWxsQ29uc3VtZVVuaXQ6ZnJlcUxpbWl0TG9vc2Usb3V0ZXJCZWF0SW5uZXI6ZW5hYmxlLG91dGVyUXVpdDpkZWZhdWx0LGZkc19ydHQ6ZGVmYXVsdKABHqgB4QSyASBXbHnmbpOszwTXdVHn7Ki%2FqhzsnkZKkYFNZgfpS815cLoBLmh0dHBzOi8vbS53ZWliby5jbi82MTkyODc3MjQyLzQzMzM1NDIxMjI4NzM3MTLCAYUBMzA3Ml8xNDI3Xzg0Nl83MjRfNDU3XzQ1MV80MzRfMzg1XzE3NF8xNTBfMTQ4XzE0OF8xNDhfMTQ4XzE0OF8xNDdfMTQ3XzE0N18xNDdfMTQ3XzE0N18xNDdfMTM5XzEzOV8xMzlfMTM5XzEzOV8xMzlfMTM5XzEzOV8xMzlfMTM5XzEzOMoBANIBANgBJuABgIyNngLoAYCMjZ4C8AEA%2BAEegAICiAIAkgLlAjE4MDIyNl8xNTUwNTM0OTIxLDE5NjEzNV8xNTUwNTM0OTMxLDc3NzA3XzE1NTA1MzQ5MzgsMjAwMzkyXzE1NTA1MzUxNDUsMTc2NzgwXzE1NTA1MzUxNTMsMTgwMjI1XzE1NTA1MzUxNjYsMjA0MDMzXzE1NTA1MzUyMzMsMjAyNDQ5XzE1NTA1MzUyMzMsNzc3MjNfMTU1MDUzNTIzNywyMDA0MTNfMTU1MDUzNTI0MywxMDE3MDNfMTU1MDUzNTczOCwyMDAxNDFfMTU1MDU5MTE1MSwxOTU3MzlfMTU1MDU5MTE1NywxNzY3NDhfMTU1MDYwMTU5OSwyMDA0MTFfMTU1MDYwMTYwMCwxNTE2NTJfMTU1MDYwMTYxMCwxNTE2NTBfMTU1MDYwMTczNiwyMDI0NDVfMTU1MDYwMTc1MCwyMDUyNjBfMTU1MDYxOTAyNiwyMDUyNjNfMTU1MDYxOTAyN5gCrqCjBqAC8qUHqALu%2FgSwAp8EuAIAwAIAyAIA0AIA2AIA4gISLCzmna3lt54t5LiK5Z%2BO5Yy6 - @SerializedName("long_desc") - var longDesc: String, - @SerializedName("title") - var title: String // 往老鼠洞里打氢气和氧气,场面瞬间失控 - ) { - data class Cover( - @SerializedName("url") - var url: String // https://i0.hdslb.com/bfs/sycp/creative_img/201902/9097a17ff77a3dc03ea4b8841f46078f.jpg_640x400.jpg - ) - } - } - } - - data class ThreePointV2( - @SerializedName("reasons") - var reasons: List, - @SerializedName("subtitle") - var subtitle: String, // (选择后将减少相似内容推荐) - @SerializedName("title") - var title: String, // 不感兴趣 - @SerializedName("type") - var type: String // dislike - ) { - data class Reason( - @SerializedName("id") - var id: Int, // 1 - @SerializedName("name") - var name: String // 不感兴趣 - ) - } - - data class BannerItem( - @SerializedName("ad_cb") - var adCb: String, // CMDeARAAGOChASAAKAAwAzjABUIfMTU1MDY0NTk0MjUxNHExNzJhMjJhNTZhMTU5cTcxNkjysc3NkC1SBuadreW3nloG5rWZ5rGfYgbkuK3lm71oAXAAeICAgIAQgAEAiAGCJJIBDjEwMS43MS4yNDUuMjQymgGKA2FsbDpjcGNfY3Jvd2RfdGFyZ2V0LGVjcG06ZGVmYXVsdCxjcGNUYWdGaWx0ZXI6dW5kZWZpbmVkLGVuaGFuY2VDdHJRRmFjdG9yOmRlZmF1bHQsYWRNZWNoYW5pc21Nb25pdG9yOm90aGVyLHBsYXlwYWdlY3RyOmRpc2FibGUsdXBfcmVjX2Zsb3dfY29udHJvbDp1bmRlZmluZWQsYnJ1c2hfZHVwbGljYXRlOmRlZmF1bHQscGN0cl9jcG06Y3BtLGRmeF9zcGVjaWZpY19yYXRpbzp1bmRlZmluZWQscGN0cl92MjpkZnQsZHluYW1pY19mbG93X2NvbnRyb2w6c3BsaXQgdGhlIGZsb3cgYnkgbWlkLHBjdnI6ZGxkLGZyZXFMaW1pdDpkZWZhdWx0LHNtYWxsQ29uc3VtZVVuaXQ6ZnJlcUxpbWl0TG9vc2Usb3V0ZXJCZWF0SW5uZXI6ZGVmYXVsdCxvdXRlclF1aXQ6ZGVmYXVsdCxmZHNfcnR0OmRlZmF1bHSgAQCoAQCyASBzEMEnoPF8mLhSbbL8kmKEYNtD/f3W63yJX7yJ/ZmpN7oBQ2JpbGliaWxpOi8vZ2FtZV9jZW50ZXIvZGV0YWlsP2lkPTgwJnNvdXJjZUZyb209NzgyJnNvdXJjZVR5cGU9YWRQdXTCAQDKAQDSAQDYAQHgAQDoAQDwAQD4AQCAAgCIAgC4AgDAAqCsT8gCANACANgCAOICEiws5p2t5beeLeS4iuWfjuWMug== - @SerializedName("click_url") - var clickUrl: String, // https://ad-bili-data.biligame.com/api/mobile/clickBili?ad_plan_id=1670&mid=__MID__&os=0&idfa=__IDFA__&buvid=__BUVID__&android_id=43d7a1ebb6669597650e3ee417d9e7f5&imei=__IMEI__&mac=1035d532877200d6598f96118c2821e8&duid=__DUID__&ip=101.71.245.242&request_id=1550645942514q172a22a56a159q716&ts=__TS__&ua=Dalvik%252F2.1.0%2B%2528Linux%253B%2BU%253B%2BAndroid%2B6.0%253B%2BAndroid%2BSDK%2Bbuilt%2Bfor%2Bx86%2BBuild%252FMASTER%2529 - @SerializedName("client_ip") - var clientIp: String, // 101.71.245.242 - @SerializedName("cm_mark") - var cmMark: Int, // 0 - @SerializedName("creative_id") - var creativeId: Int, // 20704 - @SerializedName("extra") - var extra: Extra, - @SerializedName("hash") - var hash: String, // 036073dcc265f595ce2a0d331fe404c0 - @SerializedName("id") - var id: Int, // 229421 - @SerializedName("image") - var image: String, // http://i0.hdslb.com/bfs/archive/91318bfd6076f4c5fd59b945120f346eda43cc59.jpg - @SerializedName("index") - var index: Int, // 5 - @SerializedName("is_ad") - var isAd: Boolean, // true - @SerializedName("is_ad_loc") - var isAdLoc: Boolean, // true - @SerializedName("request_id") - var requestId: String, // 1550645942462 - @SerializedName("resource_id") - var resourceId: Int, // 631 - @SerializedName("server_type") - var serverType: Int, // 0 - @SerializedName("src_id") - var srcId: Int, // 704 - @SerializedName("title") - var title: String, // 还有哪些特别的过年习俗呢? - @SerializedName("uri") - var uri: String // https://www.bilibili.com/blackboard/topic/activity-Dp6imaUka.html - ) { - data class Extra( - @SerializedName("card") - var card: Card, - @SerializedName("click_urls") - var clickUrls: List, - @SerializedName("open_whitelist") - var openWhitelist: List, - @SerializedName("preload_landingpage") - var preloadLandingpage: Int, // 0 - @SerializedName("report_time") - var reportTime: Int, // 2000 - @SerializedName("sales_type") - var salesType: Int, // 31 - @SerializedName("show_urls") - var showUrls: List, - @SerializedName("special_industry") - var specialIndustry: Boolean, // false - @SerializedName("special_industry_tips") - var specialIndustryTips: String, - @SerializedName("use_ad_web_v2") - var useAdWebV2: Boolean // false - ) { - data class Card( - @SerializedName("ad_tag") - var adTag: String, - @SerializedName("button") - var button: Button, - @SerializedName("callup_url") - var callupUrl: String, - @SerializedName("card_type") - var cardType: Int, // 0 - @SerializedName("covers") - var covers: List, - @SerializedName("desc") - var desc: String, - @SerializedName("jump_url") - var jumpUrl: String, // bilibili://game_center/detail?id=80&sourceFrom=782&sourceType=adPut - @SerializedName("long_desc") - var longDesc: String, - @SerializedName("title") - var title: String - ) { - data class Cover( - @SerializedName("url") - var url: String // https://i0.hdslb.com/bfs/sycp/creative_img/201902/abd37b988b7f043a8aba3f173ef5c220.jpg - ) - - data class Button( - @SerializedName("dlsuc_callup_url") - var dlsucCallupUrl: String, - @SerializedName("jump_url") - var jumpUrl: String, // bilibili://game_center/detail?id=80&sourceFrom=782&sourceType=adPut - @SerializedName("report_urls") - var reportUrls: List, - @SerializedName("text") - var text: String, - @SerializedName("type") - var type: Int // 1 - ) - } - } - } - - data class RcmdReasonStyle( - @SerializedName("bg_color") - var bgColor: String, // #FFFB9E60 - @SerializedName("bg_style") - var bgStyle: Int, // 1 - @SerializedName("border_color") - var borderColor: String, // #FFFB9E60 - @SerializedName("text") - var text: String, // 已关注 - @SerializedName("text_color") - var textColor: String // #FFFFFFFF - ) - - data class DescButton( - @SerializedName("event") - var event: String, // channel_click - @SerializedName("text") - var text: String, // 单机游戏 · 宇宙 - @SerializedName("type") - var type: Int, // 1 - @SerializedName("uri") - var uri: String // bilibili://pegasus/channel/9264 - ) - } - - data class Config( - @SerializedName("autoplay_card") - var autoplayCard: Int, // 2 - @SerializedName("column") - var column: Int, // 2 - @SerializedName("feed_clean_abtest") - var feedCleanAbtest: Int // 0 - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/LikeResponse.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/LikeResponse.kt deleted file mode 100644 index d35753b..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/LikeResponse.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class LikeResponse( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - /** - * 取消点赞时 toast 为 "" - */ - @SerializedName("toast") - var toast: String // 点赞收到!视频可能推荐哦 - ) -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/Mine.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/Mine.kt deleted file mode 100644 index 5d9f34e..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/Mine.kt +++ /dev/null @@ -1,60 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class Mine( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("audio_type") - var audioType: Int, // 0 - @SerializedName("bcoin") - var bcoin: Int, // 5 - @SerializedName("coin") - var coin: Double, // 892.7 - @SerializedName("dynamic") - var `dynamic`: Int, // 8 - @SerializedName("face") - var face: String, // http://i0.hdslb.com/bfs/face/0434dccc0ec4de223e8ca374dea06a6e1e8eb471.jpg - @SerializedName("follower") - var follower: Int, // 512 - @SerializedName("following") - var following: Int, // 106 - @SerializedName("level") - var level: Int, // 5 - @SerializedName("mid") - var mid: Long, // 2866663 - @SerializedName("name") - var name: String, // hyx5020 - @SerializedName("new_followers") - var newFollowers: Int, // 0 - @SerializedName("official_verify") - var officialVerify: OfficialVerify, - @SerializedName("rank") - var rank: Int, // 10000 - @SerializedName("sex") - var sex: Int, // 0 - @SerializedName("show_creative") - var showCreative: Int, // 1 - @SerializedName("show_videoup") - var showVideoup: Int, // 1 - @SerializedName("silence") - var silence: Int, // 0 - @SerializedName("vip_type") - var vipType: Int // 2 - ) { - data class OfficialVerify( - @SerializedName("desc") - var desc: String, - @SerializedName("type") - var type: Int // -1 - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/MyInfo.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/MyInfo.kt deleted file mode 100644 index 361470a..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/MyInfo.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class MyInfo( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("birthday") - var birthday: String, // 1995-11-18 - @SerializedName("coins") - var coins: Int, // 1025 - @SerializedName("email_status") - var emailStatus: Int, // 0 - @SerializedName("face") - var face: String, // http://i1.hdslb.com/bfs/face/4f65e79399ad5a1bf3f877851b2f819d5870b494.jpg - @SerializedName("identification") - var identification: Int, // 1 - @SerializedName("level") - var level: Int, // 4 - @SerializedName("mid") - var mid: Long, // 20293030 - @SerializedName("name") - var name: String, // czp3009 - @SerializedName("official") - var official: Official, - @SerializedName("rank") - var rank: Int, // 10000 - @SerializedName("sex") - var sex: Int, // 0 - @SerializedName("sign") - var sign: String, - @SerializedName("silence") - var silence: Int, // 0 - @SerializedName("tel_status") - var telStatus: Int, // 1 - @SerializedName("vip") - var vip: Vip - ) { - data class Official( - @SerializedName("desc") - var desc: String, - @SerializedName("role") - var role: Int, // 0 - @SerializedName("title") - var title: String - ) - - data class Vip( - @SerializedName("due_date") - var dueDate: Long, // 0 - @SerializedName("status") - var status: Int, // 0 - @SerializedName("type") - var type: Int, // 0 - @SerializedName("vip_pay_type") - var vipPayType: Int // 0 - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/PopularPage.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/PopularPage.kt deleted file mode 100644 index 4394d88..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/PopularPage.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.JsonElement -import com.google.gson.annotations.SerializedName - -data class PopularPage( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("config") - var config: Config, - @SerializedName("data") - var `data`: List, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ver") - var ver: String // 1550674482 -) { - data class Data( - @SerializedName("args") - var args: JsonElement, // {} - @SerializedName("card_goto") - var cardGoto: String, // av - @SerializedName("card_type") - var cardType: String, // small_cover_v5 - @SerializedName("cover") - var cover: String, // http://i1.hdslb.com/bfs/archive/92c41f8fd16ccc7c9fb8ff4c302c8cd28f98500c.jpg - @SerializedName("cover_right_text_1") - var coverRightText1: String, // 2:22:47 - @SerializedName("from_type") - var fromType: String, // recommend - @SerializedName("goto") - var goto: String, // av - @SerializedName("idx") - var idx: Int, // 10 - @SerializedName("param") - var `param`: String, // 44139240 - @SerializedName("rcmd_reason_style") - var rcmdReasonStyle: RcmdReasonStyle, - @SerializedName("right_desc_1") - var rightDesc1: String, // Alessa0 - @SerializedName("right_desc_2") - var rightDesc2: String, // 17.5万观看 · 11小时前 - @SerializedName("three_point") - var threePoint: ThreePoint, - @SerializedName("three_point_v2") - var threePointV2: List, - @SerializedName("title") - var title: String, // 【莫璃】还愿-Devotion 实况解说 - @SerializedName("uri") - var uri: String // bilibili://video/44139240?page=1&player_preload=%7B%22cid%22%3A77299630%2C%22expire_time%22%3A1550678082%2C%22file_info%22%3A%7B%22116%22%3A%5B%7B%22timelength%22%3A1650317%2C%22filesize%22%3A1203029539%7D%5D%2C%2216%22%3A%5B%7B%22timelength%22%3A1650264%2C%22filesize%22%3A59700129%7D%5D%2C%2232%22%3A%5B%7B%22timelength%22%3A1650264%2C%22filesize%22%3A133510883%7D%5D%2C%2264%22%3A%5B%7B%22timelength%22%3A1650264%2C%22filesize%22%3A295466703%7D%5D%2C%2274%22%3A%5B%7B%22timelength%22%3A1650317%2C%22filesize%22%3A601916177%7D%5D%2C%2280%22%3A%5B%7B%22timelength%22%3A1650264%2C%22filesize%22%3A442710018%7D%5D%7D%2C%22support_quality%22%3A%5B116%2C74%2C80%2C64%2C32%2C16%5D%2C%22support_formats%22%3A%5B%22flv_p60%22%2C%22flv720_p60%22%2C%22flv%22%2C%22flv720%22%2C%22flv480%22%2C%22flv360%22%5D%2C%22support_description%22%3A%5B%22%E9%AB%98%E6%B8%85%201080P60%22%2C%22%E9%AB%98%E6%B8%85%20720P60%22%2C%22%E9%AB%98%E6%B8%85%201080P%22%2C%22%E9%AB%98%E6%B8%85%20720P%22%2C%22%E6%B8%85%E6%99%B0%20480P%22%2C%22%E6%B5%81%E7%95%85%20360P%22%5D%2C%22quality%22%3A32%2C%22video_codecid%22%3A7%2C%22video_project%22%3Atrue%2C%22fnver%22%3A0%2C%22fnval%22%3A16%2C%22dash%22%3A%7B%22video%22%3A%5B%7B%22id%22%3A16%2C%22base_url%22%3A%22http%3A%2F%2F112.13.92.201%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30015.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3DpB2mBK-uUt8J2FR7gpRkMw%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A380120%2C%22codecid%22%3A7%7D%2C%7B%22id%22%3A32%2C%22base_url%22%3A%22http%3A%2F%2F112.16.2.199%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30032.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3DQnAj8uehkASEqd0d4x2qng%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A722044%2C%22codecid%22%3A7%7D%2C%7B%22id%22%3A64%2C%22base_url%22%3A%22http%3A%2F%2F112.16.2.200%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30064.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3DQrLc5Upez1bBgiBKy18EAA%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A967572%2C%22codecid%22%3A7%7D%2C%7B%22id%22%3A80%2C%22base_url%22%3A%22http%3A%2F%2F112.13.92.209%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30080.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3D_mTir3zLWUP6l1IkebdNxA%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A1901584%2C%22codecid%22%3A7%7D%2C%7B%22id%22%3A16%2C%22base_url%22%3A%22http%3A%2F%2F112.16.2.195%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30011.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3DC0KJJqQGAv_ZnGPvLFCxKA%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A289408%2C%22codecid%22%3A12%7D%2C%7B%22id%22%3A32%2C%22base_url%22%3A%22http%3A%2F%2F112.16.2.197%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30033.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3D7qlxqk9UW65zMM87EROiTQ%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A647221%2C%22codecid%22%3A12%7D%2C%7B%22id%22%3A64%2C%22base_url%22%3A%22http%3A%2F%2F112.16.2.195%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30066.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3DESc65T0K8um6aFJwFT0ATg%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A1432336%2C%22codecid%22%3A12%7D%2C%7B%22id%22%3A80%2C%22base_url%22%3A%22http%3A%2F%2F112.16.2.196%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30077.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3DmxkPp_P0Z4p665jFbM6Yeg%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A2146129%2C%22codecid%22%3A12%7D%5D%2C%22audio%22%3A%5B%7B%22id%22%3A30280%2C%22base_url%22%3A%22http%3A%2F%2F112.16.2.202%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30280.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3DFSfFHiKsuIi26dSiVD1R1A%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A258739%2C%22codecid%22%3A0%7D%2C%7B%22id%22%3A30216%2C%22base_url%22%3A%22http%3A%2F%2F117.149.37.134%2Fupgcxcode%2F30%2F96%2F77299630%2F77299630-1-30216.m4s%3Fexpires%3D1550681400%5Cu0026platform%3Dandroid%5Cu0026ssig%3DMkkmNF2KLHxp826xbglC7w%5Cu0026oi%3D3670888805%5Cu0026hfa%3D2120131681%5Cu0026hfb%3DNzUxMjI5MWJlMDBjMDY0YTQxNjFjMTJiYWE0MjEwYmQ%3D%5Cu0026trid%3Ddfa70793caa4422581b4291f4a4f9a0d%5Cu0026nfc%3D1%22%2C%22bandwidth%22%3A67093%2C%22codecid%22%3A0%7D%5D%7D%7D&player_width=1920&player_height=1080&player_rotate=0 - ) { - data class ThreePoint( - @SerializedName("watch_later") - var watchLater: Int // 1 - ) - - data class ThreePointV2( - @SerializedName("title") - var title: String, // 添加至稍后再看 - @SerializedName("type") - var type: String // watch_later - ) - - data class RcmdReasonStyle( - @SerializedName("bg_color") - var bgColor: String, // #FFFB9E60 - @SerializedName("bg_style") - var bgStyle: Int, // 1 - @SerializedName("border_color") - var borderColor: String, // #FFFB9E60 - @SerializedName("text") - var text: String, // 新 - @SerializedName("text_color") - var textColor: String // #FFFFFFFF - ) - } - - data class Config( - @SerializedName("bottom_text") - var bottomText: String, // 已经到达热门的尽头惹,关于热门 - @SerializedName("bottom_text_cover") - var bottomTextCover: String, // http://i0.hdslb.com/bfs/archive/10814950191d33ba6eb6f29439e27399c3eeee37.png - @SerializedName("bottom_text_url") - var bottomTextUrl: String, // https://www.bilibili.com/blackboard/activity-RKWxGjjMb.html - @SerializedName("item_title") - var itemTitle: String // 当前热门 - ) -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchArticleResult.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchArticleResult.kt deleted file mode 100644 index 26163a7..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchArticleResult.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class SearchArticleResult( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("items") - var items: List, - @SerializedName("pages") - var pages: Int, // 50 - @SerializedName("total") - var total: Int, // 0 - @SerializedName("trackid") - var trackid: String // 2251647613743955310 - ) { - data class Item( - @SerializedName("badge") - var badge: String, // 专栏 - @SerializedName("desc") - var desc: String, // 今天来和大家说下《刀剑神域3》第19集的先行图剧情,与其说是第19集,确切的讲应该是18.5集,根据先行图来看,这一集是前面的合集,主要讲的是桐人和尤吉欧的经历。在第18集结尾,桐人不小心说出了赛鲁卡的名字,导致爱丽丝记忆发生了错乱,隐约想起了自己的妹妹,而接下来就是桐人会和爱丽丝说关于她的事了,而所说的方式根据先行图来看事回忆杀方式。下面就简单和大家说下官方给出的先行图。先行图01:a姐植入记忆水晶桐人既然要告诉爱丽丝真相,也会给她说这一切的元凶就是最高祭师a姐,从上图先行图可以看出,这是a姐 - @SerializedName("goto") - var goto: String, // article - @SerializedName("id") - var id: Long, // 2052980 - @SerializedName("image_urls") - var imageUrls: List, - @SerializedName("like") - var like: Int, // 116 - @SerializedName("mid") - var mid: Int, // 12043763 - @SerializedName("name") - var name: String, // 老白与动漫 - @SerializedName("param") - var `param`: String, // 2052980 - @SerializedName("play") - var play: Int, // 19101 - @SerializedName("reply") - var reply: Int, // 82 - @SerializedName("template_id") - var templateId: Int, // 3 - @SerializedName("title") - var title: String, // 刀剑神域3第19集先行:桐人告诉爱丽丝真相,又是回忆杀剧情! - @SerializedName("uri") - var uri: String, // bilibili://article/2052980 - @SerializedName("view") - var view: Int // 19101 - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchBangumiResult.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchBangumiResult.kt deleted file mode 100644 index 65f7687..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchBangumiResult.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class SearchBangumiResult( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("items") - var items: List, - @SerializedName("pages") - var pages: Int, // 1 - @SerializedName("total") - var total: Int, // 1 - @SerializedName("trackid") - var trackid: String // 1357843021891149439 - ) { - data class Item( - @SerializedName("area") - var area: String, // 日本 - @SerializedName("badge") - var badge: String, // 番剧 - @SerializedName("badges") - var badges: List, - @SerializedName("cover") - var cover: String, // https://i0.hdslb.com/bfs/bangumi/4d9f43eb3dba572797f8915f8f28efce9e58d756.jpg - @SerializedName("cv") - var cv: String, // 桐人(桐谷和人):松冈祯丞亚丝娜(结城明日奈):户松遥爱丽丝:茅野爱衣尤吉欧:岛崎信长赛鲁卡:前田佳织里罗妮耶·亚拉贝尔:近藤玲奈蒂洁·修特利尼:石原夏织神代凛子:小林沙苗菊冈诚二郎:森川智之莱欧斯·安提诺斯:岩濑周平温贝尔·吉泽克:木岛隆一索尔狄丽娜·塞路尔特:潘惠美沃罗·利凡玎:村田太志诗乃(朝田诗乃):泽城美雪 强尼·布莱克(金本敦):逢坂良太 西莉卡(绫野珪子):日高里菜 莉兹贝特(筱崎里香):高垣彩阳 - @SerializedName("episodes") - var episodes: List, - @SerializedName("goto") - var goto: String, // bangumi - @SerializedName("is_atten") - var isAtten: Int, // 1 - @SerializedName("is_selection") - var isSelection: Int, // 1 - @SerializedName("label") - var label: String, // 小说改/热血/奇幻/战斗/励志 - @SerializedName("media_type") - var mediaType: Int, // 1 - @SerializedName("param") - var `param`: String, // 130412 - @SerializedName("ptime") - var ptime: Int, // 1538841600 - @SerializedName("rating") - var rating: Double, // 9.2 - @SerializedName("season_id") - var seasonId: Int, // 25510 - @SerializedName("season_type") - var seasonType: Int, // 1 - @SerializedName("season_type_name") - var seasonTypeName: String, // 番剧 - @SerializedName("staff") - var staff: String, // 原作:川原砾原作插画 / 角色设计草案:abec导演:小野学助理导演:佐久间贵史角色设计:足立慎吾、铃木豪、西口智也总作画监督:铃木豪、西口智也动作作画监督:菅野芳弘、竹内哲也美术导演:小川友佳子、渡边佳人美术设定:森冈贤一、谷内优穗色彩设计:中野尚美CG导演:云藤隆太音响导演:岩浪美和效果:小山恭正音响制作:ソニルード音乐:梶浦由记制片:EGG FIRM、Straight Edge制作:A-1 Pictures - @SerializedName("style") - var style: String, // 小说改/热血/奇幻/战斗/励志 - @SerializedName("title") - var title: String, // 刀剑神域 Alicization - @SerializedName("uri") - var uri: String, // https://www.bilibili.com/bangumi/play/ss25510/ - @SerializedName("vote") - var vote: Int // 48497 - ) { - data class Badge( - @SerializedName("bg_color") - var bgColor: String, // #FB7299 - @SerializedName("bg_color_night") - var bgColorNight: String, // #BB5B76 - @SerializedName("bg_style") - var bgStyle: Int, // 1 - @SerializedName("border_color") - var borderColor: String, // #FB7299 - @SerializedName("border_color_night") - var borderColorNight: String, // #BB5B76 - @SerializedName("text") - var text: String, // 会员抢先 - @SerializedName("text_color") - var textColor: String, // #FFFFFF - @SerializedName("text_color_night") - var textColorNight: String // #E5E5E5 - ) - - data class Episode( - @SerializedName("index") - var index: String, // 21 - @SerializedName("param") - var `param`: String, // 250557 - @SerializedName("uri") - var uri: String // https://www.bilibili.com/bangumi/play/ep250557 - ) - } - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchDefaultWords.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchDefaultWords.kt deleted file mode 100644 index 4a0842c..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchDefaultWords.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class SearchDefaultWords( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("param") - var `param`: String, // 5157193909505109430 - @SerializedName("show") - var show: String, // 如果绝地求生也能滑铲 - @SerializedName("trackid") - var trackid: String, // 14016083035920227490 - @SerializedName("word") - var word: String // av46169875 - ) -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchHot.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchHot.kt deleted file mode 100644 index 9d814bd..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchHot.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class SearchHot( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("list") - var list: List, - @SerializedName("trackid") - var trackid: String // 3482080616107297898 - ) { - data class Hot( - @SerializedName("keyword") - var keyword: String, // 凹凸世界 - @SerializedName("name_type") - var nameType: String, - @SerializedName("status") - var status: String - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchLiveResult.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchLiveResult.kt deleted file mode 100644 index fde2772..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchLiveResult.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class SearchLiveResult( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("live_master") - var liveMaster: LiveMaster, - @SerializedName("live_room") - var liveRoom: LiveRoom, - @SerializedName("pages") - var pages: Int, // 3 - @SerializedName("total") - var total: Int, // 0 - @SerializedName("trackid") - var trackid: String // 14587616663833842975 - ) { - data class LiveRoom( - @SerializedName("items") - var items: List, - @SerializedName("pages") - var pages: Int, // 3 - @SerializedName("total") - var total: Int, // 57 - @SerializedName("trackid") - var trackid: String - ) { - data class Item( - @SerializedName("area_v2_name") - var areaV2Name: String, // 300英雄 - @SerializedName("attentions") - var attentions: Int, // 2 - @SerializedName("badge") - var badge: String, // 直播 - @SerializedName("cover") - var cover: String, // https://i0.hdslb.com/bfs/live/16181996f2260024f861db58d0d3dea2dd390930.jpg - @SerializedName("goto") - var goto: String, // live - @SerializedName("live_status") - var liveStatus: Int, // 2 - @SerializedName("mid") - var mid: Long, // 82542745 - @SerializedName("name") - var name: String, // SAO刀剑神域丶 - @SerializedName("online") - var online: Int, // 7 - @SerializedName("param") - var `param`: String, // 3387258 - @SerializedName("region") - var region: Int, // 4 - @SerializedName("roomid") - var roomid: Long, // 3387258 - @SerializedName("tags") - var tags: String, // 点点关注 - @SerializedName("title") - var title: String, // SAO刀剑神域丶的直播间 - @SerializedName("type") - var type: String, // live_room - @SerializedName("uri") - var uri: String // bilibili://live/3387258?broadcast_type=0 - ) - } - - data class LiveMaster( - @SerializedName("pages") - var pages: Int, // 0 - @SerializedName("total") - var total: Int, // 0 - @SerializedName("trackid") - var trackid: String - ) - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchMovieResult.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchMovieResult.kt deleted file mode 100644 index 026b5ca..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchMovieResult.kt +++ /dev/null @@ -1,92 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.annotations.SerializedName - -data class SearchMovieResult( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("items") - var items: List, - @SerializedName("pages") - var pages: Int, // 1 - @SerializedName("total") - var total: Int, // 2 - @SerializedName("trackid") - var trackid: String // 11415000413319714311 - ) { - data class Item( - @SerializedName("area") - var area: String, // 日本 - @SerializedName("badge") - var badge: String, // 电影 - /** - * badge 的特殊样式 - */ - @SerializedName("badges") - var badges: List>, - @SerializedName("cover") - var cover: String, // https://i0.hdslb.com/bfs/bangumi/aef914fac9edfa518c4df9a82d5d3d0cba08a451.jpg - /** - * 类型为 纪录片 时没有 cv, 其他一些字段同理 - */ - @SerializedName("cv") - var cv: String?, // 曹旭鹏、阎萌萌、碧涓、惠霖、梦娇 - /** - * 有些纪录片有分集, 有些没有 - */ - @SerializedName("episodes") - var episodes: List?, - @SerializedName("goto") - var goto: String, // movie - /** - * 一些纪录片没有 label, 其他一些字段同理 - */ - @SerializedName("label") - var label: String?, // 演员:曹旭鹏、阎萌萌、碧涓、惠霖、梦娇 - /** - * 2 为剧场版动画, 3 为纪录片 - */ - @SerializedName("media_type") - var mediaType: Int, // 2 - @SerializedName("param") - var `param`: String, // 115472 - @SerializedName("ptime") - var ptime: Long, // 1505404800 - @SerializedName("rating") - var rating: Double, // 5.8 - @SerializedName("season_id") - var seasonId: Int, // 12767 - @SerializedName("season_type") - var seasonType: Int, // 2 - @SerializedName("season_type_name") - var seasonTypeName: String, // 电影 - @SerializedName("staff") - var staff: String?, // 导演:伊藤智彦编剧:川原砾 - @SerializedName("style") - var style: String, // 科幻/动画 - @SerializedName("title") - var title: String, // 刀剑神域:序列之争(中文) - @SerializedName("uri") - var uri: String, // https://www.bilibili.com/bangumi/play/ss12767/ - @SerializedName("vote") - var vote: Int? // 581 - ) { - data class Episode( - @SerializedName("index") - var index: String, // 4 - @SerializedName("param") - var `param`: String, // 250006 - @SerializedName("uri") - var uri: String // https://www.bilibili.com/bangumi/play/ep250006 - ) - } - } -} diff --git a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchResult.kt b/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchResult.kt deleted file mode 100644 index faadb80..0000000 --- a/src/main/kotlin/com/hiczp/bilibili/api/app/model/SearchResult.kt +++ /dev/null @@ -1,186 +0,0 @@ -package com.hiczp.bilibili.api.app.model - -import com.google.gson.JsonElement -import com.google.gson.annotations.SerializedName - -data class SearchResult( - @SerializedName("code") - var code: Int, // 0 - @SerializedName("data") - var `data`: Data, - @SerializedName("message") - var message: String, // 0 - @SerializedName("ttl") - var ttl: Int // 1 -) { - data class Data( - @SerializedName("array") - var array: Int, // 1 - @SerializedName("attribute") - var attribute: Int, // 1 - @SerializedName("item") - var item: List, - @SerializedName("items") - var items: JsonElement, - @SerializedName("nav") - var nav: List