refactor: Don't use context receiver

Deprecated on Kotlin 2.x, scheduled for removal in v2.1.x, will be replaced with context parameters

REF: https://github.com/Kotlin/KEEP/issues/259#issuecomment-2278319746
REF: https://youtrack.jetbrains.com/issue/KT-67119/Migration-warning-from-context-receivers-to-context-parameters
REF: https://github.com/Kotlin/KEEP/issues/367
This commit is contained in:
Ahmad Ansori Palembani 2025-01-01 07:10:30 +07:00
parent 1b92ae2e5f
commit d02f1bdd11
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
17 changed files with 265 additions and 347 deletions

View file

@ -278,7 +278,6 @@ tasks {
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
withType<KotlinCompile> { withType<KotlinCompile> {
compilerOptions.freeCompilerArgs.addAll( compilerOptions.freeCompilerArgs.addAll(
"-Xcontext-receivers",
// "-opt-in=kotlin.Experimental", // "-opt-in=kotlin.Experimental",
"-opt-in=kotlin.RequiresOptIn", "-opt-in=kotlin.RequiresOptIn",
"-opt-in=kotlin.ExperimentalStdlibApi", "-opt-in=kotlin.ExperimentalStdlibApi",

View file

@ -49,7 +49,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("completedAt", createDate(track.finished_reading_date)) put("completedAt", createDate(track.finished_reading_date))
} }
} }
with(json) {
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime))) authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
.awaitSuccess() .awaitSuccess()
.parseAs<ALAddMangaResult>() .parseAs<ALAddMangaResult>()
@ -59,7 +58,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
} }
} }
} }
}
suspend fun updateLibraryManga(track: Track): Track { suspend fun updateLibraryManga(track: Track): Track {
return withIOContext { return withIOContext {
@ -74,13 +72,11 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("completedAt", createDate(track.finished_reading_date)) put("completedAt", createDate(track.finished_reading_date))
} }
} }
with(json) {
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime))) authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
.awaitSuccess() .awaitSuccess()
track track
} }
} }
}
suspend fun search(search: String): List<TrackSearch> { suspend fun search(search: String): List<TrackSearch> {
return withIOContext { return withIOContext {
@ -90,7 +86,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("query", search) put("query", search)
} }
} }
with(json) {
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime))) authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
.awaitSuccess() .awaitSuccess()
.parseAs<ALSearchResult>() .parseAs<ALSearchResult>()
@ -98,7 +93,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
.map { it.toALManga().toTrack() } .map { it.toALManga().toTrack() }
} }
} }
}
suspend fun findLibManga(track: Track, userid: Int): Track? { suspend fun findLibManga(track: Track, userid: Int): Track? {
return withIOContext { return withIOContext {
@ -109,7 +103,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
put("manga_id", track.media_id) put("manga_id", track.media_id)
} }
} }
with(json) {
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime))) authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
.awaitSuccess() .awaitSuccess()
.parseAs<ALUserListMangaQueryResult>() .parseAs<ALUserListMangaQueryResult>()
@ -119,7 +112,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
?.toTrack() ?.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")

View file

@ -75,7 +75,6 @@ class BangumiApi(
.appendQueryParameter("responseGroup", "large") .appendQueryParameter("responseGroup", "large")
.appendQueryParameter("max_results", "20") .appendQueryParameter("max_results", "20")
.build() .build()
with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<BGMSearchResult>() .parseAs<BGMSearchResult>()
@ -88,18 +87,15 @@ class BangumiApi(
} }
} }
} }
}
suspend fun findLibManga(track: Track): Track? { suspend fun findLibManga(track: Track): Track? {
return withIOContext { return withIOContext {
with(json) {
authClient.newCall(GET("$API_URL/subject/${track.media_id}")) authClient.newCall(GET("$API_URL/subject/${track.media_id}"))
.awaitSuccess() .awaitSuccess()
.parseAs<BGMSearchItem>() .parseAs<BGMSearchItem>()
.toTrackSearch(trackId) .toTrackSearch(trackId)
} }
} }
}
suspend fun statusLibManga(track: Track): Track? { suspend fun statusLibManga(track: Track): Track? {
return withIOContext { return withIOContext {
@ -111,7 +107,6 @@ class BangumiApi(
.build() .build()
// TODO: get user readed chapter here // TODO: get user readed chapter here
with(json) {
authClient.newCall(requestUserRead) authClient.newCall(requestUserRead)
.awaitSuccess() .awaitSuccess()
.parseAs<BGMCollectionResponse>() .parseAs<BGMCollectionResponse>()
@ -125,17 +120,14 @@ class BangumiApi(
} }
} }
} }
}
suspend fun accessToken(code: String): BGMOAuth { suspend fun accessToken(code: String): BGMOAuth {
return withIOContext { return withIOContext {
with(json) {
client.newCall(accessTokenRequest(code)) client.newCall(accessTokenRequest(code))
.awaitSuccess() .awaitSuccess()
.parseAs() .parseAs()
} }
} }
}
private fun accessTokenRequest(code: String) = POST( private fun accessTokenRequest(code: String) = POST(
OAUTH_URL, OAUTH_URL,

View file

@ -44,7 +44,7 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
try { try {
client.newCall(request).execute().use { client.newCall(request).execute().use {
when (it.code) { when (it.code) {
200 -> return with(json) { it.parseAs<AuthenticationDto>().token } 200 -> return it.parseAs<AuthenticationDto>().token
401 -> { 401 -> {
Logger.w { "Unauthorized / api key not valid: Cleaned api URL: $apiUrl, Api key is empty: ${apiKey.isEmpty()}" } Logger.w { "Unauthorized / api key not valid: Cleaned api URL: $apiUrl, Api key is empty: ${apiKey.isEmpty()}" }
throw IOException("Unauthorized / api key not valid") throw IOException("Unauthorized / api key not valid")
@ -89,11 +89,10 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
private fun getTotalChapters(url: String): Long { private fun getTotalChapters(url: String): Long {
val requestUrl = getApiVolumesUrl(url) val requestUrl = getApiVolumesUrl(url)
try { try {
val listVolumeDto = with(json) { val listVolumeDto =
authClient.newCall(GET(requestUrl)) authClient.newCall(GET(requestUrl))
.execute() .execute()
.parseAs<List<VolumeDto>>() .parseAs<List<VolumeDto>>()
}
var volumeNumber = 0L var volumeNumber = 0L
var maxChapterNumber = 0L var maxChapterNumber = 0L
for (volume in listVolumeDto) { for (volume in listVolumeDto) {
@ -117,9 +116,7 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
try { try {
authClient.newCall(GET(requestUrl)).execute().use { authClient.newCall(GET(requestUrl)).execute().use {
if (it.code == 200) { if (it.code == 200) {
return with(json) { return it.parseAs<ChapterDto>().number!!.replace(",", ".").toFloat()
it.parseAs<ChapterDto>().number!!.replace(",", ".").toFloat()
}
} }
if (it.code == 204) { if (it.code == 204) {
return 0F return 0F
@ -134,11 +131,10 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
suspend fun getTrackSearch(url: String): TrackSearch = withIOContext { suspend fun getTrackSearch(url: String): TrackSearch = withIOContext {
try { try {
val serieDto: SeriesDto = with(json) { val serieDto: SeriesDto =
authClient.newCall(GET(url)) authClient.newCall(GET(url))
.awaitSuccess() .awaitSuccess()
.parseAs() .parseAs()
}
val track = serieDto.toTrack() val track = serieDto.toTrack()
track.apply { track.apply {

View file

@ -131,7 +131,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
suspend fun search(query: String): List<TrackSearch> { suspend fun search(query: String): List<TrackSearch> {
return withIOContext { return withIOContext {
with(json) {
authClient.newCall(GET(ALGOLIA_KEY_URL)) authClient.newCall(GET(ALGOLIA_KEY_URL))
.awaitSuccess() .awaitSuccess()
.parseAs<KitsuSearchResult>() .parseAs<KitsuSearchResult>()
@ -140,14 +139,12 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
} }
} }
} }
}
private suspend fun algoliaSearch(key: String, query: String): List<TrackSearch> { private suspend fun algoliaSearch(key: String, query: String): List<TrackSearch> {
return withIOContext { return withIOContext {
val jsonObject = buildJsonObject { val jsonObject = buildJsonObject {
put("params", "query=$query$ALGOLIA_FILTER") put("params", "query=$query$ALGOLIA_FILTER")
} }
with(json) {
client.newCall( client.newCall(
POST( POST(
ALGOLIA_URL, ALGOLIA_URL,
@ -167,7 +164,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
.map { it.toTrack() } .map { it.toTrack() }
} }
} }
}
suspend fun findLibManga(track: Track, userId: String): Track? { suspend fun findLibManga(track: Track, userId: String): Track? {
return withIOContext { return withIOContext {
@ -175,7 +171,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
.encodedQuery("filter[manga_id]=${track.media_id}&filter[user_id]=$userId") .encodedQuery("filter[manga_id]=${track.media_id}&filter[user_id]=$userId")
.appendQueryParameter("include", "manga") .appendQueryParameter("include", "manga")
.build() .build()
with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<KitsuListSearchResult>() .parseAs<KitsuListSearchResult>()
@ -188,7 +183,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
} }
} }
} }
}
suspend fun getLibManga(track: Track): Track { suspend fun getLibManga(track: Track): Track {
return withIOContext { return withIOContext {
@ -196,7 +190,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
.encodedQuery("filter[id]=${track.media_id}") .encodedQuery("filter[id]=${track.media_id}")
.appendQueryParameter("include", "manga") .appendQueryParameter("include", "manga")
.build() .build()
with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<KitsuListSearchResult>() .parseAs<KitsuListSearchResult>()
@ -209,7 +202,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
} }
} }
} }
}
suspend fun login(username: String, password: String): KitsuOAuth { suspend fun login(username: String, password: String): KitsuOAuth {
return withIOContext { return withIOContext {
@ -220,20 +212,17 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
.add("client_id", CLIENT_ID) .add("client_id", CLIENT_ID)
.add("client_secret", CLIENT_SECRET) .add("client_secret", CLIENT_SECRET)
.build() .build()
with(json) {
client.newCall(POST(LOGIN_URL, body = formBody)) client.newCall(POST(LOGIN_URL, body = formBody))
.awaitSuccess() .awaitSuccess()
.parseAs() .parseAs()
} }
} }
}
suspend fun getCurrentUser(): String { suspend fun getCurrentUser(): String {
return withIOContext { return withIOContext {
val url = "${BASE_URL}users".toUri().buildUpon() val url = "${BASE_URL}users".toUri().buildUpon()
.encodedQuery("filter[self]=true") .encodedQuery("filter[self]=true")
.build() .build()
with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<KitsuCurrentUserResult>() .parseAs<KitsuCurrentUserResult>()
@ -241,7 +230,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
.id .id
} }
} }
}
companion object { companion object {
private const val CLIENT_ID = private const val CLIENT_ID =

View file

@ -26,7 +26,6 @@ class KomgaApi(private val client: OkHttpClient) {
withIOContext { withIOContext {
try { try {
val track = val track =
with(json) {
if (url.contains(READLIST_API)) { if (url.contains(READLIST_API)) {
client.newCall(GET(url)) client.newCall(GET(url))
.awaitSuccess() .awaitSuccess()
@ -38,9 +37,8 @@ class KomgaApi(private val client: OkHttpClient) {
.parseAs<SeriesDto>() .parseAs<SeriesDto>()
.toTrack() .toTrack()
} }
}
val progress = with(json) { val progress =
client client
.newCall( .newCall(
GET( GET(
@ -59,7 +57,6 @@ class KomgaApi(private val client: OkHttpClient) {
it.parseAs<ReadProgressDto>().toV2() it.parseAs<ReadProgressDto>().toV2()
} }
} }
}
track.apply { track.apply {
cover_url = "$url/thumbnail" cover_url = "$url/thumbnail"
tracking_url = url tracking_url = url

View file

@ -37,7 +37,6 @@ class MangaUpdatesApi(
suspend fun getSeriesListItem(track: Track): Pair<MUListItem, MURating?> { suspend fun getSeriesListItem(track: Track): Pair<MUListItem, MURating?> {
val listItem = val listItem =
with(json) {
authClient.newCall( authClient.newCall(
GET( GET(
url = "$BASE_URL/v1/lists/series/${track.media_id}", url = "$BASE_URL/v1/lists/series/${track.media_id}",
@ -45,7 +44,6 @@ class MangaUpdatesApi(
) )
.awaitSuccess() .awaitSuccess()
.parseAs<MUListItem>() .parseAs<MUListItem>()
}
val rating = getSeriesRating(track) val rating = getSeriesRating(track)
@ -104,7 +102,6 @@ class MangaUpdatesApi(
private suspend fun getSeriesRating(track: Track): MURating? { private suspend fun getSeriesRating(track: Track): MURating? {
return try { return try {
with(json) {
authClient.newCall( authClient.newCall(
GET( GET(
url = "$BASE_URL/v1/series/${track.media_id}/rating", url = "$BASE_URL/v1/series/${track.media_id}/rating",
@ -112,7 +109,6 @@ class MangaUpdatesApi(
) )
.awaitSuccess() .awaitSuccess()
.parseAs<MURating>() .parseAs<MURating>()
}
} catch (e: Exception) { } catch (e: Exception) {
null null
} }
@ -151,8 +147,7 @@ class MangaUpdatesApi(
}, },
) )
} }
return with(json) { return client.newCall(
client.newCall(
POST( POST(
url = "$BASE_URL/v1/series/search", url = "$BASE_URL/v1/series/search",
body = body.toString().toRequestBody(CONTENT_TYPE), body = body.toString().toRequestBody(CONTENT_TYPE),
@ -163,15 +158,13 @@ class MangaUpdatesApi(
.results .results
.map { it.record } .map { it.record }
} }
}
suspend fun authenticate(username: String, password: String): MUContext? { suspend fun authenticate(username: String, password: String): MUContext? {
val body = buildJsonObject { val body = buildJsonObject {
put("username", username) put("username", username)
put("password", password) put("password", password)
} }
return with(json) { return client.newCall(
client.newCall(
PUT( PUT(
url = "$BASE_URL/v1/account/login", url = "$BASE_URL/v1/account/login",
body = body.toString().toRequestBody(CONTENT_TYPE), body = body.toString().toRequestBody(CONTENT_TYPE),
@ -181,7 +174,6 @@ class MangaUpdatesApi(
.parseAs<MULoginResponse>() .parseAs<MULoginResponse>()
.context .context
} }
}
companion object { companion object {
private const val BASE_URL = "https://api.mangaupdates.com" private const val BASE_URL = "https://api.mangaupdates.com"

View file

@ -45,13 +45,11 @@ 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()
with(json) {
client.newCall(POST("$BASE_OAUTH_URL/token", body = formBody)) client.newCall(POST("$BASE_OAUTH_URL/token", body = formBody))
.awaitSuccess() .awaitSuccess()
.parseAs() .parseAs()
} }
} }
}
suspend fun getCurrentUser(): String { suspend fun getCurrentUser(): String {
return withIOContext { return withIOContext {
@ -59,14 +57,12 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.url("$BASE_API_URL/users/@me") .url("$BASE_API_URL/users/@me")
.get() .get()
.build() .build()
with(json) {
authClient.newCall(request) authClient.newCall(request)
.awaitSuccess() .awaitSuccess()
.parseAs<MALUser>() .parseAs<MALUser>()
.name .name
} }
} }
}
suspend fun search(query: String): List<TrackSearch> { suspend fun search(query: String): List<TrackSearch> {
return withIOContext { return withIOContext {
@ -75,7 +71,6 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.appendQueryParameter("q", query.take(64)) .appendQueryParameter("q", query.take(64))
.appendQueryParameter("nsfw", "true") .appendQueryParameter("nsfw", "true")
.build() .build()
with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<MALSearchResult>() .parseAs<MALSearchResult>()
@ -85,7 +80,6 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.filter { !it.publishing_type.contains("novel") } .filter { !it.publishing_type.contains("novel") }
} }
} }
}
suspend fun getMangaDetails(id: Int): TrackSearch { suspend fun getMangaDetails(id: Int): TrackSearch {
return withIOContext { return withIOContext {
@ -93,7 +87,6 @@ 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()
with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<MALManga>() .parseAs<MALManga>()
@ -112,7 +105,6 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
} }
} }
} }
}
suspend fun updateItem(track: Track): Track { suspend fun updateItem(track: Track): Track {
return withIOContext { return withIOContext {
@ -132,14 +124,12 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.url(mangaUrl(track.media_id).toString()) .url(mangaUrl(track.media_id).toString())
.put(formBodyBuilder.build()) .put(formBodyBuilder.build())
.build() .build()
with(json) {
authClient.newCall(request) authClient.newCall(request)
.awaitSuccess() .awaitSuccess()
.parseAs<MALListItemStatus>() .parseAs<MALListItemStatus>()
.let { parseMangaItem(it, track) } .let { parseMangaItem(it, track) }
} }
} }
}
suspend fun findListItem(track: Track): Track? { suspend fun findListItem(track: Track): Track? {
return withIOContext { return withIOContext {
@ -147,7 +137,6 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.appendPath(track.media_id.toString()) .appendPath(track.media_id.toString())
.appendQueryParameter("fields", "num_chapters,my_list_status{start_date,finish_date}") .appendQueryParameter("fields", "num_chapters,my_list_status{start_date,finish_date}")
.build() .build()
with(json) {
authClient.newCall(GET(uri.toString())) authClient.newCall(GET(uri.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<MALListItem>() .parseAs<MALListItem>()
@ -157,7 +146,6 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
} }
} }
} }
}
suspend fun findListItems(query: String, offset: Int = 0): List<TrackSearch> { suspend fun findListItems(query: String, offset: Int = 0): List<TrackSearch> {
return withIOContext { return withIOContext {
@ -190,13 +178,11 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
.url(urlBuilder.build().toString()) .url(urlBuilder.build().toString())
.get() .get()
.build() .build()
with(json) {
authClient.newCall(request) authClient.newCall(request)
.awaitSuccess() .awaitSuccess()
.parseAs() .parseAs()
} }
} }
}
private fun parseMangaItem(listStatus: MALListItemStatus, track: Track): Track { private fun parseMangaItem(listStatus: MALListItemStatus, track: Track): Track {
return track.apply { return track.apply {

View file

@ -66,7 +66,7 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
return runCatching { return runCatching {
if (response.isSuccessful) { if (response.isSuccessful) {
with(json) { response.parseAs<MALOAuth>() } response.parseAs<MALOAuth>()
} else { } else {
response.close() response.close()
null null

View file

@ -74,14 +74,12 @@ class ShikimoriApi(
.appendQueryParameter("search", search) .appendQueryParameter("search", search)
.appendQueryParameter("limit", "20") .appendQueryParameter("limit", "20")
.build() .build()
with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<List<SMManga>>() .parseAs<List<SMManga>>()
.map { it.toTrack(trackId) } .map { it.toTrack(trackId) }
} }
} }
}
suspend fun remove(track: Track): Boolean { suspend fun remove(track: Track): Boolean {
return try { return try {
@ -102,18 +100,16 @@ class ShikimoriApi(
val urlMangas = "$API_URL/mangas".toUri().buildUpon() val urlMangas = "$API_URL/mangas".toUri().buildUpon()
.appendPath(track.media_id.toString()) .appendPath(track.media_id.toString())
.build() .build()
val manga = with(json) { val manga =
authClient.newCall(GET(urlMangas.toString())) authClient.newCall(GET(urlMangas.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<SMManga>() .parseAs<SMManga>()
}
val url = "$API_URL/v2/user_rates".toUri().buildUpon() val url = "$API_URL/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()
with(json) {
authClient.newCall(GET(url.toString())) authClient.newCall(GET(url.toString()))
.execute() .execute()
.parseAs<List<SMUserListEntry>>() .parseAs<List<SMUserListEntry>>()
@ -127,28 +123,23 @@ class ShikimoriApi(
} }
} }
} }
}
suspend fun getCurrentUser(): Int { suspend fun getCurrentUser(): Int {
return withIOContext { return withIOContext {
with(json) {
authClient.newCall(GET("$API_URL/users/whoami")) authClient.newCall(GET("$API_URL/users/whoami"))
.awaitSuccess() .awaitSuccess()
.parseAs<SMUser>() .parseAs<SMUser>()
.id .id
} }
} }
}
suspend fun accessToken(code: String): SMOAuth { suspend fun accessToken(code: String): SMOAuth {
return withIOContext { return withIOContext {
with(json) {
client.newCall(accessTokenRequest(code)) client.newCall(accessTokenRequest(code))
.awaitSuccess() .awaitSuccess()
.parseAs() .parseAs()
} }
} }
}
private fun accessTokenRequest(code: String) = POST( private fun accessTokenRequest(code: String) = POST(
OAUTH_URL, OAUTH_URL,

View file

@ -52,9 +52,7 @@ class TachideskApi {
trackUrl trackUrl
} }
val manga = with(json) { val manga = client.newCall(GET("$url/full", headers)).awaitSuccess().parseAs<MangaDataClass>()
client.newCall(GET("$url/full", headers)).awaitSuccess().parseAs<MangaDataClass>()
}
TrackSearch.create(TrackManager.SUWAYOMI).apply { TrackSearch.create(TrackManager.SUWAYOMI).apply {
title = manga.title title = manga.title
@ -74,9 +72,7 @@ class TachideskApi {
suspend fun updateProgress(track: Track): Track { suspend fun updateProgress(track: Track): Track {
val url = track.tracking_url val url = track.tracking_url
val chapters = with(json) { val chapters = client.newCall(GET("$url/chapters", headers)).awaitSuccess().parseAs<List<ChapterDataClass>>()
client.newCall(GET("$url/chapters", headers)).awaitSuccess().parseAs<List<ChapterDataClass>>()
}
val lastChapterIndex = chapters.first { it.chapterNumber == track.last_chapter_read }.index val lastChapterIndex = chapters.first { it.chapterNumber == track.last_chapter_read }.index
client.newCall( client.newCall(

View file

@ -11,12 +11,12 @@ import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.util.system.localeContext import eu.kanade.tachiyomi.util.system.localeContext
import eu.kanade.tachiyomi.util.system.withIOContext import eu.kanade.tachiyomi.util.system.withIOContext
import java.util.Date
import java.util.concurrent.TimeUnit
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import yokai.domain.base.models.Version import yokai.domain.base.models.Version
import java.util.*
import java.util.concurrent.*
class AppUpdateChecker( class AppUpdateChecker(
private val json: Json = Injekt.get(), private val json: Json = Injekt.get(),
@ -31,8 +31,7 @@ class AppUpdateChecker(
} }
return withIOContext { return withIOContext {
val result = with(json) { val result = if (preferences.checkForBetas().get()) {
if (preferences.checkForBetas().get()) {
networkService.client networkService.client
.newCall(GET("https://api.github.com/repos/$GITHUB_REPO/releases")) .newCall(GET("https://api.github.com/repos/$GITHUB_REPO/releases"))
.await() .await()
@ -73,7 +72,6 @@ class AppUpdateChecker(
} }
} }
} }
}
if (doExtrasAfterNewUpdate && result is AppUpdateResult.NewUpdate) { if (doExtrasAfterNewUpdate && result is AppUpdateResult.NewUpdate) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
preferences.appShouldAutoUpdate().get() != AppDownloadInstallJob.NEVER preferences.appShouldAutoUpdate().get() != AppDownloadInstallJob.NEVER

View file

@ -14,7 +14,6 @@ import eu.kanade.tachiyomi.util.system.withIOContext
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -24,7 +23,6 @@ import yokai.domain.extension.repo.model.ExtensionRepo
internal class ExtensionApi { internal class ExtensionApi {
private val json: Json by injectLazy()
private val networkService: NetworkHelper by injectLazy() private val networkService: NetworkHelper by injectLazy()
private val getExtensionRepo: GetExtensionRepo by injectLazy() private val getExtensionRepo: GetExtensionRepo by injectLazy()
private val updateExtensionRepo: UpdateExtensionRepo by injectLazy() private val updateExtensionRepo: UpdateExtensionRepo by injectLazy()
@ -47,11 +45,9 @@ internal class ExtensionApi {
.newCall(GET("$repoBaseUrl/index.min.json")) .newCall(GET("$repoBaseUrl/index.min.json"))
.awaitSuccess() .awaitSuccess()
with(json) {
response response
.parseAs<List<ExtensionJsonObject>>() .parseAs<List<ExtensionJsonObject>>()
.toExtensions(repoBaseUrl) .toExtensions(repoBaseUrl)
}
} catch (e: Throwable) { } catch (e: Throwable) {
Logger.e(e) { "Failed to get extensions from $repoBaseUrl" } Logger.e(e) { "Failed to get extensions from $repoBaseUrl" }
emptyList() emptyList()

View file

@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.util.chapter.ChapterFilter
import eu.kanade.tachiyomi.util.manga.MangaShortcutManager import eu.kanade.tachiyomi.util.manga.MangaShortcutManager
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.protobuf.ProtoBuf
import nl.adaptivity.xmlutil.XmlDeclMode import nl.adaptivity.xmlutil.XmlDeclMode
import nl.adaptivity.xmlutil.core.XmlVersion import nl.adaptivity.xmlutil.core.XmlVersion
import nl.adaptivity.xmlutil.serialization.XML import nl.adaptivity.xmlutil.serialization.XML
@ -145,6 +146,9 @@ fun appModule(app: Application) = module {
xmlVersion = XmlVersion.XML10 xmlVersion = XmlVersion.XML10
} }
} }
single<ProtoBuf> {
ProtoBuf
}
single { ChapterFilter() } single { ChapterFilter() }

View file

@ -6,17 +6,13 @@ import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.awaitSuccess import eu.kanade.tachiyomi.network.awaitSuccess
import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.network.parseAs
import eu.kanade.tachiyomi.util.system.withIOContext import eu.kanade.tachiyomi.util.system.withIOContext
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
import yokai.domain.extension.repo.model.ExtensionRepo import yokai.domain.extension.repo.model.ExtensionRepo
class ExtensionRepoService( class ExtensionRepoService(
private val client: OkHttpClient, private val client: OkHttpClient,
) { ) {
private val json: Json by injectLazy()
suspend fun fetchRepoDetails( suspend fun fetchRepoDetails(
repo: String, repo: String,
): ExtensionRepo? { ): ExtensionRepo? {
@ -24,12 +20,10 @@ class ExtensionRepoService(
val url = "$repo/repo.json".toUri() val url = "$repo/repo.json".toUri()
try { try {
with(json) {
client.newCall(GET(url.toString())) client.newCall(GET(url.toString()))
.awaitSuccess() .awaitSuccess()
.parseAs<ExtensionRepoMetaDto>() .parseAs<ExtensionRepoMetaDto>()
.toExtensionRepo(baseUrl = repo) .toExtensionRepo(baseUrl = repo)
}
} catch (e: Exception) { } catch (e: Exception) {
Logger.e(e) { "Failed to fetch repo details" } Logger.e(e) { "Failed to fetch repo details" }
null null

View file

@ -66,7 +66,6 @@ android {
tasks { tasks {
withType<KotlinCompile> { withType<KotlinCompile> {
compilerOptions.freeCompilerArgs.addAll( compilerOptions.freeCompilerArgs.addAll(
"-Xcontext-receivers",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi", "-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
) )

View file

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.network
import java.io.IOException import java.io.IOException
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlin.coroutines.resumeWithException import kotlin.coroutines.resumeWithException
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -18,6 +17,8 @@ import okhttp3.Response
import rx.Observable import rx.Observable
import rx.Producer import rx.Producer
import rx.Subscription import rx.Subscription
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
val jsonMime = "application/json; charset=utf-8".toMediaType() val jsonMime = "application/json; charset=utf-8".toMediaType()
@ -68,7 +69,6 @@ fun Call.asObservableSuccess(): Observable<Response> {
} }
// Based on https://github.com/gildor/kotlin-coroutines-okhttp // Based on https://github.com/gildor/kotlin-coroutines-okhttp
@OptIn(ExperimentalCoroutinesApi::class)
private suspend fun Call.await(callStack: Array<StackTraceElement>): Response { private suspend fun Call.await(callStack: Array<StackTraceElement>): Response {
return suspendCancellableCoroutine { continuation -> return suspendCancellableCoroutine { continuation ->
val callback = val callback =
@ -131,13 +131,11 @@ fun OkHttpClient.newCachelessCallWithProgress(request: Request, listener: Progre
return progressClient.newCall(request) return progressClient.newCall(request)
} }
context(Json)
inline fun <reified T> Response.parseAs(): T { inline fun <reified T> Response.parseAs(): T {
return decodeFromJsonResponse(serializer(), this) return Injekt.get<Json>().decodeFromJsonResponse(serializer(), this)
} }
context(Json) fun <T> Json.decodeFromJsonResponse(
fun <T> decodeFromJsonResponse(
deserializer: DeserializationStrategy<T>, deserializer: DeserializationStrategy<T>,
response: Response, response: Response,
): T { ): T {