From 5e99306e5f420e9c72faeb87cae3023d39b12476 Mon Sep 17 00:00:00 2001 From: MajorTanya <39014446+MajorTanya@users.noreply.github.com> Date: Sun, 6 Sep 2026 17:26:33 +0200 Subject: [PATCH] Minor tracking refactors (#3900) * Make tracker Api classes take their tracker's ID Also made the name consistently `trackerId` since `trackId` can be confusing in the context of Tracks that also carry several IDs. Also made the public constants in TrackerManager entirely redundant, so trackers are all equally getting their ID defined in their constructor call now. * Explicitly mark unused Exceptions as such * Make isExpired method of BGMOAuth data class As opposed to an extension defined in the same file * Kavita: thumbnail_url -> thumbnailUrl With a SerialName annotation of course * Suwayomi: Remove redundant with(json) Both of these requests don't use parseAs so this not required. * Bangumi: Don't recreate OAuth object for storing * Remove unused attribute from tracker OAuth classes Mostly `token_type`. Also removed `user_id` from BGMOAuth and `scope` & `expiresIn` from MangaBakaOAuth (which already provides `expiresAt`). * Use kotlin.time durations for token expiry math Something like `Clock.System.now().plus(1.hours)` is much easier to read than `System.getEpochMillis() + 3600`. Also lets us use the `epochSeconds` attribute where the given timestamps are seconds-resolution. * Bangumi: Remove redundant apply block * Kavita: Misc simplifications * Use parseAs in tracker interceptors * MAL: Use existing setAuth to store refresh token --- .../tachiyomi/data/track/TrackerManager.kt | 15 +++----- .../tachiyomi/data/track/anilist/Anilist.kt | 8 ++--- .../data/track/anilist/AnilistApi.kt | 12 ++++--- .../data/track/anilist/dto/ALManga.kt | 5 ++- .../data/track/bangumi/BangumiApi.kt | 6 ++-- .../data/track/bangumi/BangumiInterceptor.kt | 24 ++++--------- .../data/track/bangumi/dto/BGMOAuth.kt | 17 +++++---- .../data/track/bangumi/dto/BGMSearch.kt | 2 +- .../tachiyomi/data/track/hikka/HikkaApi.kt | 10 +++--- .../data/track/hikka/HikkaInterceptor.kt | 5 ++- .../tachiyomi/data/track/hikka/dto/HKManga.kt | 4 +-- .../tachiyomi/data/track/hikka/dto/HKOAuth.kt | 8 ++--- .../tachiyomi/data/track/hikka/dto/HKRead.kt | 4 +-- .../tachiyomi/data/track/kavita/Kavita.kt | 4 +-- .../tachiyomi/data/track/kavita/KavitaApi.kt | 35 ++++++++++-------- .../data/track/kavita/KavitaModels.kt | 16 +++------ .../tachiyomi/data/track/kitsu/KitsuApi.kt | 8 ++--- .../data/track/kitsu/KitsuInterceptor.kt | 10 ++++-- .../data/track/kitsu/dto/KitsuOAuth.kt | 5 ++- .../tachiyomi/data/track/komga/Komga.kt | 2 +- .../tachiyomi/data/track/komga/KomgaApi.kt | 6 ++-- .../data/track/mangabaka/MangaBakaApi.kt | 7 ++-- .../track/mangabaka/MangaBakaInterceptor.kt | 5 ++- .../track/mangabaka/dto/MangaBakaOAuth.kt | 5 --- .../data/track/mangaupdates/MangaUpdates.kt | 4 +-- .../track/mangaupdates/MangaUpdatesApi.kt | 4 +-- .../data/track/myanimelist/MyAnimeList.kt | 4 +-- .../data/track/myanimelist/MyAnimeListApi.kt | 4 +-- .../myanimelist/MyAnimeListInterceptor.kt | 5 +-- .../data/track/myanimelist/dto/MALOAuth.kt | 10 +++--- .../data/track/shikimori/Shikimori.kt | 4 +-- .../data/track/shikimori/ShikimoriApi.kt | 8 ++--- .../track/shikimori/ShikimoriInterceptor.kt | 13 +++---- .../data/track/shikimori/dto/SMManga.kt | 4 +-- .../data/track/shikimori/dto/SMOAuth.kt | 11 +++--- .../track/shikimori/dto/SMUserListEntry.kt | 4 +-- .../tachiyomi/data/track/suwayomi/Suwayomi.kt | 2 +- .../data/track/suwayomi/SuwayomiApi.kt | 36 +++++++++---------- 38 files changed, 156 insertions(+), 180 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt index 95c98ff13..3c59531e8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt @@ -20,24 +20,17 @@ import kotlinx.coroutines.flow.combine @SingleIn(AppScope::class) class TrackerManager { - companion object { - const val ANILIST = 2L - const val KITSU = 3L - const val KAVITA = 8L - const val MANGABAKA = 11L - } - val myAnimeList = MyAnimeList(1L) - val aniList = Anilist(ANILIST) - val kitsu = Kitsu(KITSU) + val aniList = Anilist(2L) + val kitsu = Kitsu(3L) val shikimori = Shikimori(4L) val bangumi = Bangumi(5L) val komga = Komga(6L) val mangaUpdates = MangaUpdates(7L) - val kavita = Kavita(KAVITA) + val kavita = Kavita(8L) val suwayomi = Suwayomi(9L) val hikka = Hikka(10L) - val mangaBaka = MangaBaka(MANGABAKA) + val mangaBaka = MangaBaka(11L) val trackers = listOf( myAnimeList, diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt index 5586bb782..d62410e3e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt @@ -35,7 +35,7 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker { private val interceptor by lazy { AnilistInterceptor(this, getPassword()) } - private val api by lazy { AnilistApi(client, interceptor) } + private val api by lazy { AnilistApi(id, client, interceptor) } override val supportsReadingDates: Boolean = true @@ -47,7 +47,7 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker { // If the preference is an int from APIv1, logout user to force using APIv2 try { scorePreference.get() - } catch (e: ClassCastException) { + } catch (_: ClassCastException) { logout() scorePreference.delete() } @@ -224,7 +224,7 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker { scorePreference.set(currentUser.mediaListOptions.scoreFormat) saveDisplayUsername(currentUser.name) saveCredentials(currentUser.id.toString(), oauth.accessToken) - } catch (e: Throwable) { + } catch (_: Throwable) { logout() } } @@ -242,7 +242,7 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker { fun loadOAuth(): ALOAuth? { return try { json.decodeFromString(trackPreferences.trackToken(this).get()) - } catch (e: Exception) { + } catch (_: Exception) { null } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt index d85cc4534..3e6282a09 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt @@ -31,7 +31,11 @@ import kotlin.time.Duration.Companion.minutes import kotlin.time.Instant import tachiyomi.domain.track.model.Track as DomainTrack -class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { +class AnilistApi( + val trackerId: Long, + val client: OkHttpClient, + interceptor: AnilistInterceptor, +) { private val json: Json by injectLazy() @@ -192,7 +196,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { .awaitSuccess() .parseAs() .data.page.media - .map { it.toALManga().toTrack() } + .map { it.toALManga().toTrack(trackerId) } } } } @@ -273,7 +277,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { .data.page.mediaList .map { it.toALUserManga() } .firstOrNull() - ?.toTrack() + ?.toTrack(trackerId) } } } @@ -375,7 +379,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { .data.page.media .firstOrNull() ?.toALManga() - ?.toTrack() + ?.toTrack(trackerId) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALManga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALManga.kt index 9eedf22c4..fa3fe84a0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/dto/ALManga.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.data.track.anilist.dto import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.anilist.Anilist import eu.kanade.tachiyomi.data.track.anilist.AnilistApi import eu.kanade.tachiyomi.data.track.model.TrackSearch @@ -21,7 +20,7 @@ data class ALManga( val averageScore: Int, val staff: ALStaff, ) { - fun toTrack() = TrackSearch.create(TrackerManager.ANILIST).apply { + fun toTrack(trackerId: Long) = TrackSearch.create(trackerId).apply { remote_id = remoteId title = this@ALManga.title total_chapters = totalChapters @@ -57,7 +56,7 @@ data class ALUserManga( val manga: ALManga, val private: Boolean, ) { - fun toTrack() = Track.create(TrackerManager.ANILIST).apply { + fun toTrack(trackerId: Long) = Track.create(trackerId).apply { remote_id = manga.remoteId title = manga.title status = toTrackStatus() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt index ec7eda239..aceb9d733 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt @@ -30,7 +30,7 @@ import tachiyomi.core.common.util.lang.withIOContext import uy.kohesive.injekt.injectLazy class BangumiApi( - private val trackId: Long, + private val trackerId: Long, private val client: OkHttpClient, interceptor: BangumiInterceptor, ) { @@ -106,7 +106,7 @@ class BangumiApi( .parseAs() .data .filter { it.platform == null || it.platform == "漫画" } - .map { it.toTrackSearch(trackId) } + .map { it.toTrackSearch(trackerId) } } } } @@ -120,7 +120,7 @@ class BangumiApi( .awaitSuccess() .parseAs() .takeIf { it.platform == null || it.platform == "漫画" } - ?.toTrackSearch(trackId) + ?.toTrackSearch(trackerId) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt index 7829405fd..aab48e854 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.data.track.bangumi import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.data.track.bangumi.dto.BGMOAuth -import eu.kanade.tachiyomi.data.track.bangumi.dto.isExpired +import eu.kanade.tachiyomi.network.parseAs import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response @@ -25,7 +25,9 @@ class BangumiInterceptor(private val bangumi: Bangumi) : Interceptor { if (currAuth.isExpired()) { val response = chain.proceed(BangumiApi.refreshTokenRequest(currAuth.refreshToken!!)) if (response.isSuccessful) { - currAuth = json.decodeFromString(response.body.string()) + currAuth = with(json) { + response.parseAs() + } newAuth(currAuth) } else { response.close() @@ -37,27 +39,13 @@ class BangumiInterceptor(private val bangumi: Bangumi) : Interceptor { "User-Agent", "antsylich/Mihon/v${BuildConfig.VERSION_NAME} (Android) (http://github.com/mihonapp/mihon)", ) - .apply { - addHeader("Authorization", "Bearer ${currAuth.accessToken}") - } + .addHeader("Authorization", "Bearer ${currAuth.accessToken}") .build() .let(chain::proceed) } fun newAuth(oauth: BGMOAuth?) { - this.oauth = if (oauth == null) { - null - } else { - BGMOAuth( - oauth.accessToken, - oauth.tokenType, - System.currentTimeMillis() / 1000, - oauth.expiresIn, - oauth.refreshToken, - this.oauth?.userId, - ) - } - + this.oauth = oauth bangumi.saveToken(oauth) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMOAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMOAuth.kt index 9ac1308a9..542eb7840 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMOAuth.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMOAuth.kt @@ -3,23 +3,22 @@ package eu.kanade.tachiyomi.data.track.bangumi.dto import kotlinx.serialization.EncodeDefault import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlin.time.Clock +import kotlin.time.Duration.Companion.hours @Serializable +// Incomplete DTO with only our needed attributes data class BGMOAuth( @SerialName("access_token") val accessToken: String, - @SerialName("token_type") - val tokenType: String, @SerialName("created_at") @EncodeDefault - val createdAt: Long = System.currentTimeMillis() / 1000, + val createdAt: Long = Clock.System.now().epochSeconds, @SerialName("expires_in") val expiresIn: Long, @SerialName("refresh_token") val refreshToken: String?, - @SerialName("user_id") - val userId: Long?, -) - -// Access token refresh before expired -fun BGMOAuth.isExpired() = (System.currentTimeMillis() / 1000) > (createdAt + expiresIn - 3600) +) { + // Access token refresh before expired + fun isExpired() = Clock.System.now().plus(1.hours).epochSeconds > (createdAt + expiresIn) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMSearch.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMSearch.kt index bdc3848ea..f4b657c97 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMSearch.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/dto/BGMSearch.kt @@ -27,7 +27,7 @@ data class BGMSubject( val rating: BGMSubjectRating?, val platform: String?, ) { - fun toTrackSearch(trackId: Long): TrackSearch = TrackSearch.create(trackId).apply { + fun toTrackSearch(trackerId: Long): TrackSearch = TrackSearch.create(trackerId).apply { remote_id = this@BGMSubject.id title = nameCn.ifBlank { name } cover_url = images?.common.orEmpty() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/HikkaApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/HikkaApi.kt index 30277b843..662924ee1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/HikkaApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/HikkaApi.kt @@ -32,7 +32,7 @@ import uy.kohesive.injekt.injectLazy import tachiyomi.domain.track.model.Track as DomainTrack class HikkaApi( - private val trackId: Long, + private val trackerId: Long, private val client: OkHttpClient, interceptor: HikkaInterceptor, ) { @@ -95,7 +95,7 @@ class HikkaApi( .awaitSuccess() .parseAs() .list - .map { it.toTrack(trackId) } + .map { it.toTrack(trackerId) } } } } @@ -113,7 +113,7 @@ class HikkaApi( } else { response .parseAs() - .toTrack(trackId) + .toTrack(trackerId) } } } @@ -149,7 +149,7 @@ class HikkaApi( authClient.newCall(GET(url.toString())) .awaitSuccess() .parseAs() - .toTrack(trackId) + .toTrack(trackerId) } } } @@ -193,7 +193,7 @@ class HikkaApi( authClient.newCall(PUT(url.toString(), body = payload.toString().toRequestBody(jsonMime))) .awaitSuccess() .parseAs() - .toTrack(trackId) + .toTrack(trackerId) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/HikkaInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/HikkaInterceptor.kt index 8de795bef..338bd2637 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/HikkaInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/HikkaInterceptor.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.track.hikka import eu.kanade.tachiyomi.data.track.hikka.dto.HKAuthTokenInfo import eu.kanade.tachiyomi.data.track.hikka.dto.HKOAuth +import eu.kanade.tachiyomi.network.parseAs import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response @@ -32,7 +33,9 @@ class HikkaInterceptor(private val hikka: Hikka) : Interceptor { throw Exception("Hikka: Auth token info failed") } - val authTokenInfo = json.decodeFromString(authTokenInfoResponse.body.string()) + val authTokenInfo = with(json) { + authTokenInfoResponse.parseAs() + } setAuth(HKOAuth(currAuth.accessToken, authTokenInfo.expiration, authTokenInfo.created)) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKManga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKManga.kt index 2260a2c32..8efa41088 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKManga.kt @@ -36,8 +36,8 @@ data class HKManga( val startDate: Long? = null, val read: List? = emptyList(), ) { - fun toTrack(trackId: Long): TrackSearch { - return TrackSearch.create(trackId).apply { + fun toTrack(trackerId: Long): TrackSearch { + return TrackSearch.create(trackerId).apply { remote_id = stringToNumber(this@HKManga.slug) title = this@HKManga.titleUa ?: this@HKManga.titleEn ?: this@HKManga.titleOriginal total_chapters = this@HKManga.chapters?.toLong() ?: 0 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKOAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKOAuth.kt index 68adff1fa..e7f88d636 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKOAuth.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKOAuth.kt @@ -2,6 +2,8 @@ package eu.kanade.tachiyomi.data.track.hikka.dto import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlin.time.Clock +import kotlin.time.Duration.Companion.minutes @Serializable data class HKOAuth( @@ -10,9 +12,5 @@ data class HKOAuth( val expiration: Long, val created: Long, ) { - fun isExpired(): Boolean { - val currentTime = System.currentTimeMillis() / 1000 - val buffer = 5 * 60 // safety margin - return currentTime >= (expiration - buffer) - } + fun isExpired() = Clock.System.now().plus(5.minutes).epochSeconds >= expiration } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKRead.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKRead.kt index 18318d20a..98bb65b54 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKRead.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/hikka/dto/HKRead.kt @@ -24,8 +24,8 @@ data class HKRead( val endDate: Long? = null, val content: HKManga? = null, ) { - fun toTrack(trackId: Long): TrackSearch { - return TrackSearch.create(trackId).apply { + fun toTrack(trackerId: Long): TrackSearch { + return TrackSearch.create(trackerId).apply { val mangaContent = this@HKRead.content if (mangaContent != null) { title = mangaContent.titleUa ?: mangaContent.titleEn ?: mangaContent.titleOriginal diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt index 91c3ceed3..29deb9e8e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/Kavita.kt @@ -27,7 +27,7 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker { var authentications: OAuth? = null private val interceptor by lazy { KavitaInterceptor(this) } - val api by lazy { KavitaApi(client, interceptor) } + val api by lazy { KavitaApi(id, client, interceptor) } private val sourceManager: SourceManager by lazy { appGraph.sourceManager } @@ -95,7 +95,7 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker { override suspend fun match(manga: Manga): TrackSearch? = try { api.getTrackSearch(manga.url) - } catch (e: Exception) { + } catch (_: Exception) { null } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt index fd1b26197..583bf2eec 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaApi.kt @@ -5,11 +5,11 @@ 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.awaitSuccess +import eu.kanade.tachiyomi.network.jsonMime import eu.kanade.tachiyomi.network.parseAs import kotlinx.serialization.json.Json import logcat.LogPriority import okhttp3.Dns -import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.RequestBody.Companion.toRequestBody import tachiyomi.core.common.util.lang.withIOContext @@ -18,7 +18,11 @@ import uy.kohesive.injekt.injectLazy import java.io.IOException import java.net.SocketTimeoutException -class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor) { +class KavitaApi( + private val trackerId: Long, + private val client: OkHttpClient, + interceptor: KavitaInterceptor, +) { private val json: Json by injectLazy() @@ -40,7 +44,7 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor fun getNewToken(apiUrl: String, apiKey: String): String? { val request = POST( "$apiUrl/Plugin/authenticate?apiKey=$apiKey&pluginName=Tachiyomi-Kavita", - body = "{}".toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()), + body = EMPTY_JSON_BODY, ) try { with(json) { @@ -54,9 +58,9 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor throw IOException("Unauthorized / api key not valid") } 500 -> { - logcat( - LogPriority.WARN, - ) { "Error fetching JWT token. API URL: $apiUrl, empty API key: ${apiKey.isEmpty()}" } + logcat(LogPriority.WARN) { + "Error fetching JWT token. API URL: $apiUrl, empty API key: ${apiKey.isEmpty()}" + } throw IOException("Error fetching JWT token") } else -> {} @@ -64,7 +68,7 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor } } // Not sure which one to catch - } catch (e: SocketTimeoutException) { + } catch (_: SocketTimeoutException) { logcat(LogPriority.WARN) { "Could not fetch JWT token. Probably due to connectivity issue or URL '$apiUrl' not available, skipping" } @@ -133,10 +137,9 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor } } } catch (e: Exception) { - logcat( - LogPriority.WARN, - e, - ) { "Exception getting latest chapter read. Could not get itemRequest: $requestUrl" } + logcat(LogPriority.WARN, e) { + "Exception getting latest chapter read. Could not get itemRequest: $requestUrl" + } throw e } return 0.0 @@ -150,9 +153,9 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor .parseAs() } - val track = seriesDto.toTrack() + val track = seriesDto.toTrack(trackerId) track.apply { - cover_url = seriesDto.thumbnail_url.toString() + cover_url = seriesDto.thumbnailUrl.toString() tracking_url = url total_chapters = getTotalChapters(url) @@ -177,9 +180,13 @@ class KavitaApi(private val client: OkHttpClient, interceptor: KavitaInterceptor track.tracking_url, )}&chapterNumber=${track.last_chapter_read}" authClient.newCall( - POST(requestUrl, body = "{}".toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())), + POST(requestUrl, body = EMPTY_JSON_BODY), ) .awaitSuccess() return getTrackSearch(track.tracking_url) } + + companion object { + private val EMPTY_JSON_BODY = "{}".toRequestBody(jsonMime) + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaModels.kt index 6f42f6836..bcaec291e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaModels.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kavita/KavitaModels.kt @@ -1,7 +1,7 @@ package eu.kanade.tachiyomi.data.track.kavita -import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.model.TrackSearch +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable @@ -9,7 +9,8 @@ data class SeriesDto( val id: Int, val name: String, val originalName: String = "", - val thumbnail_url: String? = "", + @SerialName("thumbnailUrl") + val thumbnailUrl: String? = "", val localizedName: String? = "", val sortName: String? = "", val pages: Int, @@ -22,7 +23,7 @@ data class SeriesDto( val libraryId: Int, val libraryName: String? = "", ) { - fun toTrack(): TrackSearch = TrackSearch.create(TrackerManager.KAVITA).also { + fun toTrack(trackerId: Long): TrackSearch = TrackSearch.create(trackerId).also { it.title = name it.summary = "" } @@ -69,14 +70,7 @@ class OAuth( SourceAuth(3), ), ) { - fun getToken(apiUrl: String): String? { - for (authentication in authentications) { - if (authentication.apiUrl == apiUrl) { - return authentication.jwtToken - } - } - return null - } + fun getToken(apiUrl: String): String? = authentications.find { it.apiUrl == apiUrl }?.jwtToken } data class SourceAuth( diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt index 7da976f4f..d65176572 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt @@ -33,7 +33,7 @@ import kotlin.time.Instant import tachiyomi.domain.track.model.Track as DomainTrack class KitsuApi( - private val trackId: Long, + private val trackerId: Long, private val client: OkHttpClient, interceptor: KitsuInterceptor, ) { @@ -292,7 +292,7 @@ class KitsuApi( .awaitSuccess() .parseAs() .data.searchMangaByTitle.nodes - .map { it.toTrackSearch(trackId) } + .map { it.toTrackSearch(trackerId) } } } } @@ -334,7 +334,7 @@ class KitsuApi( .awaitSuccess() .parseAs() .data.findMangaById - ?.toTrackSearch(trackId) + ?.toTrackSearch(trackerId) } } } @@ -436,7 +436,7 @@ class KitsuApi( .data.findMangaBySlug } - kitsuManga?.toTrackSearch(trackId) + kitsuManga?.toTrackSearch(trackerId) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt index 4cbb44e3a..be5a8cef4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.track.kitsu import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.data.track.kitsu.dto.KitsuOAuth +import eu.kanade.tachiyomi.network.parseAs import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response @@ -19,7 +20,7 @@ class KitsuInterceptor(private val kitsu: Kitsu) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() - val currAuth = oauth ?: throw Exception("Not authenticated with Kitsu") + var currAuth = oauth ?: throw Exception("Not authenticated with Kitsu") val refreshToken = currAuth.refreshToken!! @@ -27,7 +28,10 @@ class KitsuInterceptor(private val kitsu: Kitsu) : Interceptor { if (currAuth.isExpired()) { val response = chain.proceed(KitsuApi.refreshTokenRequest(refreshToken)) if (response.isSuccessful) { - newAuth(json.decodeFromString(response.body.string())) + currAuth = with(json) { + response.parseAs() + } + newAuth(currAuth) } else { response.close() } @@ -35,7 +39,7 @@ class KitsuInterceptor(private val kitsu: Kitsu) : Interceptor { // Add the authorization header to the original request. val authRequest = originalRequest.newBuilder() - .addHeader("Authorization", "Bearer ${oauth!!.accessToken}") + .addHeader("Authorization", "Bearer ${currAuth.accessToken}") .header("User-Agent", "Mihon v${BuildConfig.VERSION_NAME} (${BuildConfig.APPLICATION_ID})") .header("Accept", "application/vnd.api+json") .header("Content-Type", "application/vnd.api+json") diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuOAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuOAuth.kt index c623c2dad..4778b6aa0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuOAuth.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/dto/KitsuOAuth.kt @@ -3,13 +3,12 @@ package eu.kanade.tachiyomi.data.track.kitsu.dto import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlin.time.Clock +import kotlin.time.Duration.Companion.hours @Serializable data class KitsuOAuth( @SerialName("access_token") val accessToken: String, - @SerialName("token_type") - val tokenType: String, @SerialName("created_at") val createdAt: Long, @SerialName("expires_in") @@ -17,5 +16,5 @@ data class KitsuOAuth( @SerialName("refresh_token") val refreshToken: String?, ) { - fun isExpired(): Boolean = (Clock.System.now().toEpochMilliseconds() / 1000) > (createdAt + expiresIn - 3600) + fun isExpired() = Clock.System.now().plus(1.hours).epochSeconds > (createdAt + expiresIn) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt index ae0ea63fd..8df1efd56 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/Komga.kt @@ -94,7 +94,7 @@ class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedTracker { override suspend fun match(manga: Manga): TrackSearch? = try { api.getTrackSearch(manga.url) - } catch (e: Exception) { + } catch (_: Exception) { null } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt index bf51a97d5..4395db8e1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/komga/KomgaApi.kt @@ -20,7 +20,7 @@ import uy.kohesive.injekt.injectLazy private const val READLIST_API = "/api/v1/readlists" class KomgaApi( - private val trackId: Long, + private val trackerId: Long, private val client: OkHttpClient, ) { @@ -97,13 +97,13 @@ class KomgaApi( return getTrackSearch(track.tracking_url) } - private fun SeriesDto.toTrack(): TrackSearch = TrackSearch.create(trackId).also { + private fun SeriesDto.toTrack(): TrackSearch = TrackSearch.create(trackerId).also { it.title = metadata.title it.summary = metadata.summary it.publishing_status = metadata.status } - private fun ReadListDto.toTrack(): TrackSearch = TrackSearch.create(trackId).also { + private fun ReadListDto.toTrack(): TrackSearch = TrackSearch.create(trackerId).also { it.title = name } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/MangaBakaApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/MangaBakaApi.kt index 503ea9aac..db1775d0e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/MangaBakaApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/MangaBakaApi.kt @@ -4,7 +4,6 @@ import android.net.Uri import androidx.core.net.toUri import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.data.database.models.Track -import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.mangabaka.dto.MangaBakaItem import eu.kanade.tachiyomi.data.track.mangabaka.dto.MangaBakaItemResult import eu.kanade.tachiyomi.data.track.mangabaka.dto.MangaBakaListResult @@ -41,7 +40,7 @@ import java.util.Locale import tachiyomi.domain.track.model.Track as DomainTrack class MangaBakaApi( - private val trackId: Long, + private val trackerId: Long, baseClient: OkHttpClient, interceptor: MangaBakaInterceptor, ) { @@ -120,7 +119,7 @@ class MangaBakaApi( .parseAs() .data - Track.create(TrackerManager.MANGABAKA).apply { + Track.create(trackerId).apply { remote_id = track.remote_id title = additionalData.chooseBestTitle() status = userData.getStatus() @@ -196,7 +195,7 @@ class MangaBakaApi( } private fun parseSearchItem(item: MangaBakaItem): TrackSearch { - return TrackSearch.create(trackId).apply { + return TrackSearch.create(trackerId).apply { remote_id = item.id title = item.chooseBestTitle() summary = item.description?.trim().orEmpty() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/MangaBakaInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/MangaBakaInterceptor.kt index afb760c06..63901f395 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/MangaBakaInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/MangaBakaInterceptor.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.track.mangabaka import eu.kanade.tachiyomi.data.track.mangabaka.dto.MangaBakaOAuth +import eu.kanade.tachiyomi.network.parseAs import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response @@ -20,7 +21,9 @@ class MangaBakaInterceptor(private val mangaBaka: MangaBaka) : Interceptor { if (currentAuth.isExpired()) { val response = chain.proceed(MangaBakaApi.refreshTokenRequest(currentAuth.refreshToken)) if (response.isSuccessful) { - currentAuth = json.decodeFromString(response.body.string()) + currentAuth = with(json) { + response.parseAs() + } setAuth(currentAuth) } else { response.close() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/dto/MangaBakaOAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/dto/MangaBakaOAuth.kt index 6ebad3b8a..d9d93a896 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/dto/MangaBakaOAuth.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangabaka/dto/MangaBakaOAuth.kt @@ -11,13 +11,8 @@ data class MangaBakaOAuth( val accessToken: String, @SerialName("refresh_token") val refreshToken: String, - @SerialName("expires_in") - val expiresIn: Long, @SerialName("expires_at") val expiresAt: Long, - @SerialName("token_type") - val tokenType: String, - val scope: String, ) { fun isExpired(): Boolean = Clock.System.now().plus(1.minutes).epochSeconds > expiresAt } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt index 938d5571e..68e7643e2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdates.kt @@ -38,7 +38,7 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker private val interceptor by lazy { MangaUpdatesInterceptor(this) } - private val api by lazy { MangaUpdatesApi(interceptor, client) } + private val api by lazy { MangaUpdatesApi(client, interceptor) } override fun getLogo(): Int = R.drawable.brand_mangaupdates @@ -83,7 +83,7 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker return try { val (series, rating) = api.getSeriesListItem(track) track.copyFrom(series, rating) - } catch (e: Exception) { + } catch (_: Exception) { track.score = 0.0 api.addSeriesToList(track, hasReadChapters) track diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt index ee1255d49..2f7223740 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/mangaupdates/MangaUpdatesApi.kt @@ -32,8 +32,8 @@ import uy.kohesive.injekt.injectLazy import tachiyomi.domain.track.model.Track as DomainTrack class MangaUpdatesApi( - interceptor: MangaUpdatesInterceptor, private val client: OkHttpClient, + interceptor: MangaUpdatesInterceptor, ) { private val json: Json by injectLazy() @@ -123,7 +123,7 @@ class MangaUpdatesApi( .awaitSuccess() .parseAs() } - } catch (e: Exception) { + } catch (_: Exception) { null } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt index 3802fee2a..a0c015e3f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt @@ -139,7 +139,7 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker { val username = api.getCurrentUser() saveDisplayUsername(username) saveCredentials(username, oauth.accessToken) - } catch (e: Throwable) { + } catch (_: Throwable) { logout() } } @@ -165,7 +165,7 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker { fun loadOAuth(): MALOAuth? { return try { json.decodeFromString(trackPreferences.trackToken(this).get()) - } catch (e: Exception) { + } catch (_: Exception) { null } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt index c7e441788..d0c21ff88 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt @@ -31,7 +31,7 @@ import java.util.Locale import tachiyomi.domain.track.model.Track as DomainTrack class MyAnimeListApi( - private val trackId: Long, + private val trackerId: Long, private val client: OkHttpClient, interceptor: MyAnimeListInterceptor, ) { @@ -223,7 +223,7 @@ class MyAnimeListApi( } private fun parseSearchItem(searchItem: MALManga): TrackSearch { - return TrackSearch.create(trackId).apply { + return TrackSearch.create(trackerId).apply { remote_id = searchItem.id title = searchItem.title summary = searchItem.synopsis diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt index ffc77c335..132e6b42c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt @@ -72,10 +72,7 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor } } .getOrNull() - ?.also { - this.oauth = it - myanimelist.saveOAuth(it) - } + ?.also { setAuth(it) } ?: throw MALTokenRefreshFailed() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALOAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALOAuth.kt index 342016bfe..a0f5332c9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALOAuth.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/dto/MALOAuth.kt @@ -3,11 +3,11 @@ package eu.kanade.tachiyomi.data.track.myanimelist.dto import kotlinx.serialization.EncodeDefault import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlin.time.Clock +import kotlin.time.Duration.Companion.minutes @Serializable data class MALOAuth( - @SerialName("token_type") - val tokenType: String, @SerialName("refresh_token") val refreshToken: String, @SerialName("access_token") @@ -16,10 +16,8 @@ data class MALOAuth( val expiresIn: Long, @SerialName("created_at") @EncodeDefault - val createdAt: Long = System.currentTimeMillis() / 1000, + val createdAt: Long = Clock.System.now().epochSeconds, ) { // Assumes expired a minute earlier - private val adjustedExpiresIn: Long = (expiresIn - 60) - - fun isExpired() = createdAt + adjustedExpiresIn < System.currentTimeMillis() / 1000 + fun isExpired() = Clock.System.now().plus(1.minutes).epochSeconds <= createdAt + expiresIn } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt index eecdccec9..20f27bd97 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt @@ -131,7 +131,7 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker { val user = api.getCurrentUser() saveDisplayUsername(user.nickname) saveCredentials(user.id, oauth.accessToken) - } catch (e: Throwable) { + } catch (_: Throwable) { logout() } } @@ -143,7 +143,7 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker { fun restoreToken(): SMOAuth? { return try { json.decodeFromString(trackPreferences.trackToken(this).get()) - } catch (e: Exception) { + } catch (_: Exception) { null } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt index 18dbb2d68..7ab177c66 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt @@ -28,7 +28,7 @@ import uy.kohesive.injekt.injectLazy import tachiyomi.domain.track.model.Track as DomainTrack class ShikimoriApi( - private val trackId: Long, + private val trackerId: Long, private val client: OkHttpClient, interceptor: ShikimoriInterceptor, ) { @@ -145,7 +145,7 @@ class ShikimoriApi( .awaitSuccess() .parseAs() .data.mangas - .map { it.toTrack(trackId) } + .map { it.toTrack(trackerId) } } } } @@ -196,7 +196,7 @@ class ShikimoriApi( .parseAs() .data.mangas .firstOrNull() - ?.toTrack(trackId) + ?.toTrack(trackerId) } } } @@ -245,7 +245,7 @@ class ShikimoriApi( if (listResult?.userRate == null) { null } else { - listResult.toTrack(trackId) + listResult.toTrack(trackerId) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt index baa65025d..7be14e99f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt @@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.data.track.shikimori import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.data.track.shikimori.dto.SMOAuth -import eu.kanade.tachiyomi.data.track.shikimori.dto.isExpired +import eu.kanade.tachiyomi.network.parseAs import kotlinx.serialization.json.Json import okhttp3.Interceptor import okhttp3.Response @@ -20,15 +20,16 @@ class ShikimoriInterceptor(private val shikimori: Shikimori) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() - val currAuth = oauth ?: throw Exception("Not authenticated with Shikimori") - - val refreshToken = currAuth.refreshToken!! + var currAuth = oauth ?: throw Exception("Not authenticated with Shikimori") // Refresh access token if expired. if (currAuth.isExpired()) { - val response = chain.proceed(ShikimoriApi.refreshTokenRequest(refreshToken)) + val response = chain.proceed(ShikimoriApi.refreshTokenRequest(currAuth.refreshToken!!)) if (response.isSuccessful) { - newAuth(json.decodeFromString(response.body.string())) + currAuth = with(json) { + response.parseAs() + } + newAuth(currAuth) } else { response.close() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMManga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMManga.kt index 16a4f35dd..ddd4e7d37 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMManga.kt @@ -28,8 +28,8 @@ data class SMManga( val kind: String?, val personRoles: List?, ) { - fun toTrack(trackId: Long): TrackSearch { - return TrackSearch.create(trackId).apply { + fun toTrack(trackerId: Long): TrackSearch { + return TrackSearch.create(trackerId).apply { remote_id = this@SMManga.id title = name total_chapters = chapters diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMOAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMOAuth.kt index e04104801..958f16182 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMOAuth.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMOAuth.kt @@ -2,20 +2,19 @@ package eu.kanade.tachiyomi.data.track.shikimori.dto import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlin.time.Clock +import kotlin.time.Duration.Companion.hours @Serializable data class SMOAuth( @SerialName("access_token") val accessToken: String, - @SerialName("token_type") - val tokenType: String, @SerialName("created_at") val createdAt: Long, @SerialName("expires_in") val expiresIn: Long, @SerialName("refresh_token") val refreshToken: String?, -) - -// Access token lives 1 day -fun SMOAuth.isExpired() = (System.currentTimeMillis() / 1000) > (createdAt + expiresIn - 3600) +) { + fun isExpired() = Clock.System.now().plus(1.hours).epochSeconds > (createdAt + expiresIn) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMUserListEntry.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMUserListEntry.kt index e7bb37666..a6b3e36cd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMUserListEntry.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/dto/SMUserListEntry.kt @@ -24,8 +24,8 @@ data class SMUserListManga( val totalChapters: Long, // the title's total chapters val userRate: SMUserRate?, ) { - fun toTrack(trackId: Long): Track { - return Track.create(trackId).apply { + fun toTrack(trackerId: Long): Track { + return Track.create(trackerId).apply { title = name total_chapters = totalChapters tracking_url = url diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt index 50d297b83..a30b120e4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/Suwayomi.kt @@ -87,7 +87,7 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker { override suspend fun match(manga: DomainManga): TrackSearch? = try { api.getTrackSearch(manga.url.getMangaId()) - } catch (e: Exception) { + } catch (_: Exception) { null } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt index 059c70968..e3280b14c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/suwayomi/SuwayomiApi.kt @@ -25,7 +25,7 @@ import uy.kohesive.injekt.injectLazy import java.security.MessageDigest class SuwayomiApi( - private val trackId: Long, + private val trackerId: Long, private val sourceManager: SourceManager, ) { @@ -71,7 +71,7 @@ class SuwayomiApi( .entry } - TrackSearch.create(trackId).apply { + TrackSearch.create(trackerId).apply { remote_id = mangaId title = manga.title cover_url = "$baseUrl/${manga.thumbnailUrl}" @@ -152,15 +152,13 @@ class SuwayomiApi( } } } - with(json) { - client.newCall( - POST( - apiUrl, - body = markPayload.toString().toRequestBody(jsonMime), - ), - ) - .awaitSuccess() - } + client.newCall( + POST( + apiUrl, + body = markPayload.toString().toRequestBody(jsonMime), + ), + ) + .awaitSuccess() val trackQuery = $$""" |mutation TrackManga($mangaId: Int!) { @@ -175,15 +173,13 @@ class SuwayomiApi( put("mangaId", mangaId) } } - with(json) { - client.newCall( - POST( - apiUrl, - body = trackPayload.toString().toRequestBody(jsonMime), - ), - ) - .awaitSuccess() - } + client.newCall( + POST( + apiUrl, + body = trackPayload.toString().toRequestBody(jsonMime), + ), + ) + .awaitSuccess() return getTrackSearch(track.remote_id) }