2019-02-15 18:14:27 +08:00
|
|
|
# Bilibili API JVM 调用库
|
|
|
|
该项目提供 Bilibili API 的 JVM 调用, 协议来自 Bilibili Android APP 的逆向工程以及截包分析.
|
2017-11-07 16:48:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
# 技术说明
|
|
|
|
`BilibiliClient` 类表示一个模拟的客户端, 实例化此类即表示打开了 Bilibili APP.
|
2019-02-20 14:55:07 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
所有调用从这个类开始, 包括登陆以及访问其他各种 API.
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
使用协程来实现异步, 由于 [kotlin coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) 为编译器实现, 因此并非所有 JVM 语言都能正确调用 `suspend` 方法.
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
本项目尽可能的兼容其他 JVM 语言和 Android, 不要问, 问就没测试过.
|
|
|
|
|
|
|
|
`BilibiliClient` 实例化时会记录一些信息, 例如初始化的事件, 用于更逼真的模拟真实客户端发送的请求. 因此请不要每次都实例化一个新的 `BilibiliClient` 实例, 而应该保存其引用.
|
|
|
|
|
|
|
|
一个客户端下各种不同类型的 API (代理类)都是惰性初始化的, 并且只初始化一次, 因此不需要保存 API 的引用, 例如以下代码是被推荐的:
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
```kotlin
|
|
|
|
runBlocking {
|
|
|
|
val bilibiliClient = BilibiliClient().apply {
|
|
|
|
login(username, password)
|
2019-02-20 00:05:53 +08:00
|
|
|
}
|
2019-02-21 18:59:53 +08:00
|
|
|
val myInfo = bilibiliClient.appAPI.myInfo().await()
|
|
|
|
val reply = bilibiliClient.mainAPI.reply(oid = 44154463).await()
|
|
|
|
}
|
|
|
|
```
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
如果一个请求的返回内容中的 `code`(code 是 BODY 的内容, 并非 HttpStatus) 不为 0, 将抛出异常 `BilibiliApiException`, 通过以下代码来获取服务器原始返回的 `code`:
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
```kotlin
|
|
|
|
val code = bilibiliApiException.commonResponse.code
|
|
|
|
```
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
一个错误返回的原始 `JSON` 如下所示:
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
```json
|
|
|
|
{
|
|
|
|
"code": -629,
|
|
|
|
"message": "用户名与密码不匹配",
|
|
|
|
"ts": 1550730464
|
|
|
|
}
|
|
|
|
```
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
每种不同的 API 在错误时返回的 `code` 丰富多彩(确信), 可能是正数也可能是负数, 可能上万也可能是个位数, 不要问, 问就是你菜.
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
# 登录和登出
|
|
|
|
(Bilibili oauth2 v3)
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
登陆和登出均为异步方法, 需要在协程上下文中执行.
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-24 21:26:49 +08:00
|
|
|
如果所使用的语言无法正确调用 `suspend` 方法, 可以使用 `loginFuture` 方法来替代, 它会返回一个 Java8 `CompletableFuture`.
|
|
|
|
|
|
|
|
`logoutFuture` 同理.
|
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
```kotlin
|
|
|
|
runBlocking {
|
|
|
|
BilibiliClient().run {
|
|
|
|
login(username, password)
|
|
|
|
logout()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
`login` 方法返回一个 `LoginResponse` 实例, 下次可以直接赋值到没有登陆的 `BilibiliClient` 实例中来恢复登陆状态.
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
```kotlin
|
|
|
|
BilibiliClient().apply {
|
|
|
|
this.loginResponse = loginResponse
|
|
|
|
}
|
|
|
|
```
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
`LoginResponse` 继承 `Serializable`, 可被序列化(JVM 序列化).
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
可能的错误返回有两种:
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
-629 用户名与密码不匹配
|
|
|
|
-105 验证码错误
|
2019-02-20 18:24:47 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
如果仅使用用户名与密码进行登陆并且得到了 `-105` 的结果, 那么说明需要验证码(通常是由于多次错误的登陆尝试导致的).
|
2019-02-20 18:24:47 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
原始返回如下所示
|
2019-02-20 18:24:47 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
{"ts":1550569982,"code":-105,"data":{"url":"https://passport.bilibili.com/register/verification.html?success=1>=b6e5b7fad7ecd37f465838689732e788&challenge=9a67afa4d42ede71a93aeaaa54a4b6fe&ct=1&hash=105af2e7cc6ea829c4a95205f2371dc5"},"message":"验证码错误!"}
|
2019-02-20 14:55:07 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
自行访问 `commonResponse.data.obj.url.string` 打开一个极验弹窗, 完成滑动验证码后再次调用登陆接口:
|
2019-02-20 14:55:07 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
```kotlin
|
|
|
|
login(username, password, challenge, secCode, validate)
|
|
|
|
```
|
2019-02-20 14:55:07 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
`challenge` 为本次极验的唯一标识(在一开始给出的 url 中)
|
2019-02-20 14:55:07 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
`validate` 为极验返回值
|
2019-02-20 18:24:47 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
`secCode` 为 `"$validate|jordan"`
|
|
|
|
|
|
|
|
(注意, 极验会根据滑动的轨迹来识别人机, 所以要为最终用户打开一个 WebView 来进行真人操作而不能自动完成. 极验最终返回的是一个 jsonp, 里面包含以上三个参数, 详见极验接入文档).
|
2019-02-20 00:05:53 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
注意, `BilibiliClient` 不能严格保证线程安全, 如果在登出的同时进行登录操作可能引发错误.
|
|
|
|
|
|
|
|
登陆后, 可以访问全部 API.
|
2019-02-21 00:09:25 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
# 访问 API
|
|
|
|
通常的 API 访问是这样的
|
2019-02-21 00:09:25 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
```kotlin
|
|
|
|
val myInfo = bilibiliClient.appAPI.myInfo().await()
|
|
|
|
```
|
2019-02-21 00:09:25 +08:00
|
|
|
|
2019-02-21 18:59:53 +08:00
|
|
|
不要问文档, 用自动补全(心)来感受.
|
2018-03-02 16:31:44 +08:00
|
|
|
|
2017-11-07 16:48:53 +08:00
|
|
|
# License
|
|
|
|
GPL V3
|