Refactor tracker response parsing

This commit is contained in:
arkon 2020-12-27 17:46:14 -05:00
parent 0e2b8b10d1
commit 2e8791a101
5 changed files with 313 additions and 255 deletions

View File

@ -6,7 +6,9 @@ import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.await
import kotlinx.serialization.decodeFromString import eu.kanade.tachiyomi.network.parseAs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.buildJsonObject
@ -33,6 +35,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val authClient = client.newBuilder().addInterceptor(interceptor).build()
suspend fun addLibManga(track: Track): Track { suspend fun addLibManga(track: Track): Track {
return withContext(Dispatchers.IO) {
val query = val query =
""" """
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
@ -50,18 +53,24 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("status", track.toAnilistStatus()) put("status", track.toAnilistStatus())
} }
} }
return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use { authClient.newCall(
val responseBody = it.body?.string().orEmpty() POST(
if (responseBody.isEmpty()) { apiUrl,
throw Exception("Null Response") body = payload.toString().toRequestBody(jsonMime)
} )
val response = json.decodeFromString<JsonObject>(responseBody) )
track.library_id = response["data"]!!.jsonObject["SaveMediaListEntry"]!!.jsonObject["id"]!!.jsonPrimitive.long .await()
.parseAs<JsonObject>()
.let {
track.library_id =
it["data"]!!.jsonObject["SaveMediaListEntry"]!!.jsonObject["id"]!!.jsonPrimitive.long
track track
} }
} }
}
suspend fun updateLibManga(track: Track): Track { suspend fun updateLibManga(track: Track): Track {
return withContext(Dispatchers.IO) {
val query = val query =
""" """
|mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) { |mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
@ -81,11 +90,14 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("score", track.score.toInt()) put("score", track.score.toInt())
} }
} }
authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await() authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime)))
return track .await()
track
}
} }
suspend fun search(search: String): List<TrackSearch> { suspend fun search(search: String): List<TrackSearch> {
return withContext(Dispatchers.IO) {
val query = val query =
""" """
|query Search(${'$'}query: String) { |query Search(${'$'}query: String) {
@ -117,12 +129,15 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("query", search) put("query", search)
} }
} }
return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use { authClient.newCall(
val responseBody = it.body?.string().orEmpty() POST(
if (responseBody.isEmpty()) { apiUrl,
throw Exception("Null Response") body = payload.toString().toRequestBody(jsonMime)
} )
val response = json.decodeFromString<JsonObject>(responseBody) )
.await()
.parseAs<JsonObject>()
.let { response ->
val data = response["data"]!!.jsonObject val data = response["data"]!!.jsonObject
val page = data["Page"]!!.jsonObject val page = data["Page"]!!.jsonObject
val media = page["media"]!!.jsonArray val media = page["media"]!!.jsonArray
@ -130,8 +145,10 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
entries.map { it.toTrack() } entries.map { it.toTrack() }
} }
} }
}
suspend fun findLibManga(track: Track, userid: Int): Track? { suspend fun findLibManga(track: Track, userid: Int): Track? {
return withContext(Dispatchers.IO) {
val query = val query =
""" """
|query (${'$'}id: Int!, ${'$'}manga_id: Int!) { |query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
@ -170,12 +187,15 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("manga_id", track.media_id) put("manga_id", track.media_id)
} }
} }
return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use { authClient.newCall(
val responseBody = it.body?.string().orEmpty() POST(
if (responseBody.isEmpty()) { apiUrl,
throw Exception("Null Response") body = payload.toString().toRequestBody(jsonMime)
} )
val response = json.decodeFromString<JsonObject>(responseBody) )
.await()
.parseAs<JsonObject>()
.let { response ->
val data = response["data"]!!.jsonObject val data = response["data"]!!.jsonObject
val page = data["Page"]!!.jsonObject val page = data["Page"]!!.jsonObject
val media = page["mediaList"]!!.jsonArray val media = page["mediaList"]!!.jsonArray
@ -183,6 +203,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
entries.firstOrNull()?.toTrack() entries.firstOrNull()?.toTrack()
} }
} }
}
suspend fun getLibManga(track: Track, userid: Int): Track { suspend fun getLibManga(track: Track, userid: Int): Track {
return findLibManga(track, userid) ?: throw Exception("Could not find manga") return findLibManga(track, userid) ?: throw Exception("Could not find manga")
@ -193,6 +214,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
} }
suspend fun getCurrentUser(): Pair<Int, String> { suspend fun getCurrentUser(): Pair<Int, String> {
return withContext(Dispatchers.IO) {
val query = val query =
""" """
|query User { |query User {
@ -207,13 +229,16 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
val payload = buildJsonObject { val payload = buildJsonObject {
put("query", query) put("query", query)
} }
return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use { authClient.newCall(
val responseBody = it.body?.string().orEmpty() POST(
if (responseBody.isEmpty()) { apiUrl,
throw Exception("Null Response") body = payload.toString().toRequestBody(jsonMime)
} )
val response = json.decodeFromString<JsonObject>(responseBody) )
val data = response["data"]!!.jsonObject .await()
.parseAs<JsonObject>()
.let {
val data = it["data"]!!.jsonObject
val viewer = data["Viewer"]!!.jsonObject val viewer = data["Viewer"]!!.jsonObject
Pair( Pair(
viewer["id"]!!.jsonPrimitive.int, viewer["id"]!!.jsonPrimitive.int,
@ -221,6 +246,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
) )
} }
} }
}
private fun jsonToALManga(struct: JsonObject): ALManga { private fun jsonToALManga(struct: JsonObject): ALManga {
val date = try { val date = try {

View File

@ -8,6 +8,9 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.parseAs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
@ -30,37 +33,51 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val authClient = client.newBuilder().addInterceptor(interceptor).build()
suspend fun addLibManga(track: Track): Track { suspend fun addLibManga(track: Track): Track {
return withContext(Dispatchers.IO) {
val body = FormBody.Builder() val body = FormBody.Builder()
.add("rating", track.score.toInt().toString()) .add("rating", track.score.toInt().toString())
.add("status", track.toBangumiStatus()) .add("status", track.toBangumiStatus())
.build() .build()
authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = body)).await() authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = body))
return track .await()
track
}
} }
suspend fun updateLibManga(track: Track): Track { suspend fun updateLibManga(track: Track): Track {
return withContext(Dispatchers.IO) {
// read status update // read status update
val sbody = FormBody.Builder() val sbody = FormBody.Builder()
.add("status", track.toBangumiStatus()) .add("status", track.toBangumiStatus())
.build() .build()
authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = sbody)).await() authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = sbody))
.await()
// chapter update // chapter update
val body = FormBody.Builder() val body = FormBody.Builder()
.add("watched_eps", track.last_chapter_read.toString()) .add("watched_eps", track.last_chapter_read.toString())
.build() .build()
authClient.newCall(POST("$apiUrl/subject/${track.media_id}/update/watched_eps", body = body)).await() authClient.newCall(
POST(
"$apiUrl/subject/${track.media_id}/update/watched_eps",
body = body
)
).await()
return track track
}
} }
suspend fun search(search: String): List<TrackSearch> { suspend fun search(search: String): List<TrackSearch> {
return withContext(Dispatchers.IO) {
val url = "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}" val url = "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}"
.toUri() .toUri()
.buildUpon() .buildUpon()
.appendQueryParameter("max_results", "20") .appendQueryParameter("max_results", "20")
.build() .build()
return authClient.newCall(GET(url.toString())).await().use { authClient.newCall(GET(url.toString()))
.await()
.use {
var responseBody = it.body?.string().orEmpty() var responseBody = it.body?.string().orEmpty()
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
@ -69,7 +86,9 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
responseBody = "{\"results\":0,\"list\":[]}" responseBody = "{\"results\":0,\"list\":[]}"
} }
val response = json.decodeFromString<JsonObject>(responseBody)["list"]?.jsonArray val response = json.decodeFromString<JsonObject>(responseBody)["list"]?.jsonArray
response?.filter { it.jsonObject["type"]?.jsonPrimitive?.int == 1 }?.map { jsonToSearch(it.jsonObject) }.orEmpty() response?.filter { it.jsonObject["type"]?.jsonPrimitive?.int == 1 }
?.map { jsonToSearch(it.jsonObject) }.orEmpty()
}
} }
} }
@ -98,14 +117,16 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
} }
suspend fun findLibManga(track: Track): Track? { suspend fun findLibManga(track: Track): Track? {
return authClient.newCall(GET("$apiUrl/subject/${track.media_id}")).await().use { return withContext(Dispatchers.IO) {
// get comic info authClient.newCall(GET("$apiUrl/subject/${track.media_id}"))
val responseBody = it.body?.string().orEmpty() .await()
jsonToTrack(json.decodeFromString(responseBody)) .parseAs<JsonObject>()
.let { jsonToSearch(it) }
} }
} }
suspend fun statusLibManga(track: Track): Track? { suspend fun statusLibManga(track: Track): Track? {
return withContext(Dispatchers.IO) {
val urlUserRead = "$apiUrl/collection/${track.media_id}" val urlUserRead = "$apiUrl/collection/${track.media_id}"
val requestUserRead = Request.Builder() val requestUserRead = Request.Builder()
.url(urlUserRead) .url(urlUserRead)
@ -114,22 +135,22 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
.build() .build()
// TODO: get user readed chapter here // TODO: get user readed chapter here
return authClient.newCall(requestUserRead).await().use { authClient.newCall(requestUserRead)
val resp = it.body?.string() .await()
val coll = json.decodeFromString<Collection>(resp!!) .parseAs<Collection>()
track.status = coll.status?.id!! .let {
track.last_chapter_read = coll.ep_status!! track.status = it.status?.id!!
track.last_chapter_read = it.ep_status!!
track track
} }
} }
}
suspend fun accessToken(code: String): OAuth { suspend fun accessToken(code: String): OAuth {
return client.newCall(accessTokenRequest(code)).await().use { return withContext(Dispatchers.IO) {
val responseBody = it.body?.string().orEmpty() client.newCall(accessTokenRequest(code))
if (responseBody.isEmpty()) { .await()
throw Exception("Null Response") .parseAs()
}
json.decodeFromString<OAuth>(responseBody)
} }
} }

View File

@ -8,13 +8,12 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.util.PkceUtil import eu.kanade.tachiyomi.util.PkceUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.boolean import kotlinx.serialization.json.boolean
import kotlinx.serialization.json.int import kotlinx.serialization.json.int
@ -25,15 +24,11 @@ import okhttp3.FormBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.Response
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListInterceptor) { class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListInterceptor) {
private val json: Json by injectLazy()
private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val authClient = client.newBuilder().addInterceptor(interceptor).build()
suspend fun getAccessToken(authCode: String): OAuth { suspend fun getAccessToken(authCode: String): OAuth {
@ -44,10 +39,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.add("code_verifier", codeVerifier) .add("code_verifier", codeVerifier)
.add("grant_type", "authorization_code") .add("grant_type", "authorization_code")
.build() .build()
client.newCall(POST("$baseOAuthUrl/token", body = formBody)).await().use { client.newCall(POST("$baseOAuthUrl/token", body = formBody))
val responseBody = it.body?.string().orEmpty() .await()
json.decodeFromString(responseBody) .parseAs()
}
} }
} }
@ -57,11 +51,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.url("$baseApiUrl/users/@me") .url("$baseApiUrl/users/@me")
.get() .get()
.build() .build()
authClient.newCall(request).await().use { authClient.newCall(request)
val responseBody = it.body?.string().orEmpty() .await()
val response = json.decodeFromString<JsonObject>(responseBody) .parseAs<JsonObject>()
response["name"]!!.jsonPrimitive.content .let { it["name"]!!.jsonPrimitive.content }
}
} }
} }
@ -70,10 +63,11 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
val url = "$baseApiUrl/manga".toUri().buildUpon() val url = "$baseApiUrl/manga".toUri().buildUpon()
.appendQueryParameter("q", query) .appendQueryParameter("q", query)
.build() .build()
authClient.newCall(GET(url.toString())).await().use { authClient.newCall(GET(url.toString()))
val responseBody = it.body?.string().orEmpty() .await()
val response = json.decodeFromString<JsonObject>(responseBody) .parseAs<JsonObject>()
response["data"]!!.jsonArray .let {
it["data"]!!.jsonArray
.map { data -> data.jsonObject["node"]!!.jsonObject } .map { data -> data.jsonObject["node"]!!.jsonObject }
.map { node -> .map { node ->
val id = node["id"]!!.jsonPrimitive.int val id = node["id"]!!.jsonPrimitive.int
@ -91,10 +85,11 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.appendPath(id.toString()) .appendPath(id.toString())
.appendQueryParameter("fields", "id,title,synopsis,num_chapters,main_picture,status,media_type,start_date") .appendQueryParameter("fields", "id,title,synopsis,num_chapters,main_picture,status,media_type,start_date")
.build() .build()
authClient.newCall(GET(url.toString())).await().use { authClient.newCall(GET(url.toString()))
val responseBody = it.body?.string().orEmpty() .await()
val response = json.decodeFromString<JsonObject>(responseBody) .parseAs<JsonObject>()
val obj = response.jsonObject .let {
val obj = it.jsonObject
TrackSearch.create(TrackManager.MYANIMELIST).apply { TrackSearch.create(TrackManager.MYANIMELIST).apply {
media_id = obj["id"]!!.jsonPrimitive.int media_id = obj["id"]!!.jsonPrimitive.int
title = obj["title"]!!.jsonPrimitive.content title = obj["title"]!!.jsonPrimitive.content
@ -124,9 +119,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.url(mangaUrl(track.media_id).toString()) .url(mangaUrl(track.media_id).toString())
.put(formBody) .put(formBody)
.build() .build()
authClient.newCall(request).await().use { authClient.newCall(request)
parseMangaItem(it, track) .await()
} .parseAs<JsonObject>()
.let { parseMangaItem(it, track) }
} }
} }
@ -140,9 +136,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.url(mangaUrl(track.media_id).toString()) .url(mangaUrl(track.media_id).toString())
.put(formBody) .put(formBody)
.build() .build()
authClient.newCall(request).await().use { authClient.newCall(request)
parseMangaItem(it, track) .await()
} .parseAs<JsonObject>()
.let { parseMangaItem(it, track) }
} }
} }
@ -158,15 +155,15 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.url(mangaUrl(track.media_id).toString()) .url(mangaUrl(track.media_id).toString())
.put(formBody) .put(formBody)
.build() .build()
authClient.newCall(request).await().use { authClient.newCall(request)
parseMangaItem(it, track) .await()
} .parseAs<JsonObject>()
.let { parseMangaItem(it, track) }
} }
} }
private fun parseMangaItem(response: Response, track: Track): Track { private fun parseMangaItem(response: JsonObject, track: Track): Track {
val responseBody = response.body?.string().orEmpty() val obj = response.jsonObject
val obj = json.decodeFromString<JsonObject>(responseBody).jsonObject
return track.apply { return track.apply {
val isRereading = obj["is_rereading"]!!.jsonPrimitive.boolean val isRereading = obj["is_rereading"]!!.jsonPrimitive.boolean
status = if (isRereading) MyAnimeList.REREADING else getStatus(obj["status"]!!.jsonPrimitive.content) status = if (isRereading) MyAnimeList.REREADING else getStatus(obj["status"]!!.jsonPrimitive.content)

View File

@ -7,8 +7,10 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.await
import kotlinx.serialization.decodeFromString import eu.kanade.tachiyomi.network.parseAs
import kotlinx.serialization.json.Json import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.buildJsonObject
@ -22,16 +24,14 @@ import okhttp3.FormBody
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import uy.kohesive.injekt.injectLazy
class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInterceptor) { class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInterceptor) {
private val json: Json by injectLazy()
private val jsonMime = "application/json; charset=utf-8".toMediaType() private val jsonMime = "application/json; charset=utf-8".toMediaType()
private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val authClient = client.newBuilder().addInterceptor(interceptor).build()
suspend fun addLibManga(track: Track, user_id: String): Track { suspend fun addLibManga(track: Track, user_id: String): Track {
return withContext(Dispatchers.IO) {
val payload = buildJsonObject { val payload = buildJsonObject {
putJsonObject("user_rate") { putJsonObject("user_rate") {
put("user_id", user_id) put("user_id", user_id)
@ -42,25 +42,33 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
put("status", track.toShikimoriStatus()) put("status", track.toShikimoriStatus())
} }
} }
authClient.newCall(POST("$apiUrl/v2/user_rates", body = payload.toString().toRequestBody(jsonMime))).await() authClient.newCall(
return track POST(
"$apiUrl/v2/user_rates",
body = payload.toString().toRequestBody(jsonMime)
)
).await()
track
}
} }
suspend fun updateLibManga(track: Track, user_id: String): Track = addLibManga(track, user_id) suspend fun updateLibManga(track: Track, user_id: String): Track = addLibManga(track, user_id)
suspend fun search(search: String): List<TrackSearch> { suspend fun search(search: String): List<TrackSearch> {
return withContext(Dispatchers.IO) {
val url = "$apiUrl/mangas".toUri().buildUpon() val url = "$apiUrl/mangas".toUri().buildUpon()
.appendQueryParameter("order", "popularity") .appendQueryParameter("order", "popularity")
.appendQueryParameter("search", search) .appendQueryParameter("search", search)
.appendQueryParameter("limit", "20") .appendQueryParameter("limit", "20")
.build() .build()
return authClient.newCall(GET(url.toString())).await().use { authClient.newCall(GET(url.toString()))
val responseBody = it.body?.string().orEmpty() .await()
if (responseBody.isEmpty()) { .parseAs<JsonArray>()
throw Exception("Null Response") .let { response ->
response.map {
jsonToSearch(it.jsonObject)
}
} }
val response = json.decodeFromString<JsonArray>(responseBody)
response.map { jsonToSearch(it.jsonObject) }
} }
} }
@ -91,25 +99,23 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
} }
suspend fun findLibManga(track: Track, user_id: String): Track? { suspend fun findLibManga(track: Track, user_id: String): Track? {
return withContext(Dispatchers.IO) {
val urlMangas = "$apiUrl/mangas".toUri().buildUpon() val urlMangas = "$apiUrl/mangas".toUri().buildUpon()
.appendPath(track.media_id.toString()) .appendPath(track.media_id.toString())
.build() .build()
val mangas = authClient.newCall(GET(urlMangas.toString())).await().use { val mangas = authClient.newCall(GET(urlMangas.toString()))
val responseBody = it.body?.string().orEmpty() .await()
json.decodeFromString<JsonObject>(responseBody) .parseAs<JsonObject>()
}
val url = "$apiUrl/v2/user_rates".toUri().buildUpon() val url = "$apiUrl/v2/user_rates".toUri().buildUpon()
.appendQueryParameter("user_id", user_id) .appendQueryParameter("user_id", user_id)
.appendQueryParameter("target_id", track.media_id.toString()) .appendQueryParameter("target_id", track.media_id.toString())
.appendQueryParameter("target_type", "Manga") .appendQueryParameter("target_type", "Manga")
.build() .build()
return authClient.newCall(GET(url.toString())).await().use { authClient.newCall(GET(url.toString()))
val responseBody = it.body?.string().orEmpty() .await()
if (responseBody.isEmpty()) { .parseAs<JsonArray>()
throw Exception("Null Response") .let { response ->
}
val response = json.decodeFromString<JsonArray>(responseBody)
if (response.size > 1) { if (response.size > 1) {
throw Exception("Too much mangas in response") throw Exception("Too much mangas in response")
} }
@ -119,19 +125,24 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
entry.firstOrNull() entry.firstOrNull()
} }
} }
}
fun getCurrentUser(): Int { fun getCurrentUser(): Int {
val user = authClient.newCall(GET("$apiUrl/users/whoami")).execute().body?.string()!! return runBlocking {
return json.decodeFromString<JsonObject>(user)["id"]!!.jsonPrimitive.int authClient.newCall(GET("$apiUrl/users/whoami"))
.await()
.parseAs<JsonObject>()
.let {
it["id"]!!.jsonPrimitive.int
}
}
} }
suspend fun accessToken(code: String): OAuth { suspend fun accessToken(code: String): OAuth {
return client.newCall(accessTokenRequest(code)).await().use { return withContext(Dispatchers.IO) {
val responseBody = it.body?.string().orEmpty() client.newCall(accessTokenRequest(code))
if (responseBody.isEmpty()) { .await()
throw Exception("Null Response") .parseAs()
}
json.decodeFromString(responseBody)
} }
} }

View File

@ -12,6 +12,7 @@ import rx.Observable
import rx.Producer import rx.Producer
import rx.Subscription import rx.Subscription
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.fullType
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException import java.io.IOException
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
@ -111,8 +112,10 @@ fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListene
} }
inline fun <reified T> Response.parseAs(): T { inline fun <reified T> Response.parseAs(): T {
// Avoiding Injekt.get<Json>() due to compiler issues
val json = Injekt.getInstance<Json>(fullType<Json>().type)
this.use { this.use {
val responseBody = it.body?.string().orEmpty() val responseBody = it.body?.string().orEmpty()
return Injekt.get<Json>().decodeFromString<T>(responseBody) return json.decodeFromString(responseBody)
} }
} }