mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
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:
parent
1b92ae2e5f
commit
d02f1bdd11
17 changed files with 265 additions and 347 deletions
|
@ -278,7 +278,6 @@ tasks {
|
|||
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
|
||||
withType<KotlinCompile> {
|
||||
compilerOptions.freeCompilerArgs.addAll(
|
||||
"-Xcontext-receivers",
|
||||
// "-opt-in=kotlin.Experimental",
|
||||
"-opt-in=kotlin.RequiresOptIn",
|
||||
"-opt-in=kotlin.ExperimentalStdlibApi",
|
||||
|
|
|
@ -49,15 +49,13 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
put("completedAt", createDate(track.finished_reading_date))
|
||||
}
|
||||
}
|
||||
with(json) {
|
||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
.parseAs<ALAddMangaResult>()
|
||||
.let {
|
||||
track.library_id = it.data.entry.id
|
||||
track
|
||||
}
|
||||
}
|
||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
.parseAs<ALAddMangaResult>()
|
||||
.let {
|
||||
track.library_id = it.data.entry.id
|
||||
track
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,11 +72,9 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
put("completedAt", createDate(track.finished_reading_date))
|
||||
}
|
||||
}
|
||||
with(json) {
|
||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
track
|
||||
}
|
||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,13 +86,11 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
put("query", search)
|
||||
}
|
||||
}
|
||||
with(json) {
|
||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
.parseAs<ALSearchResult>()
|
||||
.data.page.media
|
||||
.map { it.toALManga().toTrack() }
|
||||
}
|
||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
.parseAs<ALSearchResult>()
|
||||
.data.page.media
|
||||
.map { it.toALManga().toTrack() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,15 +103,13 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
put("manga_id", track.media_id)
|
||||
}
|
||||
}
|
||||
with(json) {
|
||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
.parseAs<ALUserListMangaQueryResult>()
|
||||
.data.page.mediaList
|
||||
.map { it.toALUserManga() }
|
||||
.firstOrNull()
|
||||
?.toTrack()
|
||||
}
|
||||
authClient.newCall(POST(API_URL, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
.parseAs<ALUserListMangaQueryResult>()
|
||||
.data.page.mediaList
|
||||
.map { it.toALUserManga() }
|
||||
.firstOrNull()
|
||||
?.toTrack()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,29 +75,25 @@ class BangumiApi(
|
|||
.appendQueryParameter("responseGroup", "large")
|
||||
.appendQueryParameter("max_results", "20")
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<BGMSearchResult>()
|
||||
.let { result ->
|
||||
if (result.code == 404) emptyList<TrackSearch>()
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<BGMSearchResult>()
|
||||
.let { result ->
|
||||
if (result.code == 404) emptyList<TrackSearch>()
|
||||
|
||||
result.list
|
||||
?.map { it.toTrackSearch(trackId) }
|
||||
.orEmpty()
|
||||
}
|
||||
}
|
||||
result.list
|
||||
?.map { it.toTrackSearch(trackId) }
|
||||
.orEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun findLibManga(track: Track): Track? {
|
||||
return withIOContext {
|
||||
with(json) {
|
||||
authClient.newCall(GET("$API_URL/subject/${track.media_id}"))
|
||||
.awaitSuccess()
|
||||
.parseAs<BGMSearchItem>()
|
||||
.toTrackSearch(trackId)
|
||||
}
|
||||
authClient.newCall(GET("$API_URL/subject/${track.media_id}"))
|
||||
.awaitSuccess()
|
||||
.parseAs<BGMSearchItem>()
|
||||
.toTrackSearch(trackId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,29 +107,25 @@ class BangumiApi(
|
|||
.build()
|
||||
|
||||
// TODO: get user readed chapter here
|
||||
with(json) {
|
||||
authClient.newCall(requestUserRead)
|
||||
.awaitSuccess()
|
||||
.parseAs<BGMCollectionResponse>()
|
||||
.let {
|
||||
if (it.code == 400) return@let null
|
||||
authClient.newCall(requestUserRead)
|
||||
.awaitSuccess()
|
||||
.parseAs<BGMCollectionResponse>()
|
||||
.let {
|
||||
if (it.code == 400) return@let null
|
||||
|
||||
track.status = it.status?.id?.toInt() ?: Bangumi.DEFAULT_STATUS
|
||||
track.last_chapter_read = it.epStatus!!.toFloat()
|
||||
track.score = it.rating!!.toFloat()
|
||||
track
|
||||
}
|
||||
}
|
||||
track.status = it.status?.id?.toInt() ?: Bangumi.DEFAULT_STATUS
|
||||
track.last_chapter_read = it.epStatus!!.toFloat()
|
||||
track.score = it.rating!!.toFloat()
|
||||
track
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun accessToken(code: String): BGMOAuth {
|
||||
return withIOContext {
|
||||
with(json) {
|
||||
client.newCall(accessTokenRequest(code))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
client.newCall(accessTokenRequest(code))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
|
|||
try {
|
||||
client.newCall(request).execute().use {
|
||||
when (it.code) {
|
||||
200 -> return with(json) { it.parseAs<AuthenticationDto>().token }
|
||||
200 -> return it.parseAs<AuthenticationDto>().token
|
||||
401 -> {
|
||||
Logger.w { "Unauthorized / api key not valid: Cleaned api URL: $apiUrl, Api key is empty: ${apiKey.isEmpty()}" }
|
||||
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 {
|
||||
val requestUrl = getApiVolumesUrl(url)
|
||||
try {
|
||||
val listVolumeDto = with(json) {
|
||||
val listVolumeDto =
|
||||
authClient.newCall(GET(requestUrl))
|
||||
.execute()
|
||||
.parseAs<List<VolumeDto>>()
|
||||
}
|
||||
var volumeNumber = 0L
|
||||
var maxChapterNumber = 0L
|
||||
for (volume in listVolumeDto) {
|
||||
|
@ -117,9 +116,7 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
|
|||
try {
|
||||
authClient.newCall(GET(requestUrl)).execute().use {
|
||||
if (it.code == 200) {
|
||||
return with(json) {
|
||||
it.parseAs<ChapterDto>().number!!.replace(",", ".").toFloat()
|
||||
}
|
||||
return it.parseAs<ChapterDto>().number!!.replace(",", ".").toFloat()
|
||||
}
|
||||
if (it.code == 204) {
|
||||
return 0F
|
||||
|
@ -134,11 +131,10 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor
|
|||
|
||||
suspend fun getTrackSearch(url: String): TrackSearch = withIOContext {
|
||||
try {
|
||||
val serieDto: SeriesDto = with(json) {
|
||||
val serieDto: SeriesDto =
|
||||
authClient.newCall(GET(url))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
|
||||
val track = serieDto.toTrack()
|
||||
track.apply {
|
||||
|
|
|
@ -131,14 +131,12 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
|
||||
suspend fun search(query: String): List<TrackSearch> {
|
||||
return withIOContext {
|
||||
with(json) {
|
||||
authClient.newCall(GET(ALGOLIA_KEY_URL))
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuSearchResult>()
|
||||
.let {
|
||||
algoliaSearch(it.media.key, query)
|
||||
}
|
||||
}
|
||||
authClient.newCall(GET(ALGOLIA_KEY_URL))
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuSearchResult>()
|
||||
.let {
|
||||
algoliaSearch(it.media.key, query)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,25 +145,23 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
val jsonObject = buildJsonObject {
|
||||
put("params", "query=$query$ALGOLIA_FILTER")
|
||||
}
|
||||
with(json) {
|
||||
client.newCall(
|
||||
POST(
|
||||
ALGOLIA_URL,
|
||||
headers = headersOf(
|
||||
"X-Algolia-Application-Id",
|
||||
ALGOLIA_APP_ID,
|
||||
"X-Algolia-API-Key",
|
||||
key,
|
||||
),
|
||||
body = jsonObject.toString().toRequestBody(jsonMime),
|
||||
client.newCall(
|
||||
POST(
|
||||
ALGOLIA_URL,
|
||||
headers = headersOf(
|
||||
"X-Algolia-Application-Id",
|
||||
ALGOLIA_APP_ID,
|
||||
"X-Algolia-API-Key",
|
||||
key,
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuAlgoliaSearchResult>()
|
||||
.hits
|
||||
.filter { it.subtype != "novel" }
|
||||
.map { it.toTrack() }
|
||||
}
|
||||
body = jsonObject.toString().toRequestBody(jsonMime),
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuAlgoliaSearchResult>()
|
||||
.hits
|
||||
.filter { it.subtype != "novel" }
|
||||
.map { it.toTrack() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,18 +171,16 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
.encodedQuery("filter[manga_id]=${track.media_id}&filter[user_id]=$userId")
|
||||
.appendQueryParameter("include", "manga")
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuListSearchResult>()
|
||||
.let {
|
||||
if (it.data.isNotEmpty() && it.included.isNotEmpty()) {
|
||||
it.firstToTrack()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuListSearchResult>()
|
||||
.let {
|
||||
if (it.data.isNotEmpty() && it.included.isNotEmpty()) {
|
||||
it.firstToTrack()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,18 +190,16 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
.encodedQuery("filter[id]=${track.media_id}")
|
||||
.appendQueryParameter("include", "manga")
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuListSearchResult>()
|
||||
.let {
|
||||
if (it.data.isNotEmpty() && it.included.isNotEmpty()) {
|
||||
it.firstToTrack()
|
||||
} else {
|
||||
throw Exception("Could not find manga")
|
||||
}
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuListSearchResult>()
|
||||
.let {
|
||||
if (it.data.isNotEmpty() && it.included.isNotEmpty()) {
|
||||
it.firstToTrack()
|
||||
} else {
|
||||
throw Exception("Could not find manga")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,11 +212,9 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
.add("client_id", CLIENT_ID)
|
||||
.add("client_secret", CLIENT_SECRET)
|
||||
.build()
|
||||
with(json) {
|
||||
client.newCall(POST(LOGIN_URL, body = formBody))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
client.newCall(POST(LOGIN_URL, body = formBody))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,13 +223,11 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
val url = "${BASE_URL}users".toUri().buildUpon()
|
||||
.encodedQuery("filter[self]=true")
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuCurrentUserResult>()
|
||||
.data[0]
|
||||
.id
|
||||
}
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<KitsuCurrentUserResult>()
|
||||
.data[0]
|
||||
.id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,21 +26,19 @@ class KomgaApi(private val client: OkHttpClient) {
|
|||
withIOContext {
|
||||
try {
|
||||
val track =
|
||||
with(json) {
|
||||
if (url.contains(READLIST_API)) {
|
||||
client.newCall(GET(url))
|
||||
.awaitSuccess()
|
||||
.parseAs<ReadListDto>()
|
||||
.toTrack()
|
||||
} else {
|
||||
client.newCall(GET(url))
|
||||
.awaitSuccess()
|
||||
.parseAs<SeriesDto>()
|
||||
.toTrack()
|
||||
}
|
||||
if (url.contains(READLIST_API)) {
|
||||
client.newCall(GET(url))
|
||||
.awaitSuccess()
|
||||
.parseAs<ReadListDto>()
|
||||
.toTrack()
|
||||
} else {
|
||||
client.newCall(GET(url))
|
||||
.awaitSuccess()
|
||||
.parseAs<SeriesDto>()
|
||||
.toTrack()
|
||||
}
|
||||
|
||||
val progress = with(json) {
|
||||
val progress =
|
||||
client
|
||||
.newCall(
|
||||
GET(
|
||||
|
@ -59,7 +57,6 @@ class KomgaApi(private val client: OkHttpClient) {
|
|||
it.parseAs<ReadProgressDto>().toV2()
|
||||
}
|
||||
}
|
||||
}
|
||||
track.apply {
|
||||
cover_url = "$url/thumbnail"
|
||||
tracking_url = url
|
||||
|
|
|
@ -37,15 +37,13 @@ class MangaUpdatesApi(
|
|||
|
||||
suspend fun getSeriesListItem(track: Track): Pair<MUListItem, MURating?> {
|
||||
val listItem =
|
||||
with(json) {
|
||||
authClient.newCall(
|
||||
GET(
|
||||
url = "$BASE_URL/v1/lists/series/${track.media_id}",
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<MUListItem>()
|
||||
}
|
||||
authClient.newCall(
|
||||
GET(
|
||||
url = "$BASE_URL/v1/lists/series/${track.media_id}",
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<MUListItem>()
|
||||
|
||||
val rating = getSeriesRating(track)
|
||||
|
||||
|
@ -104,15 +102,13 @@ class MangaUpdatesApi(
|
|||
|
||||
private suspend fun getSeriesRating(track: Track): MURating? {
|
||||
return try {
|
||||
with(json) {
|
||||
authClient.newCall(
|
||||
GET(
|
||||
url = "$BASE_URL/v1/series/${track.media_id}/rating",
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<MURating>()
|
||||
}
|
||||
authClient.newCall(
|
||||
GET(
|
||||
url = "$BASE_URL/v1/series/${track.media_id}/rating",
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<MURating>()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
@ -151,18 +147,16 @@ class MangaUpdatesApi(
|
|||
},
|
||||
)
|
||||
}
|
||||
return with(json) {
|
||||
client.newCall(
|
||||
POST(
|
||||
url = "$BASE_URL/v1/series/search",
|
||||
body = body.toString().toRequestBody(CONTENT_TYPE),
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<MUSearchResult>()
|
||||
.results
|
||||
.map { it.record }
|
||||
}
|
||||
return client.newCall(
|
||||
POST(
|
||||
url = "$BASE_URL/v1/series/search",
|
||||
body = body.toString().toRequestBody(CONTENT_TYPE),
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<MUSearchResult>()
|
||||
.results
|
||||
.map { it.record }
|
||||
}
|
||||
|
||||
suspend fun authenticate(username: String, password: String): MUContext? {
|
||||
|
@ -170,17 +164,15 @@ class MangaUpdatesApi(
|
|||
put("username", username)
|
||||
put("password", password)
|
||||
}
|
||||
return with(json) {
|
||||
client.newCall(
|
||||
PUT(
|
||||
url = "$BASE_URL/v1/account/login",
|
||||
body = body.toString().toRequestBody(CONTENT_TYPE),
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<MULoginResponse>()
|
||||
.context
|
||||
}
|
||||
return client.newCall(
|
||||
PUT(
|
||||
url = "$BASE_URL/v1/account/login",
|
||||
body = body.toString().toRequestBody(CONTENT_TYPE),
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
.parseAs<MULoginResponse>()
|
||||
.context
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -45,11 +45,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||
.add("code_verifier", codeVerifier)
|
||||
.add("grant_type", "authorization_code")
|
||||
.build()
|
||||
with(json) {
|
||||
client.newCall(POST("$BASE_OAUTH_URL/token", body = formBody))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
client.newCall(POST("$BASE_OAUTH_URL/token", body = formBody))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,12 +57,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||
.url("$BASE_API_URL/users/@me")
|
||||
.get()
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(request)
|
||||
.awaitSuccess()
|
||||
.parseAs<MALUser>()
|
||||
.name
|
||||
}
|
||||
authClient.newCall(request)
|
||||
.awaitSuccess()
|
||||
.parseAs<MALUser>()
|
||||
.name
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,15 +71,13 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||
.appendQueryParameter("q", query.take(64))
|
||||
.appendQueryParameter("nsfw", "true")
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<MALSearchResult>()
|
||||
.data
|
||||
.map { async { getMangaDetails(it.node.id) } }
|
||||
.awaitAll()
|
||||
.filter { !it.publishing_type.contains("novel") }
|
||||
}
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<MALSearchResult>()
|
||||
.data
|
||||
.map { async { getMangaDetails(it.node.id) } }
|
||||
.awaitAll()
|
||||
.filter { !it.publishing_type.contains("novel") }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,24 +87,22 @@ 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()
|
||||
with(json) {
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<MALManga>()
|
||||
.let {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
media_id = it.id
|
||||
title = it.title
|
||||
summary = it.synopsis
|
||||
total_chapters = it.numChapters
|
||||
cover_url = it.covers.large
|
||||
tracking_url = "https://myanimelist.net/manga/$media_id"
|
||||
publishing_status = it.status.replace("_", " ")
|
||||
publishing_type = it.mediaType.replace("_", " ")
|
||||
start_date = it.startDate ?: ""
|
||||
}
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<MALManga>()
|
||||
.let {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
media_id = it.id
|
||||
title = it.title
|
||||
summary = it.synopsis
|
||||
total_chapters = it.numChapters
|
||||
cover_url = it.covers.large
|
||||
tracking_url = "https://myanimelist.net/manga/$media_id"
|
||||
publishing_status = it.status.replace("_", " ")
|
||||
publishing_type = it.mediaType.replace("_", " ")
|
||||
start_date = it.startDate ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,12 +124,10 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||
.url(mangaUrl(track.media_id).toString())
|
||||
.put(formBodyBuilder.build())
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(request)
|
||||
.awaitSuccess()
|
||||
.parseAs<MALListItemStatus>()
|
||||
.let { parseMangaItem(it, track) }
|
||||
}
|
||||
authClient.newCall(request)
|
||||
.awaitSuccess()
|
||||
.parseAs<MALListItemStatus>()
|
||||
.let { parseMangaItem(it, track) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,15 +137,13 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||
.appendPath(track.media_id.toString())
|
||||
.appendQueryParameter("fields", "num_chapters,my_list_status{start_date,finish_date}")
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(GET(uri.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<MALListItem>()
|
||||
.let { item ->
|
||||
track.total_chapters = item.numChapters
|
||||
item.myListStatus?.let { parseMangaItem(it, track) }
|
||||
}
|
||||
}
|
||||
authClient.newCall(GET(uri.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<MALListItem>()
|
||||
.let { item ->
|
||||
track.total_chapters = item.numChapters
|
||||
item.myListStatus?.let { parseMangaItem(it, track) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,11 +178,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
|||
.url(urlBuilder.build().toString())
|
||||
.get()
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(request)
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
authClient.newCall(request)
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
|
|||
|
||||
return runCatching {
|
||||
if (response.isSuccessful) {
|
||||
with(json) { response.parseAs<MALOAuth>() }
|
||||
response.parseAs<MALOAuth>()
|
||||
} else {
|
||||
response.close()
|
||||
null
|
||||
|
|
|
@ -74,12 +74,10 @@ class ShikimoriApi(
|
|||
.appendQueryParameter("search", search)
|
||||
.appendQueryParameter("limit", "20")
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<List<SMManga>>()
|
||||
.map { it.toTrack(trackId) }
|
||||
}
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<List<SMManga>>()
|
||||
.map { it.toTrack(trackId) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,51 +100,44 @@ class ShikimoriApi(
|
|||
val urlMangas = "$API_URL/mangas".toUri().buildUpon()
|
||||
.appendPath(track.media_id.toString())
|
||||
.build()
|
||||
val manga = with(json) {
|
||||
val manga =
|
||||
authClient.newCall(GET(urlMangas.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<SMManga>()
|
||||
}
|
||||
|
||||
val url = "$API_URL/v2/user_rates".toUri().buildUpon()
|
||||
.appendQueryParameter("user_id", user_id)
|
||||
.appendQueryParameter("target_id", track.media_id.toString())
|
||||
.appendQueryParameter("target_type", "Manga")
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.execute()
|
||||
.parseAs<List<SMUserListEntry>>()
|
||||
.let { entries ->
|
||||
if (entries.size > 1) {
|
||||
throw Exception("Too manga manga in response")
|
||||
}
|
||||
entries
|
||||
.map { it.toTrack(trackId, manga) }
|
||||
.firstOrNull()
|
||||
authClient.newCall(GET(url.toString()))
|
||||
.execute()
|
||||
.parseAs<List<SMUserListEntry>>()
|
||||
.let { entries ->
|
||||
if (entries.size > 1) {
|
||||
throw Exception("Too manga manga in response")
|
||||
}
|
||||
}
|
||||
entries
|
||||
.map { it.toTrack(trackId, manga) }
|
||||
.firstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getCurrentUser(): Int {
|
||||
return withIOContext {
|
||||
with(json) {
|
||||
authClient.newCall(GET("$API_URL/users/whoami"))
|
||||
.awaitSuccess()
|
||||
.parseAs<SMUser>()
|
||||
.id
|
||||
}
|
||||
authClient.newCall(GET("$API_URL/users/whoami"))
|
||||
.awaitSuccess()
|
||||
.parseAs<SMUser>()
|
||||
.id
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun accessToken(code: String): SMOAuth {
|
||||
return withIOContext {
|
||||
with(json) {
|
||||
client.newCall(accessTokenRequest(code))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
client.newCall(accessTokenRequest(code))
|
||||
.awaitSuccess()
|
||||
.parseAs()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,9 +52,7 @@ class TachideskApi {
|
|||
trackUrl
|
||||
}
|
||||
|
||||
val manga = with(json) {
|
||||
client.newCall(GET("$url/full", headers)).awaitSuccess().parseAs<MangaDataClass>()
|
||||
}
|
||||
val manga = client.newCall(GET("$url/full", headers)).awaitSuccess().parseAs<MangaDataClass>()
|
||||
|
||||
TrackSearch.create(TrackManager.SUWAYOMI).apply {
|
||||
title = manga.title
|
||||
|
@ -74,9 +72,7 @@ class TachideskApi {
|
|||
|
||||
suspend fun updateProgress(track: Track): Track {
|
||||
val url = track.tracking_url
|
||||
val chapters = with(json) {
|
||||
client.newCall(GET("$url/chapters", headers)).awaitSuccess().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(
|
||||
|
|
|
@ -11,12 +11,12 @@ import eu.kanade.tachiyomi.network.await
|
|||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import eu.kanade.tachiyomi.util.system.localeContext
|
||||
import eu.kanade.tachiyomi.util.system.withIOContext
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import yokai.domain.base.models.Version
|
||||
import java.util.*
|
||||
import java.util.concurrent.*
|
||||
|
||||
class AppUpdateChecker(
|
||||
private val json: Json = Injekt.get(),
|
||||
|
@ -31,48 +31,46 @@ class AppUpdateChecker(
|
|||
}
|
||||
|
||||
return withIOContext {
|
||||
val result = with(json) {
|
||||
if (preferences.checkForBetas().get()) {
|
||||
networkService.client
|
||||
.newCall(GET("https://api.github.com/repos/$GITHUB_REPO/releases"))
|
||||
.await()
|
||||
.parseAs<List<GithubRelease>>()
|
||||
.let { githubReleases ->
|
||||
val releases =
|
||||
githubReleases.take(10).filter { isNewVersion(it.version) }
|
||||
// Check if any of the latest versions are newer than the current version
|
||||
val release = releases
|
||||
.maxWithOrNull { r1, r2 ->
|
||||
when {
|
||||
r1.version == r2.version -> 0
|
||||
isNewVersion(r2.version, r1.version) -> -1
|
||||
else -> 1
|
||||
}
|
||||
val result = if (preferences.checkForBetas().get()) {
|
||||
networkService.client
|
||||
.newCall(GET("https://api.github.com/repos/$GITHUB_REPO/releases"))
|
||||
.await()
|
||||
.parseAs<List<GithubRelease>>()
|
||||
.let { githubReleases ->
|
||||
val releases =
|
||||
githubReleases.take(10).filter { isNewVersion(it.version) }
|
||||
// Check if any of the latest versions are newer than the current version
|
||||
val release = releases
|
||||
.maxWithOrNull { r1, r2 ->
|
||||
when {
|
||||
r1.version == r2.version -> 0
|
||||
isNewVersion(r2.version, r1.version) -> -1
|
||||
else -> 1
|
||||
}
|
||||
preferences.lastAppCheck().set(Date().time)
|
||||
|
||||
if (release != null) {
|
||||
AppUpdateResult.NewUpdate(release)
|
||||
} else {
|
||||
AppUpdateResult.NoNewUpdate
|
||||
}
|
||||
}
|
||||
} else {
|
||||
networkService.client
|
||||
.newCall(GET("https://api.github.com/repos/$GITHUB_REPO/releases/latest"))
|
||||
.await()
|
||||
.parseAs<GithubRelease>()
|
||||
.let {
|
||||
preferences.lastAppCheck().set(Date().time)
|
||||
preferences.lastAppCheck().set(Date().time)
|
||||
|
||||
// Check if latest version is newer than the current version
|
||||
if (isNewVersion(it.version)) {
|
||||
AppUpdateResult.NewUpdate(it)
|
||||
} else {
|
||||
AppUpdateResult.NoNewUpdate
|
||||
}
|
||||
if (release != null) {
|
||||
AppUpdateResult.NewUpdate(release)
|
||||
} else {
|
||||
AppUpdateResult.NoNewUpdate
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
networkService.client
|
||||
.newCall(GET("https://api.github.com/repos/$GITHUB_REPO/releases/latest"))
|
||||
.await()
|
||||
.parseAs<GithubRelease>()
|
||||
.let {
|
||||
preferences.lastAppCheck().set(Date().time)
|
||||
|
||||
// Check if latest version is newer than the current version
|
||||
if (isNewVersion(it.version)) {
|
||||
AppUpdateResult.NewUpdate(it)
|
||||
} else {
|
||||
AppUpdateResult.NoNewUpdate
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doExtrasAfterNewUpdate && result is AppUpdateResult.NewUpdate) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
|
||||
|
|
|
@ -14,7 +14,6 @@ import eu.kanade.tachiyomi.util.system.withIOContext
|
|||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
@ -24,7 +23,6 @@ import yokai.domain.extension.repo.model.ExtensionRepo
|
|||
|
||||
internal class ExtensionApi {
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
private val networkService: NetworkHelper by injectLazy()
|
||||
private val getExtensionRepo: GetExtensionRepo by injectLazy()
|
||||
private val updateExtensionRepo: UpdateExtensionRepo by injectLazy()
|
||||
|
@ -47,11 +45,9 @@ internal class ExtensionApi {
|
|||
.newCall(GET("$repoBaseUrl/index.min.json"))
|
||||
.awaitSuccess()
|
||||
|
||||
with(json) {
|
||||
response
|
||||
.parseAs<List<ExtensionJsonObject>>()
|
||||
.toExtensions(repoBaseUrl)
|
||||
}
|
||||
response
|
||||
.parseAs<List<ExtensionJsonObject>>()
|
||||
.toExtensions(repoBaseUrl)
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(e) { "Failed to get extensions from $repoBaseUrl" }
|
||||
emptyList()
|
||||
|
|
|
@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.util.chapter.ChapterFilter
|
|||
import eu.kanade.tachiyomi.util.manga.MangaShortcutManager
|
||||
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import nl.adaptivity.xmlutil.XmlDeclMode
|
||||
import nl.adaptivity.xmlutil.core.XmlVersion
|
||||
import nl.adaptivity.xmlutil.serialization.XML
|
||||
|
@ -145,6 +146,9 @@ fun appModule(app: Application) = module {
|
|||
xmlVersion = XmlVersion.XML10
|
||||
}
|
||||
}
|
||||
single<ProtoBuf> {
|
||||
ProtoBuf
|
||||
}
|
||||
|
||||
single { ChapterFilter() }
|
||||
|
||||
|
|
|
@ -6,17 +6,13 @@ import eu.kanade.tachiyomi.network.GET
|
|||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import eu.kanade.tachiyomi.util.system.withIOContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.OkHttpClient
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import yokai.domain.extension.repo.model.ExtensionRepo
|
||||
|
||||
class ExtensionRepoService(
|
||||
private val client: OkHttpClient,
|
||||
) {
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
suspend fun fetchRepoDetails(
|
||||
repo: String,
|
||||
): ExtensionRepo? {
|
||||
|
@ -24,12 +20,10 @@ class ExtensionRepoService(
|
|||
val url = "$repo/repo.json".toUri()
|
||||
|
||||
try {
|
||||
with(json) {
|
||||
client.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<ExtensionRepoMetaDto>()
|
||||
.toExtensionRepo(baseUrl = repo)
|
||||
}
|
||||
client.newCall(GET(url.toString()))
|
||||
.awaitSuccess()
|
||||
.parseAs<ExtensionRepoMetaDto>()
|
||||
.toExtensionRepo(baseUrl = repo)
|
||||
} catch (e: Exception) {
|
||||
Logger.e(e) { "Failed to fetch repo details" }
|
||||
null
|
||||
|
|
|
@ -66,7 +66,6 @@ android {
|
|||
tasks {
|
||||
withType<KotlinCompile> {
|
||||
compilerOptions.freeCompilerArgs.addAll(
|
||||
"-Xcontext-receivers",
|
||||
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
||||
)
|
||||
|
|
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.network
|
|||
import java.io.IOException
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.json.Json
|
||||
|
@ -18,6 +17,8 @@ import okhttp3.Response
|
|||
import rx.Observable
|
||||
import rx.Producer
|
||||
import rx.Subscription
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
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
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private suspend fun Call.await(callStack: Array<StackTraceElement>): Response {
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
val callback =
|
||||
|
@ -131,13 +131,11 @@ fun OkHttpClient.newCachelessCallWithProgress(request: Request, listener: Progre
|
|||
return progressClient.newCall(request)
|
||||
}
|
||||
|
||||
context(Json)
|
||||
inline fun <reified T> Response.parseAs(): T {
|
||||
return decodeFromJsonResponse(serializer(), this)
|
||||
return Injekt.get<Json>().decodeFromJsonResponse(serializer(), this)
|
||||
}
|
||||
|
||||
context(Json)
|
||||
fun <T> decodeFromJsonResponse(
|
||||
fun <T> Json.decodeFromJsonResponse(
|
||||
deserializer: DeserializationStrategy<T>,
|
||||
response: Response,
|
||||
): T {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue