Added Start/Finished Date Support to AniList
Based on 1e3de8a67f
Co-Authored-By: Jays2Kings
This commit is contained in:
parent
472ce5a5e4
commit
2ba60e9114
@ -35,6 +35,8 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
|||||||
|
|
||||||
private val api by lazy { AnilistApi(client, interceptor) }
|
private val api by lazy { AnilistApi(client, interceptor) }
|
||||||
|
|
||||||
|
override val supportsReadingDates: Boolean = true
|
||||||
|
|
||||||
private val scorePreference = preferences.anilistScoreType()
|
private val scorePreference = preferences.anilistScoreType()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.data.track.anilist
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.core.net.toUri
|
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.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
import eu.kanade.tachiyomi.network.POST
|
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.jsonMime
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||||
|
import kotlinx.serialization.json.JsonNull
|
||||||
import kotlinx.serialization.json.JsonObject
|
import kotlinx.serialization.json.JsonObject
|
||||||
import kotlinx.serialization.json.buildJsonObject
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
import kotlinx.serialization.json.contentOrNull
|
import kotlinx.serialization.json.contentOrNull
|
||||||
@ -30,8 +34,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
|
|
||||||
suspend fun addLibManga(track: Track): Track {
|
suspend fun addLibManga(track: Track): Track {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val query =
|
val query = """
|
||||||
"""
|
|
||||||
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
|
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
|
||||||
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) {
|
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) {
|
||||||
| id
|
| id
|
||||||
@ -65,10 +68,15 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
|
|
||||||
suspend fun updateLibManga(track: Track): Track {
|
suspend fun updateLibManga(track: Track): Track {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val query =
|
val query = """
|
||||||
"""
|
|mutation UpdateManga(
|
||||||
|mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
|
|${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus,
|
||||||
|SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) {
|
|${'$'}score: Int, ${'$'}startedAt: FuzzyDateInput, ${'$'}completedAt: FuzzyDateInput
|
||||||
|
|) {
|
||||||
|
|SaveMediaListEntry(
|
||||||
|
|id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status,
|
||||||
|
|scoreRaw: ${'$'}score, startedAt: ${'$'}startedAt, completedAt: ${'$'}completedAt
|
||||||
|
|) {
|
||||||
|id
|
|id
|
||||||
|status
|
|status
|
||||||
|progress
|
|progress
|
||||||
@ -82,6 +90,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
put("progress", track.last_chapter_read)
|
put("progress", track.last_chapter_read)
|
||||||
put("status", track.toAnilistStatus())
|
put("status", track.toAnilistStatus())
|
||||||
put("score", track.score.toInt())
|
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)))
|
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<TrackSearch> {
|
suspend fun search(search: String): List<TrackSearch> {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val query =
|
val query = """
|
||||||
"""
|
|
||||||
|query Search(${'$'}query: String) {
|
|query Search(${'$'}query: String) {
|
||||||
|Page (perPage: 50) {
|
|Page (perPage: 50) {
|
||||||
|media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) {
|
|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? {
|
suspend fun findLibManga(track: Track, userid: Int): Track? {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val query =
|
val query = """
|
||||||
"""
|
|
||||||
|query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
|
|query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
|
||||||
|Page {
|
|Page {
|
||||||
|mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) {
|
|mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) {
|
||||||
@ -152,6 +160,16 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
|status
|
|status
|
||||||
|scoreRaw: score(format: POINT_100)
|
|scoreRaw: score(format: POINT_100)
|
||||||
|progress
|
|progress
|
||||||
|
|startedAt {
|
||||||
|
|year
|
||||||
|
|month
|
||||||
|
|day
|
||||||
|
|}
|
||||||
|
|completedAt {
|
||||||
|
|year
|
||||||
|
|month
|
||||||
|
|day
|
||||||
|
|}
|
||||||
|media {
|
|media {
|
||||||
|id
|
|id
|
||||||
|title {
|
|title {
|
||||||
@ -209,8 +227,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
|
|
||||||
suspend fun getCurrentUser(): Pair<Int, String> {
|
suspend fun getCurrentUser(): Pair<Int, String> {
|
||||||
return withIOContext {
|
return withIOContext {
|
||||||
val query =
|
val query = """
|
||||||
"""
|
|
||||||
|query User {
|
|query User {
|
||||||
|Viewer {
|
|Viewer {
|
||||||
|id
|
|id
|
||||||
@ -243,18 +260,6 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun jsonToALManga(struct: JsonObject): ALManga {
|
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(
|
return ALManga(
|
||||||
struct["id"]!!.jsonPrimitive.int,
|
struct["id"]!!.jsonPrimitive.int,
|
||||||
struct["title"]!!.jsonObject["romaji"]!!.jsonPrimitive.content,
|
struct["title"]!!.jsonObject["romaji"]!!.jsonPrimitive.content,
|
||||||
@ -262,7 +267,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
struct["description"]!!.jsonPrimitive.contentOrNull,
|
struct["description"]!!.jsonPrimitive.contentOrNull,
|
||||||
struct["type"]!!.jsonPrimitive.content,
|
struct["type"]!!.jsonPrimitive.content,
|
||||||
struct["status"]!!.jsonPrimitive.contentOrNull ?: "",
|
struct["status"]!!.jsonPrimitive.contentOrNull ?: "",
|
||||||
date,
|
parseDate(struct, "startDate"),
|
||||||
struct["chapters"]!!.jsonPrimitive.intOrNull ?: 0
|
struct["chapters"]!!.jsonPrimitive.intOrNull ?: 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -273,10 +278,44 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||||||
struct["status"]!!.jsonPrimitive.content,
|
struct["status"]!!.jsonPrimitive.content,
|
||||||
struct["scoreRaw"]!!.jsonPrimitive.int,
|
struct["scoreRaw"]!!.jsonPrimitive.int,
|
||||||
struct["progress"]!!.jsonPrimitive.int,
|
struct["progress"]!!.jsonPrimitive.int,
|
||||||
|
parseDate(struct, "startedAt"),
|
||||||
|
parseDate(struct, "completedAt"),
|
||||||
jsonToALManga(struct["media"]!!.jsonObject)
|
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 {
|
companion object {
|
||||||
private const val clientId = "385"
|
private const val clientId = "385"
|
||||||
private const val apiUrl = "https://graphql.anilist.co/"
|
private const val apiUrl = "https://graphql.anilist.co/"
|
||||||
|
@ -44,6 +44,8 @@ data class ALUserManga(
|
|||||||
val list_status: String,
|
val list_status: String,
|
||||||
val score_raw: Int,
|
val score_raw: Int,
|
||||||
val chapters_read: Int,
|
val chapters_read: Int,
|
||||||
|
val start_date_fuzzy: Long,
|
||||||
|
val completed_date_fuzzy: Long,
|
||||||
val manga: ALManga
|
val manga: ALManga
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -51,6 +53,8 @@ data class ALUserManga(
|
|||||||
media_id = manga.media_id
|
media_id = manga.media_id
|
||||||
status = toTrackStatus()
|
status = toTrackStatus()
|
||||||
score = score_raw.toFloat()
|
score = score_raw.toFloat()
|
||||||
|
started_reading_date = start_date_fuzzy
|
||||||
|
finished_reading_date = completed_date_fuzzy
|
||||||
last_chapter_read = chapters_read
|
last_chapter_read = chapters_read
|
||||||
library_id = this@ALUserManga.library_id
|
library_id = this@ALUserManga.library_id
|
||||||
total_chapters = manga.total_chapters
|
total_chapters = manga.total_chapters
|
||||||
|
Loading…
Reference in New Issue
Block a user