From 2e8791a1010b55ed41b4342e2a67c82b5ddca878 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 27 Dec 2020 17:46:14 -0500 Subject: [PATCH] Refactor tracker response parsing --- .../data/track/anilist/AnilistApi.kt | 188 ++++++++++-------- .../data/track/bangumi/BangumiApi.kt | 131 +++++++----- .../data/track/myanimelist/MyAnimeListApi.kt | 113 +++++------ .../data/track/shikimori/ShikimoriApi.kt | 131 ++++++------ .../tachiyomi/network/OkHttpExtensions.kt | 5 +- 5 files changed, 313 insertions(+), 255 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt index ac56e5808..dc9bfc098 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt @@ -6,7 +6,9 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.POST 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.JsonObject import kotlinx.serialization.json.buildJsonObject @@ -33,8 +35,9 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { private val authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun addLibManga(track: Track): Track { - val query = - """ + return withContext(Dispatchers.IO) { + val query = + """ |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { |SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) { | id @@ -42,28 +45,34 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |} |""".trimMargin() - val payload = buildJsonObject { - put("query", query) - putJsonObject("variables") { - put("mangaId", track.media_id) - put("progress", track.last_chapter_read) - put("status", track.toAnilistStatus()) + val payload = buildJsonObject { + put("query", query) + putJsonObject("variables") { + put("mangaId", track.media_id) + put("progress", track.last_chapter_read) + put("status", track.toAnilistStatus()) + } } - } - return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use { - val responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = json.decodeFromString(responseBody) - track.library_id = response["data"]!!.jsonObject["SaveMediaListEntry"]!!.jsonObject["id"]!!.jsonPrimitive.long - track + authClient.newCall( + POST( + apiUrl, + body = payload.toString().toRequestBody(jsonMime) + ) + ) + .await() + .parseAs() + .let { + track.library_id = + it["data"]!!.jsonObject["SaveMediaListEntry"]!!.jsonObject["id"]!!.jsonPrimitive.long + track + } } } suspend fun updateLibManga(track: Track): Track { - val query = - """ + return withContext(Dispatchers.IO) { + val query = + """ |mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) { |SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) { |id @@ -72,22 +81,25 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |} |""".trimMargin() - val payload = buildJsonObject { - put("query", query) - putJsonObject("variables") { - put("listId", track.library_id) - put("progress", track.last_chapter_read) - put("status", track.toAnilistStatus()) - put("score", track.score.toInt()) + val payload = buildJsonObject { + put("query", query) + putJsonObject("variables") { + put("listId", track.library_id) + put("progress", track.last_chapter_read) + put("status", track.toAnilistStatus()) + put("score", track.score.toInt()) + } } + authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))) + .await() + track } - authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await() - return track } suspend fun search(search: String): List { - val query = - """ + return withContext(Dispatchers.IO) { + val query = + """ |query Search(${'$'}query: String) { |Page (perPage: 50) { |media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) { @@ -111,29 +123,34 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |} |""".trimMargin() - val payload = buildJsonObject { - put("query", query) - putJsonObject("variables") { - put("query", search) + val payload = buildJsonObject { + put("query", query) + putJsonObject("variables") { + put("query", search) + } } - } - return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use { - val responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = json.decodeFromString(responseBody) - val data = response["data"]!!.jsonObject - val page = data["Page"]!!.jsonObject - val media = page["media"]!!.jsonArray - val entries = media.map { jsonToALManga(it.jsonObject) } - entries.map { it.toTrack() } + authClient.newCall( + POST( + apiUrl, + body = payload.toString().toRequestBody(jsonMime) + ) + ) + .await() + .parseAs() + .let { response -> + val data = response["data"]!!.jsonObject + val page = data["Page"]!!.jsonObject + val media = page["media"]!!.jsonArray + val entries = media.map { jsonToALManga(it.jsonObject) } + entries.map { it.toTrack() } + } } } suspend fun findLibManga(track: Track, userid: Int): Track? { - val query = - """ + return withContext(Dispatchers.IO) { + val query = + """ |query (${'$'}id: Int!, ${'$'}manga_id: Int!) { |Page { |mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) { @@ -163,24 +180,28 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |} |""".trimMargin() - val payload = buildJsonObject { - put("query", query) - putJsonObject("variables") { - put("id", userid) - put("manga_id", track.media_id) + val payload = buildJsonObject { + put("query", query) + putJsonObject("variables") { + put("id", userid) + put("manga_id", track.media_id) + } } - } - return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use { - val responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = json.decodeFromString(responseBody) - val data = response["data"]!!.jsonObject - val page = data["Page"]!!.jsonObject - val media = page["mediaList"]!!.jsonArray - val entries = media.map { jsonToALUserManga(it.jsonObject) } - entries.firstOrNull()?.toTrack() + authClient.newCall( + POST( + apiUrl, + body = payload.toString().toRequestBody(jsonMime) + ) + ) + .await() + .parseAs() + .let { response -> + val data = response["data"]!!.jsonObject + val page = data["Page"]!!.jsonObject + val media = page["mediaList"]!!.jsonArray + val entries = media.map { jsonToALUserManga(it.jsonObject) } + entries.firstOrNull()?.toTrack() + } } } @@ -193,8 +214,9 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } suspend fun getCurrentUser(): Pair { - val query = - """ + return withContext(Dispatchers.IO) { + val query = + """ |query User { |Viewer { |id @@ -204,21 +226,25 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |} |} |""".trimMargin() - val payload = buildJsonObject { - put("query", query) - } - return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use { - val responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") + val payload = buildJsonObject { + put("query", query) } - val response = json.decodeFromString(responseBody) - val data = response["data"]!!.jsonObject - val viewer = data["Viewer"]!!.jsonObject - Pair( - viewer["id"]!!.jsonPrimitive.int, - viewer["mediaListOptions"]!!.jsonObject["scoreFormat"]!!.jsonPrimitive.content + authClient.newCall( + POST( + apiUrl, + body = payload.toString().toRequestBody(jsonMime) + ) ) + .await() + .parseAs() + .let { + val data = it["data"]!!.jsonObject + val viewer = data["Viewer"]!!.jsonObject + Pair( + viewer["id"]!!.jsonPrimitive.int, + viewer["mediaListOptions"]!!.jsonObject["scoreFormat"]!!.jsonPrimitive.content + ) + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt index 094119b0d..4dc9835c0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt @@ -8,6 +8,9 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST 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.json.Json import kotlinx.serialization.json.JsonObject @@ -30,46 +33,62 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept private val authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun addLibManga(track: Track): Track { - val body = FormBody.Builder() - .add("rating", track.score.toInt().toString()) - .add("status", track.toBangumiStatus()) - .build() - authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = body)).await() - return track + return withContext(Dispatchers.IO) { + val body = FormBody.Builder() + .add("rating", track.score.toInt().toString()) + .add("status", track.toBangumiStatus()) + .build() + authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = body)) + .await() + track + } } suspend fun updateLibManga(track: Track): Track { - // read status update - val sbody = FormBody.Builder() - .add("status", track.toBangumiStatus()) - .build() - authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = sbody)).await() + return withContext(Dispatchers.IO) { + // read status update + val sbody = FormBody.Builder() + .add("status", track.toBangumiStatus()) + .build() + authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = sbody)) + .await() - // chapter update - val body = FormBody.Builder() - .add("watched_eps", track.last_chapter_read.toString()) - .build() - authClient.newCall(POST("$apiUrl/subject/${track.media_id}/update/watched_eps", body = body)).await() + // chapter update + val body = FormBody.Builder() + .add("watched_eps", track.last_chapter_read.toString()) + .build() + authClient.newCall( + POST( + "$apiUrl/subject/${track.media_id}/update/watched_eps", + body = body + ) + ).await() - return track + track + } } suspend fun search(search: String): List { - val url = "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}" - .toUri() - .buildUpon() - .appendQueryParameter("max_results", "20") - .build() - return authClient.newCall(GET(url.toString())).await().use { - var responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - if (responseBody.contains("\"code\":404")) { - responseBody = "{\"results\":0,\"list\":[]}" - } - val response = json.decodeFromString(responseBody)["list"]?.jsonArray - response?.filter { it.jsonObject["type"]?.jsonPrimitive?.int == 1 }?.map { jsonToSearch(it.jsonObject) }.orEmpty() + return withContext(Dispatchers.IO) { + val url = "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}" + .toUri() + .buildUpon() + .appendQueryParameter("max_results", "20") + .build() + authClient.newCall(GET(url.toString())) + .await() + .use { + var responseBody = it.body?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") + } + if (responseBody.contains("\"code\":404")) { + responseBody = "{\"results\":0,\"list\":[]}" + } + val response = json.decodeFromString(responseBody)["list"]?.jsonArray + response?.filter { it.jsonObject["type"]?.jsonPrimitive?.int == 1 } + ?.map { jsonToSearch(it.jsonObject) }.orEmpty() + } } } @@ -98,38 +117,40 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } suspend fun findLibManga(track: Track): Track? { - return authClient.newCall(GET("$apiUrl/subject/${track.media_id}")).await().use { - // get comic info - val responseBody = it.body?.string().orEmpty() - jsonToTrack(json.decodeFromString(responseBody)) + return withContext(Dispatchers.IO) { + authClient.newCall(GET("$apiUrl/subject/${track.media_id}")) + .await() + .parseAs() + .let { jsonToSearch(it) } } } suspend fun statusLibManga(track: Track): Track? { - val urlUserRead = "$apiUrl/collection/${track.media_id}" - val requestUserRead = Request.Builder() - .url(urlUserRead) - .cacheControl(CacheControl.FORCE_NETWORK) - .get() - .build() + return withContext(Dispatchers.IO) { + val urlUserRead = "$apiUrl/collection/${track.media_id}" + val requestUserRead = Request.Builder() + .url(urlUserRead) + .cacheControl(CacheControl.FORCE_NETWORK) + .get() + .build() - // TODO: get user readed chapter here - return authClient.newCall(requestUserRead).await().use { - val resp = it.body?.string() - val coll = json.decodeFromString(resp!!) - track.status = coll.status?.id!! - track.last_chapter_read = coll.ep_status!! - track + // TODO: get user readed chapter here + authClient.newCall(requestUserRead) + .await() + .parseAs() + .let { + track.status = it.status?.id!! + track.last_chapter_read = it.ep_status!! + track + } } } suspend fun accessToken(code: String): OAuth { - return client.newCall(accessTokenRequest(code)).await().use { - val responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - json.decodeFromString(responseBody) + return withContext(Dispatchers.IO) { + client.newCall(accessTokenRequest(code)) + .await() + .parseAs() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt index cd26b51ee..cecf27571 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt @@ -8,13 +8,12 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.await +import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.util.PkceUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.withContext -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.boolean import kotlinx.serialization.json.int @@ -25,15 +24,11 @@ import okhttp3.FormBody import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody -import okhttp3.Response -import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Locale class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListInterceptor) { - private val json: Json by injectLazy() - private val authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun getAccessToken(authCode: String): OAuth { @@ -44,10 +39,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI .add("code_verifier", codeVerifier) .add("grant_type", "authorization_code") .build() - client.newCall(POST("$baseOAuthUrl/token", body = formBody)).await().use { - val responseBody = it.body?.string().orEmpty() - json.decodeFromString(responseBody) - } + client.newCall(POST("$baseOAuthUrl/token", body = formBody)) + .await() + .parseAs() } } @@ -57,11 +51,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI .url("$baseApiUrl/users/@me") .get() .build() - authClient.newCall(request).await().use { - val responseBody = it.body?.string().orEmpty() - val response = json.decodeFromString(responseBody) - response["name"]!!.jsonPrimitive.content - } + authClient.newCall(request) + .await() + .parseAs() + .let { it["name"]!!.jsonPrimitive.content } } } @@ -70,18 +63,19 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI val url = "$baseApiUrl/manga".toUri().buildUpon() .appendQueryParameter("q", query) .build() - authClient.newCall(GET(url.toString())).await().use { - val responseBody = it.body?.string().orEmpty() - val response = json.decodeFromString(responseBody) - response["data"]!!.jsonArray - .map { data -> data.jsonObject["node"]!!.jsonObject } - .map { node -> - val id = node["id"]!!.jsonPrimitive.int - async { getMangaDetails(id) } - } - .awaitAll() - .filter { trackSearch -> trackSearch.publishing_type != "novel" } - } + authClient.newCall(GET(url.toString())) + .await() + .parseAs() + .let { + it["data"]!!.jsonArray + .map { data -> data.jsonObject["node"]!!.jsonObject } + .map { node -> + val id = node["id"]!!.jsonPrimitive.int + async { getMangaDetails(id) } + } + .awaitAll() + .filter { trackSearch -> trackSearch.publishing_type != "novel" } + } } } @@ -91,27 +85,28 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI .appendPath(id.toString()) .appendQueryParameter("fields", "id,title,synopsis,num_chapters,main_picture,status,media_type,start_date") .build() - authClient.newCall(GET(url.toString())).await().use { - val responseBody = it.body?.string().orEmpty() - val response = json.decodeFromString(responseBody) - val obj = response.jsonObject - TrackSearch.create(TrackManager.MYANIMELIST).apply { - media_id = obj["id"]!!.jsonPrimitive.int - title = obj["title"]!!.jsonPrimitive.content - summary = obj["synopsis"]?.jsonPrimitive?.content ?: "" - total_chapters = obj["num_chapters"]!!.jsonPrimitive.int - cover_url = obj["main_picture"]?.jsonObject?.get("large")?.jsonPrimitive?.content ?: "" - tracking_url = "https://myanimelist.net/manga/$media_id" - publishing_status = obj["status"]!!.jsonPrimitive.content.replace("_", " ") - publishing_type = obj["media_type"]!!.jsonPrimitive.content.replace("_", " ") - start_date = try { - val outputDf = SimpleDateFormat("yyyy-MM-dd", Locale.US) - outputDf.format(obj["start_date"]!!) - } catch (e: Exception) { - "" + authClient.newCall(GET(url.toString())) + .await() + .parseAs() + .let { + val obj = it.jsonObject + TrackSearch.create(TrackManager.MYANIMELIST).apply { + media_id = obj["id"]!!.jsonPrimitive.int + title = obj["title"]!!.jsonPrimitive.content + summary = obj["synopsis"]?.jsonPrimitive?.content ?: "" + total_chapters = obj["num_chapters"]!!.jsonPrimitive.int + cover_url = obj["main_picture"]?.jsonObject?.get("large")?.jsonPrimitive?.content ?: "" + tracking_url = "https://myanimelist.net/manga/$media_id" + publishing_status = obj["status"]!!.jsonPrimitive.content.replace("_", " ") + publishing_type = obj["media_type"]!!.jsonPrimitive.content.replace("_", " ") + start_date = try { + val outputDf = SimpleDateFormat("yyyy-MM-dd", Locale.US) + outputDf.format(obj["start_date"]!!) + } catch (e: Exception) { + "" + } } } - } } } @@ -124,9 +119,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI .url(mangaUrl(track.media_id).toString()) .put(formBody) .build() - authClient.newCall(request).await().use { - parseMangaItem(it, track) - } + authClient.newCall(request) + .await() + .parseAs() + .let { parseMangaItem(it, track) } } } @@ -140,9 +136,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI .url(mangaUrl(track.media_id).toString()) .put(formBody) .build() - authClient.newCall(request).await().use { - parseMangaItem(it, track) - } + authClient.newCall(request) + .await() + .parseAs() + .let { parseMangaItem(it, track) } } } @@ -158,15 +155,15 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI .url(mangaUrl(track.media_id).toString()) .put(formBody) .build() - authClient.newCall(request).await().use { - parseMangaItem(it, track) - } + authClient.newCall(request) + .await() + .parseAs() + .let { parseMangaItem(it, track) } } } - private fun parseMangaItem(response: Response, track: Track): Track { - val responseBody = response.body?.string().orEmpty() - val obj = json.decodeFromString(responseBody).jsonObject + private fun parseMangaItem(response: JsonObject, track: Track): Track { + val obj = response.jsonObject return track.apply { val isRereading = obj["is_rereading"]!!.jsonPrimitive.boolean status = if (isRereading) MyAnimeList.REREADING else getStatus(obj["status"]!!.jsonPrimitive.content) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt index d10bd2f7a..ae1e81d1f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt @@ -7,8 +7,10 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.await -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json +import eu.kanade.tachiyomi.network.parseAs +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.buildJsonObject @@ -22,45 +24,51 @@ import okhttp3.FormBody import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.RequestBody.Companion.toRequestBody -import uy.kohesive.injekt.injectLazy 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 authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun addLibManga(track: Track, user_id: String): Track { - val payload = buildJsonObject { - putJsonObject("user_rate") { - put("user_id", user_id) - put("target_id", track.media_id) - put("target_type", "Manga") - put("chapters", track.last_chapter_read) - put("score", track.score.toInt()) - put("status", track.toShikimoriStatus()) + return withContext(Dispatchers.IO) { + val payload = buildJsonObject { + putJsonObject("user_rate") { + put("user_id", user_id) + put("target_id", track.media_id) + put("target_type", "Manga") + put("chapters", track.last_chapter_read) + put("score", track.score.toInt()) + put("status", track.toShikimoriStatus()) + } } + authClient.newCall( + POST( + "$apiUrl/v2/user_rates", + body = payload.toString().toRequestBody(jsonMime) + ) + ).await() + track } - authClient.newCall(POST("$apiUrl/v2/user_rates", body = payload.toString().toRequestBody(jsonMime))).await() - return track } suspend fun updateLibManga(track: Track, user_id: String): Track = addLibManga(track, user_id) suspend fun search(search: String): List { - val url = "$apiUrl/mangas".toUri().buildUpon() - .appendQueryParameter("order", "popularity") - .appendQueryParameter("search", search) - .appendQueryParameter("limit", "20") - .build() - return authClient.newCall(GET(url.toString())).await().use { - val responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = json.decodeFromString(responseBody) - response.map { jsonToSearch(it.jsonObject) } + return withContext(Dispatchers.IO) { + val url = "$apiUrl/mangas".toUri().buildUpon() + .appendQueryParameter("order", "popularity") + .appendQueryParameter("search", search) + .appendQueryParameter("limit", "20") + .build() + authClient.newCall(GET(url.toString())) + .await() + .parseAs() + .let { response -> + response.map { + jsonToSearch(it.jsonObject) + } + } } } @@ -91,47 +99,50 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } suspend fun findLibManga(track: Track, user_id: String): Track? { - val urlMangas = "$apiUrl/mangas".toUri().buildUpon() - .appendPath(track.media_id.toString()) - .build() - val mangas = authClient.newCall(GET(urlMangas.toString())).await().use { - val responseBody = it.body?.string().orEmpty() - json.decodeFromString(responseBody) - } + return withContext(Dispatchers.IO) { + val urlMangas = "$apiUrl/mangas".toUri().buildUpon() + .appendPath(track.media_id.toString()) + .build() + val mangas = authClient.newCall(GET(urlMangas.toString())) + .await() + .parseAs() - val url = "$apiUrl/v2/user_rates".toUri().buildUpon() - .appendQueryParameter("user_id", user_id) - .appendQueryParameter("target_id", track.media_id.toString()) - .appendQueryParameter("target_type", "Manga") - .build() - return authClient.newCall(GET(url.toString())).await().use { - val responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - val response = json.decodeFromString(responseBody) - if (response.size > 1) { - throw Exception("Too much mangas in response") - } - val entry = response.map { - jsonToTrack(it.jsonObject, mangas) - } - entry.firstOrNull() + val url = "$apiUrl/v2/user_rates".toUri().buildUpon() + .appendQueryParameter("user_id", user_id) + .appendQueryParameter("target_id", track.media_id.toString()) + .appendQueryParameter("target_type", "Manga") + .build() + authClient.newCall(GET(url.toString())) + .await() + .parseAs() + .let { response -> + if (response.size > 1) { + throw Exception("Too much mangas in response") + } + val entry = response.map { + jsonToTrack(it.jsonObject, mangas) + } + entry.firstOrNull() + } } } fun getCurrentUser(): Int { - val user = authClient.newCall(GET("$apiUrl/users/whoami")).execute().body?.string()!! - return json.decodeFromString(user)["id"]!!.jsonPrimitive.int + return runBlocking { + authClient.newCall(GET("$apiUrl/users/whoami")) + .await() + .parseAs() + .let { + it["id"]!!.jsonPrimitive.int + } + } } suspend fun accessToken(code: String): OAuth { - return client.newCall(accessTokenRequest(code)).await().use { - val responseBody = it.body?.string().orEmpty() - if (responseBody.isEmpty()) { - throw Exception("Null Response") - } - json.decodeFromString(responseBody) + return withContext(Dispatchers.IO) { + client.newCall(accessTokenRequest(code)) + .await() + .parseAs() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index f4edf40cc..4a99bd2de 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -12,6 +12,7 @@ import rx.Observable import rx.Producer import rx.Subscription import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.fullType import uy.kohesive.injekt.api.get import java.io.IOException import java.util.concurrent.atomic.AtomicBoolean @@ -111,8 +112,10 @@ fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListene } inline fun Response.parseAs(): T { + // Avoiding Injekt.get() due to compiler issues + val json = Injekt.getInstance(fullType().type) this.use { val responseBody = it.body?.string().orEmpty() - return Injekt.get().decodeFromString(responseBody) + return json.decodeFromString(responseBody) } }