Browse Source

OkHttp Call: split await() and awaitSuccess() (#8980)

stevenyomi 2 năm trước cách đây
mục cha
commit
448702e5be

+ 6 - 6
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt

@@ -5,7 +5,7 @@ import androidx.core.net.toUri
 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 eu.kanade.tachiyomi.network.awaitSuccess
 import eu.kanade.tachiyomi.network.interceptor.rateLimit
 import eu.kanade.tachiyomi.network.jsonMime
 import eu.kanade.tachiyomi.network.parseAs
@@ -59,7 +59,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
                     body = payload.toString().toRequestBody(jsonMime),
                 ),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     track.library_id =
@@ -99,7 +99,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
                 }
             }
             authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime)))
-                .await()
+                .awaitSuccess()
             track
         }
     }
@@ -143,7 +143,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
                     body = payload.toString().toRequestBody(jsonMime),
                 ),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let { response ->
                     val data = response["data"]!!.jsonObject
@@ -211,7 +211,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
                     body = payload.toString().toRequestBody(jsonMime),
                 ),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let { response ->
                     val data = response["data"]!!.jsonObject
@@ -253,7 +253,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
                     body = payload.toString().toRequestBody(jsonMime),
                 ),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     val data = it["data"]!!.jsonObject

+ 8 - 8
app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt

@@ -7,7 +7,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
 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.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.lang.withIOContext
 import kotlinx.serialization.decodeFromString
@@ -40,7 +40,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
                 .add("status", track.toBangumiStatus())
                 .build()
             authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = body))
-                .await()
+                .awaitSuccess()
             track
         }
     }
@@ -53,7 +53,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
                 .add("status", track.toBangumiStatus())
                 .build()
             authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = sbody))
-                .await()
+                .awaitSuccess()
 
             // chapter update
             val body = FormBody.Builder()
@@ -64,7 +64,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
                     "$apiUrl/subject/${track.media_id}/update/watched_eps",
                     body = body,
                 ),
-            ).await()
+            ).awaitSuccess()
 
             track
         }
@@ -78,7 +78,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
                 .appendQueryParameter("max_results", "20")
                 .build()
             authClient.newCall(GET(url.toString()))
-                .await()
+                .awaitSuccess()
                 .use {
                     var responseBody = it.body.string()
                     if (responseBody.isEmpty()) {
@@ -119,7 +119,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
     suspend fun findLibManga(track: Track): Track? {
         return withIOContext {
             authClient.newCall(GET("$apiUrl/subject/${track.media_id}"))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let { jsonToSearch(it) }
         }
@@ -135,7 +135,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
                 .build()
 
             // TODO: get user readed chapter here
-            val response = authClient.newCall(requestUserRead).await()
+            val response = authClient.newCall(requestUserRead).awaitSuccess()
             val responseBody = response.body.string()
             if (responseBody.isEmpty()) {
                 throw Exception("Null Response")
@@ -156,7 +156,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
     suspend fun accessToken(code: String): OAuth {
         return withIOContext {
             client.newCall(accessTokenRequest(code))
-                .await()
+                .awaitSuccess()
                 .parseAs()
         }
     }

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt

@@ -4,7 +4,7 @@ import eu.kanade.tachiyomi.data.database.models.Track
 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.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.lang.withIOContext
 import eu.kanade.tachiyomi.util.system.logcat
@@ -128,7 +128,7 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
     suspend fun getTrackSearch(url: String): TrackSearch = withIOContext {
         try {
             val serieDto: SeriesDto = authClient.newCall(GET(url))
-                .await()
+                .awaitSuccess()
                 .parseAs()
 
             val track = serieDto.toTrack()
@@ -154,7 +154,7 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
     suspend fun updateProgress(track: Track): Track {
         val requestUrl = "${getApiFromUrl(track.tracking_url)}/Tachiyomi/mark-chapter-until-as-read?seriesId=${getIdFromUrl(track.tracking_url)}&chapterNumber=${track.last_chapter_read}"
         authClient.newCall(POST(requestUrl, body = "{}".toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())))
-            .await()
+            .awaitSuccess()
         return getTrackSearch(track.tracking_url)
     }
 }

+ 9 - 9
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt

@@ -5,7 +5,7 @@ import eu.kanade.tachiyomi.data.database.models.Track
 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.awaitSuccess
 import eu.kanade.tachiyomi.network.jsonMime
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.lang.withIOContext
@@ -67,7 +67,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
                     body = data.toString().toRequestBody("application/vnd.api+json".toMediaType()),
                 ),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     track.media_id = it["data"]!!.jsonObject["id"]!!.jsonPrimitive.long
@@ -104,7 +104,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
                     .patch(data.toString().toRequestBody("application/vnd.api+json".toMediaType()))
                     .build(),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     track
@@ -115,7 +115,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
     suspend fun search(query: String): List<TrackSearch> {
         return withIOContext {
             authClient.newCall(GET(algoliaKeyUrl))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     val key = it["media"]!!.jsonObject["key"]!!.jsonPrimitive.content
@@ -142,7 +142,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
                     body = jsonObject.toString().toRequestBody(jsonMime),
                 ),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     it["hits"]!!.jsonArray
@@ -160,7 +160,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
                 .appendQueryParameter("include", "manga")
                 .build()
             authClient.newCall(GET(url.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     val data = it["data"]!!.jsonArray
@@ -181,7 +181,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
                 .appendQueryParameter("include", "manga")
                 .build()
             authClient.newCall(GET(url.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     val data = it["data"]!!.jsonArray
@@ -205,7 +205,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
                 .add("client_secret", clientSecret)
                 .build()
             client.newCall(POST(loginUrl, body = formBody))
-                .await()
+                .awaitSuccess()
                 .parseAs()
         }
     }
@@ -216,7 +216,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
                 .encodedQuery("filter[self]=true")
                 .build()
             authClient.newCall(GET(url.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     it["data"]!!.jsonArray[0].jsonObject["id"]!!.jsonPrimitive.content

+ 5 - 5
app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt

@@ -4,7 +4,7 @@ import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.TrackManager
 import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import eu.kanade.tachiyomi.network.GET
-import eu.kanade.tachiyomi.network.await
+import eu.kanade.tachiyomi.network.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.lang.withIOContext
 import eu.kanade.tachiyomi.util.system.logcat
@@ -28,19 +28,19 @@ class KomgaApi(private val client: OkHttpClient) {
             try {
                 val track = if (url.contains(READLIST_API)) {
                     client.newCall(GET(url))
-                        .await()
+                        .awaitSuccess()
                         .parseAs<ReadListDto>()
                         .toTrack()
                 } else {
                     client.newCall(GET(url))
-                        .await()
+                        .awaitSuccess()
                         .parseAs<SeriesDto>()
                         .toTrack()
                 }
 
                 val progress = client
                     .newCall(GET("${url.replace("/api/v1/series/", "/api/v2/series/")}/read-progress/tachiyomi"))
-                    .await().let {
+                    .awaitSuccess().let {
                         if (url.contains("/api/v1/series/")) {
                             it.parseAs<ReadProgressV2Dto>()
                         } else {
@@ -77,7 +77,7 @@ class KomgaApi(private val client: OkHttpClient) {
                 .put(payload.toRequestBody("application/json".toMediaType()))
                 .build(),
         )
-            .await()
+            .awaitSuccess()
         return getTrackSearch(track.tracking_url)
     }
 

+ 9 - 9
app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt

@@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.network.DELETE
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.network.POST
 import eu.kanade.tachiyomi.network.PUT
-import eu.kanade.tachiyomi.network.await
+import eu.kanade.tachiyomi.network.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.system.logcat
 import kotlinx.serialization.json.Json
@@ -53,7 +53,7 @@ class MangaUpdatesApi(
                     url = "$baseUrl/v1/lists/series/${track.media_id}",
                 ),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<ListItem>()
 
         val rating = getSeriesRating(track)
@@ -77,7 +77,7 @@ class MangaUpdatesApi(
                 body = body.toString().toRequestBody(contentType),
             ),
         )
-            .await()
+            .awaitSuccess()
             .let {
                 if (it.code == 200) {
                     track.status = status
@@ -104,7 +104,7 @@ class MangaUpdatesApi(
                 body = body.toString().toRequestBody(contentType),
             ),
         )
-            .await()
+            .awaitSuccess()
 
         updateSeriesRating(track)
     }
@@ -116,7 +116,7 @@ class MangaUpdatesApi(
                     url = "$baseUrl/v1/series/${track.media_id}/rating",
                 ),
             )
-                .await()
+                .awaitSuccess()
                 .parseAs<Rating>()
         } catch (e: Exception) {
             null
@@ -134,14 +134,14 @@ class MangaUpdatesApi(
                     body = body.toString().toRequestBody(contentType),
                 ),
             )
-                .await()
+                .awaitSuccess()
         } else {
             authClient.newCall(
                 DELETE(
                     url = "$baseUrl/v1/series/${track.media_id}/rating",
                 ),
             )
-                .await()
+                .awaitSuccess()
         }
     }
 
@@ -162,7 +162,7 @@ class MangaUpdatesApi(
                 body = body.toString().toRequestBody(contentType),
             ),
         )
-            .await()
+            .awaitSuccess()
             .parseAs<JsonObject>()
             .let { obj ->
                 obj["results"]?.jsonArray?.map { element ->
@@ -183,7 +183,7 @@ class MangaUpdatesApi(
                 body = body.toString().toRequestBody(contentType),
             ),
         )
-            .await()
+            .awaitSuccess()
             .parseAs<JsonObject>()
             .let { obj ->
                 try {

+ 8 - 8
app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt

@@ -7,7 +7,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
 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.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.PkceUtil
 import eu.kanade.tachiyomi.util.lang.withIOContext
@@ -43,7 +43,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
                 .add("grant_type", "authorization_code")
                 .build()
             client.newCall(POST("$baseOAuthUrl/token", body = formBody))
-                .await()
+                .awaitSuccess()
                 .parseAs()
         }
     }
@@ -55,7 +55,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
                 .get()
                 .build()
             authClient.newCall(request)
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let { it["name"]!!.jsonPrimitive.content }
         }
@@ -69,7 +69,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
                 .appendQueryParameter("nsfw", "true")
                 .build()
             authClient.newCall(GET(url.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     it["data"]!!.jsonArray
@@ -91,7 +91,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
                 .appendQueryParameter("fields", "id,title,synopsis,num_chapters,main_picture,status,media_type,start_date")
                 .build()
             authClient.newCall(GET(url.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let {
                     val obj = it.jsonObject
@@ -134,7 +134,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
                 .put(formBodyBuilder.build())
                 .build()
             authClient.newCall(request)
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let { parseMangaItem(it, track) }
         }
@@ -147,7 +147,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
                 .appendQueryParameter("fields", "num_chapters,my_list_status{start_date,finish_date}")
                 .build()
             authClient.newCall(GET(uri.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
                 .let { obj ->
                     track.total_chapters = obj["num_chapters"]!!.jsonPrimitive.int
@@ -199,7 +199,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
                 .get()
                 .build()
             authClient.newCall(request)
-                .await()
+                .awaitSuccess()
                 .parseAs()
         }
     }

+ 7 - 7
app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt

@@ -6,7 +6,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
 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.awaitSuccess
 import eu.kanade.tachiyomi.network.jsonMime
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.lang.withIOContext
@@ -46,7 +46,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
                     "$apiUrl/v2/user_rates",
                     body = payload.toString().toRequestBody(jsonMime),
                 ),
-            ).await()
+            ).awaitSuccess()
             track
         }
     }
@@ -61,7 +61,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
                 .appendQueryParameter("limit", "20")
                 .build()
             authClient.newCall(GET(url.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonArray>()
                 .let { response ->
                     response.map {
@@ -103,7 +103,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
                 .appendPath(track.media_id.toString())
                 .build()
             val mangas = authClient.newCall(GET(urlMangas.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonObject>()
 
             val url = "$apiUrl/v2/user_rates".toUri().buildUpon()
@@ -112,7 +112,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
                 .appendQueryParameter("target_type", "Manga")
                 .build()
             authClient.newCall(GET(url.toString()))
-                .await()
+                .awaitSuccess()
                 .parseAs<JsonArray>()
                 .let { response ->
                     if (response.size > 1) {
@@ -128,7 +128,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
 
     suspend fun getCurrentUser(): Int {
         return authClient.newCall(GET("$apiUrl/users/whoami"))
-            .await()
+            .awaitSuccess()
             .parseAs<JsonObject>()
             .let {
                 it["id"]!!.jsonPrimitive.int
@@ -138,7 +138,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
     suspend fun accessToken(code: String): OAuth {
         return withIOContext {
             client.newCall(accessTokenRequest(code))
-                .await()
+                .awaitSuccess()
                 .parseAs()
         }
     }

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/TachideskApi.kt

@@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.network.NetworkHelper
 import eu.kanade.tachiyomi.network.PUT
-import eu.kanade.tachiyomi.network.await
+import eu.kanade.tachiyomi.network.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.lang.withIOContext
 import okhttp3.Credentials
@@ -50,7 +50,7 @@ class TachideskApi {
             trackUrl
         }
 
-        val manga = client.newCall(GET("$url/full", headers)).await().parseAs<MangaDataClass>()
+        val manga = client.newCall(GET("$url/full", headers)).awaitSuccess().parseAs<MangaDataClass>()
 
         TrackSearch.create(TrackManager.SUWAYOMI).apply {
             title = manga.title
@@ -70,7 +70,7 @@ class TachideskApi {
 
     suspend fun updateProgress(track: Track): Track {
         val url = track.tracking_url
-        val chapters = client.newCall(GET("$url/chapters", headers)).await().parseAs<List<ChapterDataClass>>()
+        val chapters = client.newCall(GET("$url/chapters", headers)).awaitSuccess().parseAs<List<ChapterDataClass>>()
         val lastChapterIndex = chapters.first { it.chapterNumber == track.last_chapter_read }.index
 
         client.newCall(
@@ -82,7 +82,7 @@ class TachideskApi {
                     .add("read", "true")
                     .build(),
             ),
-        ).await()
+        ).awaitSuccess()
 
         return getTrackSearch(track.tracking_url)
     }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt

@@ -6,7 +6,7 @@ import eu.kanade.tachiyomi.core.preference.Preference
 import eu.kanade.tachiyomi.core.preference.PreferenceStore
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.network.NetworkHelper
-import eu.kanade.tachiyomi.network.await
+import eu.kanade.tachiyomi.network.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.lang.withIOContext
 import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid
@@ -31,7 +31,7 @@ class AppUpdateChecker {
         return withIOContext {
             val result = networkService.client
                 .newCall(GET("https://api.github.com/repos/$GITHUB_REPO/releases/latest"))
-                .await()
+                .awaitSuccess()
                 .parseAs<GithubRelease>()
                 .let {
                     lastAppCheck.set(Date().time)

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt

@@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.extension.model.LoadResult
 import eu.kanade.tachiyomi.extension.util.ExtensionLoader
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.network.NetworkHelper
-import eu.kanade.tachiyomi.network.await
+import eu.kanade.tachiyomi.network.awaitSuccess
 import eu.kanade.tachiyomi.network.parseAs
 import eu.kanade.tachiyomi.util.lang.withIOContext
 import eu.kanade.tachiyomi.util.system.logcat
@@ -39,7 +39,7 @@ internal class ExtensionGithubApi {
                 try {
                     networkService.client
                         .newCall(GET("${REPO_URL_PREFIX}index.min.json"))
-                        .await()
+                        .awaitSuccess()
                 } catch (e: Throwable) {
                     logcat(LogPriority.ERROR, e) { "Failed to get extensions from GitHub" }
                     requiresFallbackSource = true
@@ -50,7 +50,7 @@ internal class ExtensionGithubApi {
             val response = githubResponse ?: run {
                 networkService.client
                     .newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
-                    .await()
+                    .awaitSuccess()
             }
 
             val extensions = response

+ 22 - 11
core/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt

@@ -65,16 +65,11 @@ fun Call.asObservable(): Observable<Response> {
 
 // Based on https://github.com/gildor/kotlin-coroutines-okhttp
 @OptIn(ExperimentalCoroutinesApi::class)
-suspend fun Call.await(): Response {
+private suspend fun Call.await(callStack: Array<StackTraceElement>): Response {
     return suspendCancellableCoroutine { continuation ->
-        enqueue(
+        val callback =
             object : Callback {
                 override fun onResponse(call: Call, response: Response) {
-                    if (!response.isSuccessful) {
-                        continuation.resumeWithException(HttpException(response.code))
-                        return
-                    }
-
                     continuation.resume(response) {
                         response.body.close()
                     }
@@ -83,11 +78,12 @@ suspend fun Call.await(): Response {
                 override fun onFailure(call: Call, e: IOException) {
                     // Don't bother with resuming the continuation if it is already cancelled.
                     if (continuation.isCancelled) return
-
-                    continuation.resumeWithException(e)
+                    val exception = IOException(e).apply { stackTrace = callStack }
+                    continuation.resumeWithException(exception)
                 }
-            },
-        )
+            }
+
+        enqueue(callback)
 
         continuation.invokeOnCancellation {
             try {
@@ -99,6 +95,21 @@ suspend fun Call.await(): Response {
     }
 }
 
+suspend fun Call.await(): Response {
+    val callStack = Exception().stackTrace.run { copyOfRange(1, size) }
+    return await(callStack)
+}
+
+suspend fun Call.awaitSuccess(): Response {
+    val callStack = Exception().stackTrace.run { copyOfRange(1, size) }
+    val response = await(callStack)
+    if (!response.isSuccessful) {
+        response.close()
+        throw HttpException(response.code).apply { stackTrace = callStack }
+    }
+    return response
+}
+
 fun Call.asObservableSuccess(): Observable<Response> {
     return asObservable().doOnNext { response ->
         if (!response.isSuccessful) {