mirror of
https://github.com/czp3009/bilibili-api.git
synced 2025-02-19 20:50:28 +08:00
完成登陆过程中会访问的 API
This commit is contained in:
parent
e083859b1a
commit
eb588f5798
20
README.md
20
README.md
@ -43,10 +43,17 @@ https://passport.bilibili.com
|
||||
|
||||
登陆后, 可以访问全部 API.
|
||||
|
||||
# message
|
||||
https://message.bilibili.com
|
||||
|
||||
BilibiliClient().messageAPI
|
||||
|
||||
消息通知有关的接口.
|
||||
|
||||
# app
|
||||
https://app.bilibili.com
|
||||
|
||||
BilibiliClient().appAPI()
|
||||
BilibiliClient().appAPI
|
||||
|
||||
为 app 提供通用接口, 例如获取个人信息. 完整示例如下
|
||||
|
||||
@ -54,15 +61,16 @@ https://app.bilibili.com
|
||||
val bilibiliClient = BilibiliClient().apply {
|
||||
login(username, password)
|
||||
}
|
||||
val myInfo = bilibiliClient.appAPI().myInfo().await()
|
||||
val myInfo = bilibiliClient.appAPI.myInfo().await()
|
||||
println(myInfo)
|
||||
}
|
||||
|
||||
# 主站
|
||||
//TODO
|
||||
# av
|
||||
https://api.vc.bilibili.com
|
||||
|
||||
# 直播站
|
||||
//TODO
|
||||
BilibiliClient().vcAPI
|
||||
|
||||
小视频有关的接口.
|
||||
|
||||
# License
|
||||
GPL V3
|
||||
|
@ -5,17 +5,27 @@ package com.hiczp.bilibili.api
|
||||
*/
|
||||
object BaseUrl {
|
||||
/**
|
||||
* passport 站, 用于登录
|
||||
* 用户鉴权
|
||||
*/
|
||||
const val passport = "https://passport.bilibili.com"
|
||||
|
||||
/**
|
||||
* 消息
|
||||
*/
|
||||
const val message = "https://message.bilibili.com"
|
||||
|
||||
/**
|
||||
* 提供通用功能, 例如获取用户信息
|
||||
*/
|
||||
const val app = "https://app.bilibili.com"
|
||||
|
||||
/**
|
||||
* 直播站
|
||||
* 小视频
|
||||
*/
|
||||
const val vc = "https://api.vc.bilibili.com"
|
||||
|
||||
/**
|
||||
* 直播
|
||||
*/
|
||||
const val live = "https://api.live.bilibili.com"
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.hiczp.bilibili.api
|
||||
|
||||
import com.hiczp.bilibili.api.app.AppAPI
|
||||
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.retrofit.ParamType
|
||||
@ -9,8 +10,8 @@ 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 mu.KotlinLogging
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
@ -18,12 +19,11 @@ 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
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
/**
|
||||
* 此类表示一个模拟的 Bilibili 客户端(Android), 所有调用由此开始.
|
||||
* 多个 BilibiliClient 实例之间不共享登陆状态.
|
||||
@ -58,8 +58,34 @@ class BilibiliClient(
|
||||
get() = loginResponse != null
|
||||
|
||||
//快捷方式
|
||||
val userId get() = loginResponse?.userId
|
||||
val token get() = loginResponse?.token
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val userId
|
||||
get() = loginResponse?.userId
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val token
|
||||
get() = loginResponse?.token
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private val defaultCommonHeaderInterceptor = CommonHeaderInterceptor(
|
||||
"Display-ID" to { "${billingClientProperties.buildVersionId}-$initTime" },
|
||||
"Buvid" to { billingClientProperties.buildVersionId },
|
||||
"User-Agent" to { "Mozilla/5.0 BiliDroid/5.37.0 (bbcallen@gmail.com)" },
|
||||
"Device-ID" to { billingClientProperties.hardwareId }
|
||||
)
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private val defaultCommonParamArray = arrayOf(
|
||||
"access_key" to { token },
|
||||
"appkey" to { billingClientProperties.appKey },
|
||||
"build" to { billingClientProperties.build },
|
||||
"channel" to { billingClientProperties.channel },
|
||||
"mobi_app" to { billingClientProperties.platform },
|
||||
"platform" to { billingClientProperties.platform },
|
||||
"ts" to { Instant.now().epochSecond.toString() }
|
||||
)
|
||||
|
||||
private val defaultQuerySignInterceptor = SortAndSignInterceptor(ParamType.QUERY, billingClientProperties.appSecret)
|
||||
private val defaultFormSignInterceptor = SortAndSignInterceptor(ParamType.FORM_URL_ENCODED, billingClientProperties.appSecret)
|
||||
|
||||
/**
|
||||
* 用户鉴权相关的接口
|
||||
@ -67,12 +93,7 @@ class BilibiliClient(
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val passportAPI by lazy {
|
||||
createAPI<PassportAPI>(BaseUrl.passport, logLevel,
|
||||
CommonHeaderInterceptor(
|
||||
"Display-ID" to { "${billingClientProperties.buildVersionId}-$initTime" },
|
||||
"Buvid" to { billingClientProperties.buildVersionId },
|
||||
"User-Agent" to { "Mozilla/5.0 BiliDroid/5.37.0 (bbcallen@gmail.com)" },
|
||||
"Device-ID" to { billingClientProperties.hardwareId }
|
||||
),
|
||||
defaultCommonHeaderInterceptor,
|
||||
CommonParamInterceptor(ParamType.FORM_URL_ENCODED,
|
||||
"appkey" to { billingClientProperties.appKey },
|
||||
"build" to { billingClientProperties.build },
|
||||
@ -81,7 +102,22 @@ class BilibiliClient(
|
||||
"platform" to { billingClientProperties.platform },
|
||||
"ts" to { Instant.now().epochSecond.toString() }
|
||||
),
|
||||
SortAndSignInterceptor(ParamType.FORM_URL_ENCODED, billingClientProperties.appSecret)
|
||||
defaultFormSignInterceptor
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息通知有关的接口
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val messageAPI by lazy {
|
||||
createAPI<MessageAPI>(BaseUrl.message, logLevel,
|
||||
defaultCommonHeaderInterceptor,
|
||||
CommonParamInterceptor(ParamType.QUERY, *defaultCommonParamArray,
|
||||
"actionKey" to { "appkey" },
|
||||
"has_up" to { "1" }
|
||||
),
|
||||
defaultQuerySignInterceptor
|
||||
)
|
||||
}
|
||||
|
||||
@ -91,22 +127,28 @@ class BilibiliClient(
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val appAPI by lazy {
|
||||
createAPI<AppAPI>(BaseUrl.app, logLevel,
|
||||
CommonHeaderInterceptor(
|
||||
"Display-ID" to { "${billingClientProperties.buildVersionId}-$initTime" },
|
||||
"Buvid" to { billingClientProperties.buildVersionId },
|
||||
"User-Agent" to { "Mozilla/5.0 BiliDroid/5.37.0 (bbcallen@gmail.com)" },
|
||||
"Device-ID" to { billingClientProperties.hardwareId }
|
||||
defaultCommonHeaderInterceptor,
|
||||
CommonParamInterceptor(ParamType.QUERY, *defaultCommonParamArray),
|
||||
defaultQuerySignInterceptor
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 小视频相关接口
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val vcAPI by lazy {
|
||||
createAPI<VcAPI>(BaseUrl.vc, logLevel,
|
||||
defaultCommonHeaderInterceptor,
|
||||
CommonParamInterceptor(ParamType.QUERY, *defaultCommonParamArray,
|
||||
"_device" to { billingClientProperties.platform },
|
||||
"_hwid" to { billingClientProperties.hardwareId },
|
||||
"src" to { billingClientProperties.channel },
|
||||
"trace_id" to { generateTraceId() },
|
||||
"uid" to { userId?.toString() },
|
||||
"version" to { billingClientProperties.version }
|
||||
),
|
||||
CommonParamInterceptor(ParamType.QUERY,
|
||||
"access_key" to { token },
|
||||
"appkey" to { billingClientProperties.appKey },
|
||||
"build" to { billingClientProperties.build },
|
||||
"channel" to { billingClientProperties.channel },
|
||||
"mobi_app" to { billingClientProperties.platform },
|
||||
"platform" to { billingClientProperties.platform },
|
||||
"ts" to { Instant.now().epochSecond.toString() }
|
||||
),
|
||||
SortAndSignInterceptor(ParamType.QUERY, billingClientProperties.appSecret)
|
||||
defaultQuerySignInterceptor
|
||||
)
|
||||
}
|
||||
|
||||
@ -164,6 +206,11 @@ class BilibiliClient(
|
||||
passportAPI.revoke(cookieMap, response.token).await()
|
||||
loginResponse = null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val traceIdFormat = SimpleDateFormat("yyyyMMddHHmm000ss")
|
||||
private fun generateTraceId() = traceIdFormat.format(Date())
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
|
@ -1,12 +1,60 @@
|
||||
package com.hiczp.bilibili.api.app
|
||||
|
||||
import com.hiczp.bilibili.api.app.model.IndexPage
|
||||
import com.hiczp.bilibili.api.app.model.Mine
|
||||
import com.hiczp.bilibili.api.app.model.MyInfo
|
||||
import com.hiczp.bilibili.api.app.model.Sidebar
|
||||
import kotlinx.coroutines.Deferred
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* 提供通用信息的接口
|
||||
*/
|
||||
@Suppress("DeferredIsResult")
|
||||
interface AppAPI {
|
||||
/**
|
||||
* 登陆完成后将请求一次此接口以获得个人资料
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@GET("/x/v2/account/myinfo")
|
||||
fun myInfo(): Deferred<MyInfo>
|
||||
|
||||
/**
|
||||
* 登陆后也会访问此接口, 返回内容大致与 myInfo() 相同
|
||||
*/
|
||||
@GET("/x/v2/account/mine")
|
||||
fun mine(): Deferred<Mine>
|
||||
|
||||
/**
|
||||
* 侧边栏中动态增加的按钮, 返回信息包含 URI 地址(到对应的 activity)
|
||||
*/
|
||||
@GET("/x/resource/sidebar")
|
||||
fun sidebar(): Deferred<Sidebar>
|
||||
|
||||
/**
|
||||
* 首页内容
|
||||
* 首页 -> 推荐
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@GET("/x/v2/feed/index")
|
||||
fun index(
|
||||
@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 = 2,
|
||||
@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<IndexPage>
|
||||
}
|
||||
|
374
src/main/kotlin/com/hiczp/bilibili/api/app/model/IndexPage.kt
Normal file
374
src/main/kotlin/com/hiczp/bilibili/api/app/model/IndexPage.kt
Normal file
File diff suppressed because one or more lines are too long
60
src/main/kotlin/com/hiczp/bilibili/api/app/model/Mine.kt
Normal file
60
src/main/kotlin/com/hiczp/bilibili/api/app/model/Mine.kt
Normal file
@ -0,0 +1,60 @@
|
||||
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: Int, // 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
|
||||
)
|
||||
}
|
||||
}
|
33
src/main/kotlin/com/hiczp/bilibili/api/app/model/Sidebar.kt
Normal file
33
src/main/kotlin/com/hiczp/bilibili/api/app/model/Sidebar.kt
Normal file
@ -0,0 +1,33 @@
|
||||
package com.hiczp.bilibili.api.app.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class Sidebar(
|
||||
@SerializedName("code")
|
||||
var code: Int, // 0
|
||||
@SerializedName("data")
|
||||
var `data`: List<SidebarElement>,
|
||||
@SerializedName("message")
|
||||
var message: String, // 0
|
||||
@SerializedName("ttl")
|
||||
var ttl: Int // 1
|
||||
) {
|
||||
data class SidebarElement(
|
||||
@SerializedName("id")
|
||||
var id: Int, // 13
|
||||
@SerializedName("logo")
|
||||
var logo: String, // http://i0.hdslb.com/bfs/archive/91f7ba40e54502f7479c8d355e4298989bb8ebce.png
|
||||
@SerializedName("module")
|
||||
var module: Int, // 1
|
||||
@SerializedName("name")
|
||||
var name: String, // 会员购中心
|
||||
@SerializedName("online_time")
|
||||
var onlineTime: Int, // 0
|
||||
@SerializedName("param")
|
||||
var `param`: String, // bilibili://mall/mine?msource=mine
|
||||
@SerializedName("rank")
|
||||
var rank: Int, // 300
|
||||
@SerializedName("tip")
|
||||
var tip: Int // 1
|
||||
)
|
||||
}
|
26
src/main/kotlin/com/hiczp/bilibili/api/message/MessageAPI.kt
Normal file
26
src/main/kotlin/com/hiczp/bilibili/api/message/MessageAPI.kt
Normal file
@ -0,0 +1,26 @@
|
||||
package com.hiczp.bilibili.api.message
|
||||
|
||||
import com.hiczp.bilibili.api.message.model.NotifyCount
|
||||
import com.hiczp.bilibili.api.message.model.UplmList
|
||||
import kotlinx.coroutines.Deferred
|
||||
import retrofit2.http.GET
|
||||
|
||||
/**
|
||||
* 消息推送有关的接口
|
||||
*/
|
||||
@Suppress("DeferredIsResult")
|
||||
interface MessageAPI {
|
||||
/**
|
||||
* 获取消息数量
|
||||
* 首页 -> 右上角 talk 图标
|
||||
*/
|
||||
@GET("/api/notify/query.notify.count.do")
|
||||
fun queryNotifyCount(): Deferred<NotifyCount>
|
||||
|
||||
/**
|
||||
* 荣誉周报
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@GET("/api/notify/get.uplm.list.do")
|
||||
fun getUplmList(): Deferred<UplmList>
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.hiczp.bilibili.api.message.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class NotifyCount(
|
||||
@SerializedName("code")
|
||||
var code: Int, // 0
|
||||
@SerializedName("data")
|
||||
var `data`: Data,
|
||||
@SerializedName("message")
|
||||
var message: String,
|
||||
@SerializedName("msg")
|
||||
var msg: String
|
||||
) {
|
||||
data class Data(
|
||||
@SerializedName("_gt_")
|
||||
var gt: Int, // 0
|
||||
/**
|
||||
* \@我
|
||||
*/
|
||||
@SerializedName("at_me")
|
||||
var atMe: Int, // 0
|
||||
@SerializedName("notify_me")
|
||||
var notifyMe: Int, // 9
|
||||
/**
|
||||
* 收到的赞
|
||||
*/
|
||||
@SerializedName("praise_me")
|
||||
var praiseMe: Int, // 0
|
||||
/**
|
||||
* 回复我的
|
||||
*/
|
||||
@SerializedName("reply_me")
|
||||
var replyMe: Int, // 0
|
||||
@SerializedName("up")
|
||||
var up: Int // 0
|
||||
)
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.hiczp.bilibili.api.message.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class UplmList(
|
||||
@SerializedName("code")
|
||||
var code: Int, // 0
|
||||
@SerializedName("data")
|
||||
var `data`: Data,
|
||||
@SerializedName("message")
|
||||
var message: String,
|
||||
@SerializedName("msg")
|
||||
var msg: String
|
||||
) {
|
||||
data class Data(
|
||||
@SerializedName("_gt_")
|
||||
var gt: Int, // 0
|
||||
@SerializedName("id")
|
||||
var id: Int, // 2429173
|
||||
@SerializedName("time")
|
||||
var time: String, // 2018-11-25 19:29:22
|
||||
@SerializedName("title")
|
||||
var title: String, // 叮!你有一份荣誉周报待查收!
|
||||
@SerializedName("unread")
|
||||
var unread: Int // 0
|
||||
)
|
||||
}
|
@ -9,6 +9,9 @@ import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
|
||||
/**
|
||||
* 用户鉴权相关的接口
|
||||
*/
|
||||
@Suppress("DeferredIsResult")
|
||||
interface PassportAPI {
|
||||
@POST("/api/oauth2/getKey")
|
||||
|
30
src/main/kotlin/com/hiczp/bilibili/api/vc/VcAPI.kt
Normal file
30
src/main/kotlin/com/hiczp/bilibili/api/vc/VcAPI.kt
Normal file
@ -0,0 +1,30 @@
|
||||
package com.hiczp.bilibili.api.vc
|
||||
|
||||
import com.hiczp.bilibili.api.vc.model.AttentionList
|
||||
import com.hiczp.bilibili.api.vc.model.DynamicNumber
|
||||
import kotlinx.coroutines.Deferred
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
|
||||
/**
|
||||
* 小视频
|
||||
*/
|
||||
@Suppress("DeferredIsResult")
|
||||
interface VcAPI {
|
||||
/**
|
||||
* //TODO 接口意义不明
|
||||
* 可能是一个通知接口
|
||||
*/
|
||||
@GET("/dynamic_svr/v1/dynamic_svr/dynamic_num")
|
||||
fun dynamicNumber(
|
||||
@Query("rsp_type") rspType: Int,
|
||||
@Query("type_list") typeList: Long? = null,
|
||||
@Query("update_num_dy_id") updateNumberDynamicId: Int = 0
|
||||
): Deferred<DynamicNumber>
|
||||
|
||||
/**
|
||||
* 关注列表
|
||||
*/
|
||||
@GET("/feed/v1/feed/get_attention_list")
|
||||
fun getAttentionList(): Deferred<AttentionList>
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.hiczp.bilibili.api.vc.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class AttentionList(
|
||||
@SerializedName("code")
|
||||
var code: Int, // 0
|
||||
@SerializedName("data")
|
||||
var `data`: Data,
|
||||
@SerializedName("message")
|
||||
var message: String, // success
|
||||
@SerializedName("msg")
|
||||
var msg: String // success
|
||||
) {
|
||||
data class Data(
|
||||
@SerializedName("list")
|
||||
var list: List<String>
|
||||
)
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.hiczp.bilibili.api.vc.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class DynamicNumber(
|
||||
@SerializedName("code")
|
||||
var code: Int, // 0
|
||||
@SerializedName("data")
|
||||
var `data`: Data,
|
||||
@SerializedName("message")
|
||||
var message: String,
|
||||
@SerializedName("msg")
|
||||
var msg: String
|
||||
) {
|
||||
data class Data(
|
||||
@SerializedName("_gt_")
|
||||
var gt: Int, // 0
|
||||
@SerializedName("exist_gap")
|
||||
var existGap: Int, // 1
|
||||
@SerializedName("new_num")
|
||||
var newNum: Int, // 30
|
||||
@SerializedName("update_num")
|
||||
var updateNum: Int // 100
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user