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 d9b0a56a67..7ebabfd50d 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,6 +35,8 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) { private val api by lazy { AnilistApi(client, interceptor) } + override val supportsReadingDates: Boolean = true + private val scorePreference = preferences.anilistScoreType() init { 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 cd0fcad186..18da573a68 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 @@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.data.track.anilist import android.net.Uri import androidx.core.net.toUri +import com.afollestad.date.dayOfMonth +import com.afollestad.date.month +import com.afollestad.date.year import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.POST @@ -9,6 +12,7 @@ import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.jsonMime import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.util.lang.withIOContext +import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.contentOrNull @@ -30,8 +34,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { suspend fun addLibManga(track: Track): Track { return withIOContext { - val query = - """ + val query = """ |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { |SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) { | id @@ -65,10 +68,15 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { suspend fun updateLibManga(track: Track): Track { return withIOContext { - val query = - """ - |mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) { - |SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) { + val query = """ + |mutation UpdateManga( + |${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, + |${'$'}score: Int, ${'$'}startedAt: FuzzyDateInput, ${'$'}completedAt: FuzzyDateInput + |) { + |SaveMediaListEntry( + |id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, + |scoreRaw: ${'$'}score, startedAt: ${'$'}startedAt, completedAt: ${'$'}completedAt + |) { |id |status |progress @@ -82,6 +90,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { put("progress", track.last_chapter_read) put("status", track.toAnilistStatus()) put("score", track.score.toInt()) + put("startedAt", createDate(track.started_reading_date)) + put("completedAt", createDate(track.finished_reading_date)) } } authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime))) @@ -92,8 +102,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { suspend fun search(search: String): List { return withIOContext { - val query = - """ + val query = """ |query Search(${'$'}query: String) { |Page (perPage: 50) { |media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) { @@ -143,8 +152,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { suspend fun findLibManga(track: Track, userid: Int): Track? { return withIOContext { - val query = - """ + val query = """ |query (${'$'}id: Int!, ${'$'}manga_id: Int!) { |Page { |mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) { @@ -152,6 +160,16 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { |status |scoreRaw: score(format: POINT_100) |progress + |startedAt { + |year + |month + |day + |} + |completedAt { + |year + |month + |day + |} |media { |id |title { @@ -209,8 +227,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { suspend fun getCurrentUser(): Pair { return withIOContext { - val query = - """ + val query = """ |query User { |Viewer { |id @@ -243,18 +260,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } private fun jsonToALManga(struct: JsonObject): ALManga { - val date = try { - val date = Calendar.getInstance() - date.set( - struct["startDate"]!!.jsonObject["year"]!!.jsonPrimitive.int, - struct["startDate"]!!.jsonObject["month"]!!.jsonPrimitive.int - 1, - struct["startDate"]!!.jsonObject["day"]!!.jsonPrimitive.int - ) - date.timeInMillis - } catch (_: Exception) { - 0L - } - return ALManga( struct["id"]!!.jsonPrimitive.int, struct["title"]!!.jsonObject["romaji"]!!.jsonPrimitive.content, @@ -262,7 +267,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { struct["description"]!!.jsonPrimitive.contentOrNull, struct["type"]!!.jsonPrimitive.content, struct["status"]!!.jsonPrimitive.contentOrNull ?: "", - date, + parseDate(struct, "startDate"), struct["chapters"]!!.jsonPrimitive.intOrNull ?: 0 ) } @@ -273,10 +278,44 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { struct["status"]!!.jsonPrimitive.content, struct["scoreRaw"]!!.jsonPrimitive.int, struct["progress"]!!.jsonPrimitive.int, + parseDate(struct, "startedAt"), + parseDate(struct, "completedAt"), jsonToALManga(struct["media"]!!.jsonObject) ) } + private fun parseDate(struct: JsonObject, dateKey: String): Long { + return try { + val date = Calendar.getInstance() + date.set( + struct[dateKey]!!.jsonObject["year"]!!.jsonPrimitive.int, + struct[dateKey]!!.jsonObject["month"]!!.jsonPrimitive.int - 1, + struct[dateKey]!!.jsonObject["day"]!!.jsonPrimitive.int + ) + date.timeInMillis + } catch (_: Exception) { + 0L + } + } + + private fun createDate(dateValue: Long): JsonObject { + if (dateValue == 0L) { + return buildJsonObject { + put("year", JsonNull) + put("month", JsonNull) + put("day", JsonNull) + } + } + + val calendar = Calendar.getInstance() + calendar.timeInMillis = dateValue + return buildJsonObject { + put("year", calendar.year) + put("month", calendar.month + 1) + put("day", calendar.dayOfMonth) + } + } + companion object { private const val clientId = "385" private const val apiUrl = "https://graphql.anilist.co/" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt index 592ba1d589..0b3a9c6f33 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt @@ -44,6 +44,8 @@ data class ALUserManga( val list_status: String, val score_raw: Int, val chapters_read: Int, + val start_date_fuzzy: Long, + val completed_date_fuzzy: Long, val manga: ALManga ) { @@ -51,6 +53,8 @@ data class ALUserManga( media_id = manga.media_id status = toTrackStatus() score = score_raw.toFloat() + started_reading_date = start_date_fuzzy + finished_reading_date = completed_date_fuzzy last_chapter_read = chapters_read library_id = this@ALUserManga.library_id total_chapters = manga.total_chapters