Use coroutines for Anilist API

This commit is contained in:
arkon 2020-12-24 16:55:04 -05:00
parent 271de31d51
commit dc3ed7fffc
2 changed files with 61 additions and 81 deletions

View file

@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.util.lang.runAsObservable
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -132,26 +133,26 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
} }
override fun add(track: Track): Observable<Track> { override fun add(track: Track): Observable<Track> {
return api.addLibManga(track) return runAsObservable({ api.addLibManga(track) })
} }
override fun update(track: Track): Observable<Track> { override fun update(track: Track): Observable<Track> {
// If user was using API v1 fetch library_id // If user was using API v1 fetch library_id
if (track.library_id == null || track.library_id!! == 0L) { if (track.library_id == null || track.library_id!! == 0L) {
return api.findLibManga(track, getUsername().toInt()).flatMap { return runAsObservable({ api.findLibManga(track, getUsername().toInt()) }).flatMap {
if (it == null) { if (it == null) {
throw Exception("$track not found on user library") throw Exception("$track not found on user library")
} }
track.library_id = it.library_id track.library_id = it.library_id
api.updateLibManga(track) runAsObservable({ api.updateLibManga(track) })
} }
} }
return api.updateLibManga(track) return runAsObservable({ api.updateLibManga(track) })
} }
override fun bind(track: Track): Observable<Track> { override fun bind(track: Track): Observable<Track> {
return api.findLibManga(track, getUsername().toInt()) return runAsObservable({ api.findLibManga(track, getUsername().toInt()) })
.flatMap { remoteTrack -> .flatMap { remoteTrack ->
if (remoteTrack != null) { if (remoteTrack != null) {
track.copyPersonalFrom(remoteTrack) track.copyPersonalFrom(remoteTrack)
@ -167,11 +168,11 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
} }
override fun search(query: String): Observable<List<TrackSearch>> { override fun search(query: String): Observable<List<TrackSearch>> {
return api.search(query) return runAsObservable({ api.search(query) })
} }
override fun refresh(track: Track): Observable<Track> { override fun refresh(track: Track): Observable<Track> {
return api.getLibManga(track, getUsername().toInt()) return runAsObservable({ api.getLibManga(track, getUsername().toInt()) })
.map { remoteTrack -> .map { remoteTrack ->
track.copyPersonalFrom(remoteTrack) track.copyPersonalFrom(remoteTrack)
track.total_chapters = remoteTrack.total_chapters track.total_chapters = remoteTrack.total_chapters
@ -184,7 +185,7 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
fun login(token: String): Completable { fun login(token: String): Completable {
val oauth = api.createOAuth(token) val oauth = api.createOAuth(token)
interceptor.setAuth(oauth) interceptor.setAuth(oauth)
return api.getCurrentUser().map { (username, scoreType) -> return runAsObservable({ api.getCurrentUser() }).map { (username, scoreType) ->
scorePreference.set(scoreType) scorePreference.set(scoreType)
saveCredentials(username.toString(), oauth.access_token) saveCredentials(username.toString(), oauth.access_token)
}.doOnError { }.doOnError {

View file

@ -5,7 +5,7 @@ import androidx.core.net.toUri
import eu.kanade.tachiyomi.data.database.models.Track 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.asObservableSuccess import eu.kanade.tachiyomi.network.await
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
@ -22,7 +22,6 @@ import kotlinx.serialization.json.putJsonObject
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 rx.Observable
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Calendar import java.util.Calendar
@ -33,7 +32,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
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()
fun addLibManga(track: Track): Observable<Track> { suspend fun addLibManga(track: Track): Track {
val query = val query =
""" """
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
@ -51,22 +50,18 @@ 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))) return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use {
.asObservableSuccess() val responseBody = it.body?.string().orEmpty()
.map { netResponse -> if (responseBody.isEmpty()) {
netResponse.use { throw Exception("Null Response")
val responseBody = it.body?.string().orEmpty()
if (responseBody.isEmpty()) {
throw Exception("Null Response")
}
val response = json.decodeFromString<JsonObject>(responseBody)
track.library_id = response["data"]!!.jsonObject["SaveMediaListEntry"]!!.jsonObject["id"]!!.jsonPrimitive.long
track
}
} }
val response = json.decodeFromString<JsonObject>(responseBody)
track.library_id = response["data"]!!.jsonObject["SaveMediaListEntry"]!!.jsonObject["id"]!!.jsonPrimitive.long
track
}
} }
fun updateLibManga(track: Track): Observable<Track> { suspend fun updateLibManga(track: Track): Track {
val query = val query =
""" """
|mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) { |mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
@ -86,14 +81,11 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("score", track.score.toInt()) put("score", track.score.toInt())
} }
} }
return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))) authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await()
.asObservableSuccess() return track
.map {
track
}
} }
fun search(search: String): Observable<List<TrackSearch>> { suspend fun search(search: String): List<TrackSearch> {
val query = val query =
""" """
|query Search(${'$'}query: String) { |query Search(${'$'}query: String) {
@ -125,25 +117,21 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("query", search) put("query", search)
} }
} }
return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))) return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use {
.asObservableSuccess() val responseBody = it.body?.string().orEmpty()
.map { netResponse -> if (responseBody.isEmpty()) {
netResponse.use { throw Exception("Null Response")
val responseBody = it.body?.string().orEmpty()
if (responseBody.isEmpty()) {
throw Exception("Null Response")
}
val response = json.decodeFromString<JsonObject>(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() }
}
} }
val response = json.decodeFromString<JsonObject>(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() }
}
} }
fun findLibManga(track: Track, userid: Int): Observable<Track?> { suspend fun findLibManga(track: Track, userid: Int): Track? {
val query = val query =
""" """
|query (${'$'}id: Int!, ${'$'}manga_id: Int!) { |query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
@ -182,34 +170,29 @@ 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))) return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use {
.asObservableSuccess() val responseBody = it.body?.string().orEmpty()
.map { netResponse -> if (responseBody.isEmpty()) {
netResponse.use { throw Exception("Null Response")
val responseBody = it.body?.string().orEmpty()
if (responseBody.isEmpty()) {
throw Exception("Null Response")
}
val response = json.decodeFromString<JsonObject>(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()
}
} }
val response = json.decodeFromString<JsonObject>(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()
}
} }
fun getLibManga(track: Track, userid: Int): Observable<Track> { suspend fun getLibManga(track: Track, userid: Int): Track {
return findLibManga(track, userid) return findLibManga(track, userid) ?: throw Exception("Could not find manga")
.map { it ?: throw Exception("Could not find manga") }
} }
fun createOAuth(token: String): OAuth { fun createOAuth(token: String): OAuth {
return OAuth(token, "Bearer", System.currentTimeMillis() + 31536000000, 31536000000) return OAuth(token, "Bearer", System.currentTimeMillis() + 31536000000, 31536000000)
} }
fun getCurrentUser(): Observable<Pair<Int, String>> { suspend fun getCurrentUser(): Pair<Int, String> {
val query = val query =
""" """
|query User { |query User {
@ -224,23 +207,19 @@ 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))) return authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))).await().use {
.asObservableSuccess() val responseBody = it.body?.string().orEmpty()
.map { netResponse -> if (responseBody.isEmpty()) {
netResponse.use { throw Exception("Null Response")
val responseBody = it.body?.string().orEmpty()
if (responseBody.isEmpty()) {
throw Exception("Null Response")
}
val response = json.decodeFromString<JsonObject>(responseBody)
val data = response["data"]!!.jsonObject
val viewer = data["Viewer"]!!.jsonObject
Pair(
viewer["id"]!!.jsonPrimitive.int,
viewer["mediaListOptions"]!!.jsonObject["scoreFormat"]!!.jsonPrimitive.content
)
}
} }
val response = json.decodeFromString<JsonObject>(responseBody)
val data = response["data"]!!.jsonObject
val viewer = data["Viewer"]!!.jsonObject
Pair(
viewer["id"]!!.jsonPrimitive.int,
viewer["mediaListOptions"]!!.jsonObject["scoreFormat"]!!.jsonPrimitive.content
)
}
} }
private fun jsonToALManga(struct: JsonObject): ALManga { private fun jsonToALManga(struct: JsonObject): ALManga {