Some domain Track model migrations
This commit is contained in:
parent
5908bd1930
commit
6d74a86711
28 changed files with 129 additions and 127 deletions
|
@ -16,7 +16,7 @@ fun Track.copyPersonalFrom(other: Track): Track {
|
|||
fun Track.toDbTrack(): DbTrack = DbTrack.create(syncId).also {
|
||||
it.id = id
|
||||
it.manga_id = mangaId
|
||||
it.media_id = remoteId
|
||||
it.remote_id = remoteId
|
||||
it.library_id = libraryId
|
||||
it.title = title
|
||||
it.last_chapter_read = lastChapterRead.toFloat()
|
||||
|
@ -34,7 +34,7 @@ fun DbTrack.toDomainTrack(idRequired: Boolean = true): Track? {
|
|||
id = trackId,
|
||||
mangaId = manga_id,
|
||||
syncId = sync_id.toLong(),
|
||||
remoteId = media_id,
|
||||
remoteId = remote_id,
|
||||
libraryId = library_id,
|
||||
title = title,
|
||||
lastChapterRead = last_chapter_read.toDouble(),
|
||||
|
|
|
@ -47,7 +47,6 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.presentation.track.components.TrackLogoIcon
|
||||
|
@ -101,7 +100,7 @@ fun TrackInfoDialogHome(
|
|||
}
|
||||
},
|
||||
onChaptersClick = { onChapterClick(item) },
|
||||
score = item.tracker.displayScore(item.track.toDbTrack())
|
||||
score = item.tracker.displayScore(item.track)
|
||||
.takeIf { supportsScoring && item.track.score != 0.0 },
|
||||
onScoreClick = { onScoreClick(item) }
|
||||
.takeIf { supportsScoring },
|
||||
|
|
|
@ -63,7 +63,7 @@ internal class TrackerSearchPreviewProvider : PreviewParameterProvider<@Composab
|
|||
it.id = Random.nextLong()
|
||||
it.manga_id = Random.nextLong()
|
||||
it.sync_id = Random.nextInt()
|
||||
it.media_id = Random.nextLong()
|
||||
it.remote_id = Random.nextLong()
|
||||
it.library_id = Random.nextLong()
|
||||
it.title = lorem((1..10).random()).joinToString()
|
||||
it.last_chapter_read = (0..100).random().toFloat()
|
||||
|
|
|
@ -10,7 +10,7 @@ interface Track : Serializable {
|
|||
|
||||
var sync_id: Int
|
||||
|
||||
var media_id: Long
|
||||
var remote_id: Long
|
||||
|
||||
var library_id: Long?
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ class TrackImpl : Track {
|
|||
|
||||
override var sync_id: Int = 0
|
||||
|
||||
override var media_id: Long = 0
|
||||
override var remote_id: Long = 0
|
||||
|
||||
override var library_id: Long? = null
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package eu.kanade.tachiyomi.data.track
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import tachiyomi.domain.track.model.Track
|
||||
|
||||
/**
|
||||
* Tracker that support deleting am entry from a user's list.
|
||||
*/
|
||||
interface DeletableTracker {
|
||||
|
||||
suspend fun delete(track: Track): Track
|
||||
suspend fun delete(track: Track)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
|||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import okhttp3.OkHttpClient
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
interface Tracker {
|
||||
|
||||
|
@ -39,11 +40,11 @@ interface Tracker {
|
|||
fun getScoreList(): ImmutableList<String>
|
||||
|
||||
// TODO: Store all scores as 10 point in the future maybe?
|
||||
fun get10PointScore(track: tachiyomi.domain.track.model.Track): Double
|
||||
fun get10PointScore(track: DomainTrack): Double
|
||||
|
||||
fun indexToScore(index: Int): Float
|
||||
|
||||
fun displayScore(track: Track): String
|
||||
fun displayScore(track: DomainTrack): String
|
||||
|
||||
suspend fun update(track: Track, didReadChapter: Boolean = false): Track
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.track.anilist
|
|||
|
||||
import android.graphics.Color
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
|
@ -120,16 +121,16 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
|
|||
}
|
||||
}
|
||||
|
||||
override fun displayScore(track: Track): String {
|
||||
override fun displayScore(track: DomainTrack): String {
|
||||
val score = track.score
|
||||
|
||||
return when (scorePreference.get()) {
|
||||
POINT_5 -> when (score) {
|
||||
0f -> "0 ★"
|
||||
0.0 -> "0 ★"
|
||||
else -> "${((score + 10) / 20).toInt()} ★"
|
||||
}
|
||||
POINT_3 -> when {
|
||||
score == 0f -> "0"
|
||||
score == 0.0 -> "0"
|
||||
score <= 35 -> "😦"
|
||||
score <= 60 -> "😐"
|
||||
else -> "😊"
|
||||
|
@ -167,13 +168,13 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
|
|||
return api.updateLibManga(track)
|
||||
}
|
||||
|
||||
override suspend fun delete(track: Track): Track {
|
||||
if (track.library_id == null || track.library_id!! == 0L) {
|
||||
val libManga = api.findLibManga(track, getUsername().toInt()) ?: return track
|
||||
track.library_id = libManga.library_id
|
||||
override suspend fun delete(track: DomainTrack) {
|
||||
if (track.libraryId == null || track.libraryId == 0L) {
|
||||
val libManga = api.findLibManga(track.toDbTrack(), getUsername().toInt()) ?: return
|
||||
return api.deleteLibManga(track.copy(id = libManga.library_id!!))
|
||||
}
|
||||
|
||||
return api.deleteLibManga(track)
|
||||
api.deleteLibManga(track)
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.time.LocalDate
|
|||
import java.time.ZoneId
|
||||
import java.time.ZonedDateTime
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|
||||
|
@ -55,7 +56,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
val payload = buildJsonObject {
|
||||
put("query", query)
|
||||
putJsonObject("variables") {
|
||||
put("mangaId", track.media_id)
|
||||
put("mangaId", track.remote_id)
|
||||
put("progress", track.last_chapter_read.toInt())
|
||||
put("status", track.toAnilistStatus())
|
||||
}
|
||||
|
@ -113,8 +114,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun deleteLibManga(track: Track): Track {
|
||||
return withIOContext {
|
||||
suspend fun deleteLibManga(track: DomainTrack) {
|
||||
withIOContext {
|
||||
val query = """
|
||||
|mutation DeleteManga(${'$'}listId: Int) {
|
||||
|DeleteMediaListEntry(id: ${'$'}listId) {
|
||||
|
@ -126,12 +127,11 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
val payload = buildJsonObject {
|
||||
put("query", query)
|
||||
putJsonObject("variables") {
|
||||
put("listId", track.library_id)
|
||||
put("listId", track.libraryId)
|
||||
}
|
||||
}
|
||||
authClient.newCall(POST(apiUrl, body = payload.toString().toRequestBody(jsonMime)))
|
||||
.awaitSuccess()
|
||||
track
|
||||
}
|
||||
}
|
||||
suspend fun search(search: String): List<TrackSearch> {
|
||||
|
@ -235,7 +235,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
put("query", query)
|
||||
putJsonObject("variables") {
|
||||
put("id", userid)
|
||||
put("manga_id", track.media_id)
|
||||
put("manga_id", track.remote_id)
|
||||
}
|
||||
}
|
||||
with(json) {
|
||||
|
@ -258,8 +258,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun getLibManga(track: Track, userid: Int): Track {
|
||||
return findLibManga(track, userid) ?: throw Exception("Could not find manga")
|
||||
suspend fun getLibManga(track: Track, userId: Int): Track {
|
||||
return findLibManga(track, userId) ?: throw Exception("Could not find manga")
|
||||
}
|
||||
|
||||
fun createOAuth(token: String): OAuth {
|
||||
|
|
|
@ -9,9 +9,10 @@ import kotlinx.serialization.Serializable
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
data class ALManga(
|
||||
val media_id: Long,
|
||||
val remote_id: Long,
|
||||
val title_user_pref: String,
|
||||
val image_url_lge: String,
|
||||
val description: String?,
|
||||
|
@ -23,13 +24,13 @@ data class ALManga(
|
|||
) {
|
||||
|
||||
fun toTrack() = TrackSearch.create(TrackerManager.ANILIST).apply {
|
||||
media_id = this@ALManga.media_id
|
||||
remote_id = this@ALManga.remote_id
|
||||
title = title_user_pref
|
||||
total_chapters = this@ALManga.total_chapters
|
||||
cover_url = image_url_lge
|
||||
summary = description?.htmlDecode() ?: ""
|
||||
score = average_score.toFloat()
|
||||
tracking_url = AnilistApi.mangaUrl(media_id)
|
||||
tracking_url = AnilistApi.mangaUrl(remote_id)
|
||||
publishing_status = this@ALManga.publishing_status
|
||||
publishing_type = format
|
||||
if (start_date_fuzzy != 0L) {
|
||||
|
@ -54,7 +55,7 @@ data class ALUserManga(
|
|||
) {
|
||||
|
||||
fun toTrack() = Track.create(TrackerManager.ANILIST).apply {
|
||||
media_id = manga.media_id
|
||||
remote_id = manga.remote_id
|
||||
title = manga.title_user_pref
|
||||
status = toTrackStatus()
|
||||
score = score_raw.toFloat()
|
||||
|
@ -98,28 +99,28 @@ fun Track.toAnilistStatus() = when (status) {
|
|||
|
||||
private val preferences: TrackPreferences by injectLazy()
|
||||
|
||||
fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().get()) {
|
||||
// 10 point
|
||||
fun DomainTrack.toAnilistScore(): String = when (preferences.anilistScoreType().get()) {
|
||||
// 10 point
|
||||
"POINT_10" -> (score.toInt() / 10).toString()
|
||||
// 100 point
|
||||
// 100 point
|
||||
"POINT_100" -> score.toInt().toString()
|
||||
// 5 stars
|
||||
// 5 stars
|
||||
"POINT_5" -> when {
|
||||
score == 0f -> "0"
|
||||
score == 0.0 -> "0"
|
||||
score < 30 -> "1"
|
||||
score < 50 -> "2"
|
||||
score < 70 -> "3"
|
||||
score < 90 -> "4"
|
||||
else -> "5"
|
||||
}
|
||||
// Smiley
|
||||
// Smiley
|
||||
"POINT_3" -> when {
|
||||
score == 0f -> "0"
|
||||
score == 0.0 -> "0"
|
||||
score <= 35 -> ":("
|
||||
score <= 60 -> ":|"
|
||||
else -> ":)"
|
||||
}
|
||||
// 10 point decimal
|
||||
// 10 point decimal
|
||||
"POINT_10_DECIMAL" -> (score / 10).toString()
|
||||
else -> throw NotImplementedError("Unknown score type")
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
|
||||
|
||||
|
@ -23,7 +24,7 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
|
|||
|
||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||
|
||||
override fun displayScore(track: Track): String {
|
||||
override fun displayScore(track: DomainTrack): String {
|
||||
return track.score.toInt().toString()
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class BangumiApi(
|
|||
.add("rating", track.score.toInt().toString())
|
||||
.add("status", track.toBangumiStatus())
|
||||
.build()
|
||||
authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = body))
|
||||
authClient.newCall(POST("$apiUrl/collection/${track.remote_id}/update", body = body))
|
||||
.awaitSuccess()
|
||||
track
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class BangumiApi(
|
|||
.add("rating", track.score.toInt().toString())
|
||||
.add("status", track.toBangumiStatus())
|
||||
.build()
|
||||
authClient.newCall(POST("$apiUrl/collection/${track.media_id}/update", body = sbody))
|
||||
authClient.newCall(POST("$apiUrl/collection/${track.remote_id}/update", body = sbody))
|
||||
.awaitSuccess()
|
||||
|
||||
// chapter update
|
||||
|
@ -64,7 +64,7 @@ class BangumiApi(
|
|||
.build()
|
||||
authClient.newCall(
|
||||
POST(
|
||||
"$apiUrl/subject/${track.media_id}/update/watched_eps",
|
||||
"$apiUrl/subject/${track.remote_id}/update/watched_eps",
|
||||
body = body,
|
||||
),
|
||||
).awaitSuccess()
|
||||
|
@ -111,7 +111,7 @@ class BangumiApi(
|
|||
}
|
||||
val rating = obj["rating"]?.jsonObject?.get("score")?.jsonPrimitive?.floatOrNull ?: -1f
|
||||
return TrackSearch.create(trackId).apply {
|
||||
media_id = obj["id"]!!.jsonPrimitive.long
|
||||
remote_id = obj["id"]!!.jsonPrimitive.long
|
||||
title = obj["name_cn"]!!.jsonPrimitive.content
|
||||
cover_url = coverUrl
|
||||
summary = obj["name"]!!.jsonPrimitive.content
|
||||
|
@ -124,7 +124,7 @@ class BangumiApi(
|
|||
suspend fun findLibManga(track: Track): Track? {
|
||||
return withIOContext {
|
||||
with(json) {
|
||||
authClient.newCall(GET("$apiUrl/subject/${track.media_id}"))
|
||||
authClient.newCall(GET("$apiUrl/subject/${track.remote_id}"))
|
||||
.awaitSuccess()
|
||||
.parseAs<JsonObject>()
|
||||
.let { jsonToSearch(it) }
|
||||
|
@ -134,7 +134,7 @@ class BangumiApi(
|
|||
|
||||
suspend fun statusLibManga(track: Track): Track? {
|
||||
return withIOContext {
|
||||
val urlUserRead = "$apiUrl/collection/${track.media_id}"
|
||||
val urlUserRead = "$apiUrl/collection/${track.remote_id}"
|
||||
val requestUserRead = Request.Builder()
|
||||
.url(urlUserRead)
|
||||
.cacheControl(CacheControl.FORCE_NETWORK)
|
||||
|
|
|
@ -55,7 +55,7 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker {
|
|||
|
||||
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||
|
||||
override fun displayScore(track: Track): String = ""
|
||||
override fun displayScore(track: DomainTrack): String = ""
|
||||
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETED) {
|
||||
|
|
|
@ -14,6 +14,7 @@ import kotlinx.serialization.json.Json
|
|||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DecimalFormat
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker {
|
||||
|
||||
|
@ -65,7 +66,7 @@ class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker {
|
|||
return if (index > 0) (index + 1) / 2f else 0f
|
||||
}
|
||||
|
||||
override fun displayScore(track: Track): String {
|
||||
override fun displayScore(track: DomainTrack): String {
|
||||
val df = DecimalFormat("0.#")
|
||||
return df.format(track.score)
|
||||
}
|
||||
|
@ -92,15 +93,15 @@ class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker {
|
|||
return api.updateLibManga(track)
|
||||
}
|
||||
|
||||
override suspend fun delete(track: Track): Track {
|
||||
return api.removeLibManga(track)
|
||||
override suspend fun delete(track: DomainTrack) {
|
||||
api.removeLibManga(track)
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
val remoteTrack = api.findLibManga(track, getUserId())
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.media_id = remoteTrack.media_id
|
||||
track.remote_id = remoteTrack.remote_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
track.status = if (hasReadChapters) READING else track.status
|
||||
|
|
|
@ -29,6 +29,7 @@ import tachiyomi.core.util.lang.withIOContext
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) {
|
||||
|
||||
|
@ -54,7 +55,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
}
|
||||
putJsonObject("media") {
|
||||
putJsonObject("data") {
|
||||
put("id", track.media_id)
|
||||
put("id", track.remote_id)
|
||||
put("type", "manga")
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +78,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
.awaitSuccess()
|
||||
.parseAs<JsonObject>()
|
||||
.let {
|
||||
track.media_id = it["data"]!!.jsonObject["id"]!!.jsonPrimitive.long
|
||||
track.remote_id = it["data"]!!.jsonObject["id"]!!.jsonPrimitive.long
|
||||
track
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +90,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
val data = buildJsonObject {
|
||||
putJsonObject("data") {
|
||||
put("type", "libraryEntries")
|
||||
put("id", track.media_id)
|
||||
put("id", track.remote_id)
|
||||
putJsonObject("attributes") {
|
||||
put("status", track.toKitsuStatus())
|
||||
put("progress", track.last_chapter_read.toInt())
|
||||
|
@ -103,7 +104,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
with(json) {
|
||||
authClient.newCall(
|
||||
Request.Builder()
|
||||
.url("${baseUrl}library-entries/${track.media_id}")
|
||||
.url("${baseUrl}library-entries/${track.remote_id}")
|
||||
.headers(
|
||||
headersOf(
|
||||
"Content-Type",
|
||||
|
@ -124,19 +125,19 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun removeLibManga(track: Track): Track {
|
||||
return withIOContext {
|
||||
authClient.newCall(
|
||||
DELETE(
|
||||
"${baseUrl}library-entries/${track.media_id}",
|
||||
headers = headersOf(
|
||||
"Content-Type",
|
||||
"application/vnd.api+json",
|
||||
suspend fun removeLibManga(track: DomainTrack) {
|
||||
withIOContext {
|
||||
authClient
|
||||
.newCall(
|
||||
DELETE(
|
||||
"${baseUrl}library-entries/${track.remoteId}",
|
||||
headers = headersOf(
|
||||
"Content-Type",
|
||||
"application/vnd.api+json",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
.awaitSuccess()
|
||||
track
|
||||
}
|
||||
}
|
||||
suspend fun search(query: String): List<TrackSearch> {
|
||||
|
@ -187,7 +188,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
suspend fun findLibManga(track: Track, userId: String): Track? {
|
||||
return withIOContext {
|
||||
val url = "${baseUrl}library-entries".toUri().buildUpon()
|
||||
.encodedQuery("filter[manga_id]=${track.media_id}&filter[user_id]=$userId")
|
||||
.encodedQuery("filter[manga_id]=${track.remote_id}&filter[user_id]=$userId")
|
||||
.appendQueryParameter("include", "manga")
|
||||
.build()
|
||||
with(json) {
|
||||
|
@ -210,7 +211,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||
suspend fun getLibManga(track: Track): Track {
|
||||
return withIOContext {
|
||||
val url = "${baseUrl}library-entries".toUri().buildUpon()
|
||||
.encodedQuery("filter[id]=${track.media_id}")
|
||||
.encodedQuery("filter[id]=${track.remote_id}")
|
||||
.appendQueryParameter("include", "manga")
|
||||
.build()
|
||||
with(json) {
|
||||
|
|
|
@ -37,12 +37,12 @@ class KitsuSearchManga(obj: JsonObject) {
|
|||
|
||||
@CallSuper
|
||||
fun toTrack() = TrackSearch.create(TrackerManager.KITSU).apply {
|
||||
media_id = this@KitsuSearchManga.id
|
||||
remote_id = this@KitsuSearchManga.id
|
||||
title = canonicalTitle
|
||||
total_chapters = chapterCount ?: 0
|
||||
cover_url = original ?: ""
|
||||
summary = synopsis ?: ""
|
||||
tracking_url = KitsuApi.mangaUrl(media_id)
|
||||
tracking_url = KitsuApi.mangaUrl(remote_id)
|
||||
score = rating ?: -1f
|
||||
publishing_status = if (endDate == null) {
|
||||
"Publishing"
|
||||
|
@ -70,12 +70,12 @@ class KitsuLibManga(obj: JsonObject, manga: JsonObject) {
|
|||
val progress = obj["attributes"]!!.jsonObject["progress"]!!.jsonPrimitive.int
|
||||
|
||||
fun toTrack() = TrackSearch.create(TrackerManager.KITSU).apply {
|
||||
media_id = libraryId
|
||||
remote_id = libraryId
|
||||
title = canonicalTitle
|
||||
total_chapters = chapterCount ?: 0
|
||||
cover_url = original
|
||||
summary = synopsis
|
||||
tracking_url = KitsuApi.mangaUrl(media_id)
|
||||
tracking_url = KitsuApi.mangaUrl(remote_id)
|
||||
publishing_status = this@KitsuLibManga.status
|
||||
publishing_type = type
|
||||
start_date = startDate
|
||||
|
|
|
@ -52,7 +52,7 @@ class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedTracker {
|
|||
|
||||
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||
|
||||
override fun displayScore(track: Track): String = ""
|
||||
override fun displayScore(track: DomainTrack): String = ""
|
||||
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETED) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
|||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker {
|
||||
|
||||
|
@ -60,7 +61,7 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker
|
|||
|
||||
override fun indexToScore(index: Int): Float = SCORE_LIST[index].toFloat()
|
||||
|
||||
override fun displayScore(track: Track): String = track.score.toString()
|
||||
override fun displayScore(track: DomainTrack): String = track.score.toString()
|
||||
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETE_LIST && didReadChapter) {
|
||||
|
@ -70,9 +71,8 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker
|
|||
return track
|
||||
}
|
||||
|
||||
override suspend fun delete(track: Track): Track {
|
||||
override suspend fun delete(track: DomainTrack) {
|
||||
api.deleteSeriesFromList(track)
|
||||
return track
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
|
|
|
@ -30,6 +30,7 @@ import okhttp3.OkHttpClient
|
|||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class MangaUpdatesApi(
|
||||
interceptor: MangaUpdatesInterceptor,
|
||||
|
@ -48,7 +49,7 @@ class MangaUpdatesApi(
|
|||
|
||||
suspend fun getSeriesListItem(track: Track): Pair<ListItem, Rating?> {
|
||||
val listItem = with(json) {
|
||||
authClient.newCall(GET("$baseUrl/v1/lists/series/${track.media_id}"))
|
||||
authClient.newCall(GET("$baseUrl/v1/lists/series/${track.remote_id}"))
|
||||
.awaitSuccess()
|
||||
.parseAs<ListItem>()
|
||||
}
|
||||
|
@ -63,7 +64,7 @@ class MangaUpdatesApi(
|
|||
val body = buildJsonArray {
|
||||
addJsonObject {
|
||||
putJsonObject("series") {
|
||||
put("id", track.media_id)
|
||||
put("id", track.remote_id)
|
||||
}
|
||||
put("list_id", status)
|
||||
}
|
||||
|
@ -87,7 +88,7 @@ class MangaUpdatesApi(
|
|||
val body = buildJsonArray {
|
||||
addJsonObject {
|
||||
putJsonObject("series") {
|
||||
put("id", track.media_id)
|
||||
put("id", track.remote_id)
|
||||
}
|
||||
put("list_id", track.status)
|
||||
putJsonObject("status") {
|
||||
|
@ -106,9 +107,9 @@ class MangaUpdatesApi(
|
|||
updateSeriesRating(track)
|
||||
}
|
||||
|
||||
suspend fun deleteSeriesFromList(track: Track) {
|
||||
suspend fun deleteSeriesFromList(track: DomainTrack) {
|
||||
val body = buildJsonArray {
|
||||
add(track.media_id)
|
||||
add(track.remoteId)
|
||||
}
|
||||
authClient.newCall(
|
||||
POST(
|
||||
|
@ -122,7 +123,7 @@ class MangaUpdatesApi(
|
|||
private suspend fun getSeriesRating(track: Track): Rating? {
|
||||
return try {
|
||||
with(json) {
|
||||
authClient.newCall(GET("$baseUrl/v1/series/${track.media_id}/rating"))
|
||||
authClient.newCall(GET("$baseUrl/v1/series/${track.remote_id}/rating"))
|
||||
.awaitSuccess()
|
||||
.parseAs<Rating>()
|
||||
}
|
||||
|
@ -138,7 +139,7 @@ class MangaUpdatesApi(
|
|||
}
|
||||
authClient.newCall(
|
||||
PUT(
|
||||
url = "$baseUrl/v1/series/${track.media_id}/rating",
|
||||
url = "$baseUrl/v1/series/${track.remote_id}/rating",
|
||||
body = body.toString().toRequestBody(contentType),
|
||||
),
|
||||
)
|
||||
|
@ -146,7 +147,7 @@ class MangaUpdatesApi(
|
|||
} else {
|
||||
authClient.newCall(
|
||||
DELETE(
|
||||
url = "$baseUrl/v1/series/${track.media_id}/rating",
|
||||
url = "$baseUrl/v1/series/${track.remote_id}/rating",
|
||||
),
|
||||
)
|
||||
.awaitSuccess()
|
||||
|
|
|
@ -25,7 +25,7 @@ data class Record(
|
|||
|
||||
fun Record.toTrackSearch(id: Long): TrackSearch {
|
||||
return TrackSearch.create(id).apply {
|
||||
media_id = this@toTrackSearch.seriesId ?: 0L
|
||||
remote_id = this@toTrackSearch.seriesId ?: 0L
|
||||
title = this@toTrackSearch.title?.htmlDecode() ?: ""
|
||||
total_chapters = 0
|
||||
cover_url = this@toTrackSearch.image?.url?.original ?: ""
|
||||
|
|
|
@ -10,7 +10,7 @@ class TrackSearch : Track {
|
|||
|
||||
override var sync_id: Int = 0
|
||||
|
||||
override var media_id: Long = 0
|
||||
override var remote_id: Long = 0
|
||||
|
||||
override var library_id: Long? = null
|
||||
|
||||
|
@ -48,7 +48,7 @@ class TrackSearch : Track {
|
|||
|
||||
if (manga_id != other.manga_id) return false
|
||||
if (sync_id != other.sync_id) return false
|
||||
if (media_id != other.media_id) return false
|
||||
if (remote_id != other.remote_id) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class TrackSearch : Track {
|
|||
override fun hashCode(): Int {
|
||||
var result = manga_id.hashCode()
|
||||
result = 31 * result + sync_id
|
||||
result = 31 * result + media_id.hashCode()
|
||||
result = 31 * result + remote_id.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
|
||||
|
||||
|
@ -65,7 +66,7 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
|
|||
|
||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||
|
||||
override fun displayScore(track: Track): String {
|
||||
override fun displayScore(track: DomainTrack): String {
|
||||
return track.score.toInt().toString()
|
||||
}
|
||||
|
||||
|
@ -91,15 +92,15 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
|
|||
return api.updateItem(track)
|
||||
}
|
||||
|
||||
override suspend fun delete(track: Track): Track {
|
||||
return api.deleteItem(track)
|
||||
override suspend fun delete(track: DomainTrack) {
|
||||
api.deleteItem(track)
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
val remoteTrack = api.findListItem(track)
|
||||
return if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.media_id = remoteTrack.media_id
|
||||
track.remote_id = remoteTrack.remote_id
|
||||
|
||||
if (track.status != COMPLETED) {
|
||||
val isRereading = track.status == REREADING
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.net.Uri
|
|||
import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.DELETE
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
|
@ -31,6 +32,7 @@ import tachiyomi.core.util.lang.withIOContext
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class MyAnimeListApi(
|
||||
private val trackId: Long,
|
||||
|
@ -114,7 +116,7 @@ class MyAnimeListApi(
|
|||
.let {
|
||||
val obj = it.jsonObject
|
||||
TrackSearch.create(trackId).apply {
|
||||
media_id = obj["id"]!!.jsonPrimitive.long
|
||||
remote_id = obj["id"]!!.jsonPrimitive.long
|
||||
title = obj["title"]!!.jsonPrimitive.content
|
||||
summary = obj["synopsis"]?.jsonPrimitive?.content ?: ""
|
||||
total_chapters = obj["num_chapters"]!!.jsonPrimitive.int
|
||||
|
@ -122,7 +124,7 @@ class MyAnimeListApi(
|
|||
cover_url =
|
||||
obj["main_picture"]?.jsonObject?.get("large")?.jsonPrimitive?.content
|
||||
?: ""
|
||||
tracking_url = "https://myanimelist.net/manga/$media_id"
|
||||
tracking_url = "https://myanimelist.net/manga/$remote_id"
|
||||
publishing_status =
|
||||
obj["status"]!!.jsonPrimitive.content.replace("_", " ")
|
||||
publishing_type =
|
||||
|
@ -154,7 +156,7 @@ class MyAnimeListApi(
|
|||
}
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(mangaUrl(track.media_id).toString())
|
||||
.url(mangaUrl(track.remote_id).toString())
|
||||
.put(formBodyBuilder.build())
|
||||
.build()
|
||||
with(json) {
|
||||
|
@ -166,24 +168,18 @@ class MyAnimeListApi(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun deleteItem(track: Track): Track {
|
||||
return withIOContext {
|
||||
val request = Request.Builder()
|
||||
.url(mangaUrl(track.media_id).toString())
|
||||
.delete()
|
||||
.build()
|
||||
with(json) {
|
||||
authClient.newCall(request)
|
||||
.awaitSuccess()
|
||||
track
|
||||
}
|
||||
suspend fun deleteItem(track: DomainTrack) {
|
||||
withIOContext {
|
||||
authClient
|
||||
.newCall(DELETE(mangaUrl(track.remoteId).toString()))
|
||||
.awaitSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun findListItem(track: Track): Track? {
|
||||
return withIOContext {
|
||||
val uri = "$baseApiUrl/manga".toUri().buildUpon()
|
||||
.appendPath(track.media_id.toString())
|
||||
.appendPath(track.remote_id.toString())
|
||||
.appendQueryParameter("fields", "num_chapters,my_list_status{start_date,finish_date}")
|
||||
.build()
|
||||
with(json) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
|
||||
|
||||
|
@ -37,7 +38,7 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
|
|||
|
||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||
|
||||
override fun displayScore(track: Track): String {
|
||||
override fun displayScore(track: DomainTrack): String {
|
||||
return track.score.toInt().toString()
|
||||
}
|
||||
|
||||
|
@ -59,8 +60,8 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
|
|||
return api.updateLibManga(track, getUsername())
|
||||
}
|
||||
|
||||
override suspend fun delete(track: Track): Track {
|
||||
return api.deleteLibManga(track)
|
||||
override suspend fun delete(track: DomainTrack) {
|
||||
api.deleteLibManga(track)
|
||||
}
|
||||
|
||||
override suspend fun bind(track: Track, hasReadChapters: Boolean): Track {
|
||||
|
|
|
@ -27,6 +27,7 @@ import okhttp3.OkHttpClient
|
|||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class ShikimoriApi(
|
||||
private val trackId: Long,
|
||||
|
@ -44,7 +45,7 @@ class ShikimoriApi(
|
|||
val payload = buildJsonObject {
|
||||
putJsonObject("user_rate") {
|
||||
put("user_id", userId)
|
||||
put("target_id", track.media_id)
|
||||
put("target_id", track.remote_id)
|
||||
put("target_type", "Manga")
|
||||
put("chapters", track.last_chapter_read.toInt())
|
||||
put("score", track.score.toInt())
|
||||
|
@ -69,14 +70,11 @@ class ShikimoriApi(
|
|||
|
||||
suspend fun updateLibManga(track: Track, userId: String): Track = addLibManga(track, userId)
|
||||
|
||||
suspend fun deleteLibManga(track: Track): Track {
|
||||
return withIOContext {
|
||||
authClient.newCall(
|
||||
DELETE(
|
||||
"$apiUrl/v2/user_rates/${track.library_id}",
|
||||
),
|
||||
).awaitSuccess()
|
||||
track
|
||||
suspend fun deleteLibManga(track: DomainTrack) {
|
||||
withIOContext {
|
||||
authClient
|
||||
.newCall(DELETE("$apiUrl/v2/user_rates/${track.libraryId}"))
|
||||
.awaitSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +100,7 @@ class ShikimoriApi(
|
|||
|
||||
private fun jsonToSearch(obj: JsonObject): TrackSearch {
|
||||
return TrackSearch.create(trackId).apply {
|
||||
media_id = obj["id"]!!.jsonPrimitive.long
|
||||
remote_id = obj["id"]!!.jsonPrimitive.long
|
||||
title = obj["name"]!!.jsonPrimitive.content
|
||||
total_chapters = obj["chapters"]!!.jsonPrimitive.int
|
||||
cover_url = baseUrl + obj["image"]!!.jsonObject["preview"]!!.jsonPrimitive.content
|
||||
|
@ -118,7 +116,7 @@ class ShikimoriApi(
|
|||
private fun jsonToTrack(obj: JsonObject, mangas: JsonObject): Track {
|
||||
return Track.create(trackId).apply {
|
||||
title = mangas["name"]!!.jsonPrimitive.content
|
||||
media_id = obj["id"]!!.jsonPrimitive.long
|
||||
remote_id = obj["id"]!!.jsonPrimitive.long
|
||||
total_chapters = mangas["chapters"]!!.jsonPrimitive.int
|
||||
library_id = obj["id"]!!.jsonPrimitive.long
|
||||
last_chapter_read = obj["chapters"]!!.jsonPrimitive.float
|
||||
|
@ -131,7 +129,7 @@ class ShikimoriApi(
|
|||
suspend fun findLibManga(track: Track, userId: String): Track? {
|
||||
return withIOContext {
|
||||
val urlMangas = "$apiUrl/mangas".toUri().buildUpon()
|
||||
.appendPath(track.media_id.toString())
|
||||
.appendPath(track.remote_id.toString())
|
||||
.build()
|
||||
val mangas = with(json) {
|
||||
authClient.newCall(GET(urlMangas.toString()))
|
||||
|
@ -141,7 +139,7 @@ class ShikimoriApi(
|
|||
|
||||
val url = "$apiUrl/v2/user_rates".toUri().buildUpon()
|
||||
.appendQueryParameter("user_id", userId)
|
||||
.appendQueryParameter("target_id", track.media_id.toString())
|
||||
.appendQueryParameter("target_id", track.remote_id.toString())
|
||||
.appendQueryParameter("target_type", "Manga")
|
||||
.build()
|
||||
with(json) {
|
||||
|
|
|
@ -45,7 +45,7 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
|
|||
|
||||
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||
|
||||
override fun displayScore(track: Track): String = ""
|
||||
override fun displayScore(track: DomainTrack): String = ""
|
||||
|
||||
override suspend fun update(track: Track, didReadChapter: Boolean): Track {
|
||||
if (track.status != COMPLETED) {
|
||||
|
|
|
@ -399,7 +399,7 @@ private data class TrackScoreSelectorScreen(
|
|||
private class Model(
|
||||
private val track: Track,
|
||||
private val tracker: Tracker,
|
||||
) : StateScreenModel<Model.State>(State(tracker.displayScore(track.toDbTrack()))) {
|
||||
) : StateScreenModel<Model.State>(State(tracker.displayScore(track))) {
|
||||
|
||||
fun getSelections(): ImmutableList<String> {
|
||||
return tracker.getScoreList()
|
||||
|
@ -816,7 +816,7 @@ private data class TrackerRemoveScreen(
|
|||
|
||||
fun deleteMangaFromService() {
|
||||
screenModelScope.launchNonCancellable {
|
||||
(tracker as DeletableTracker).delete(track.toDbTrack())
|
||||
(tracker as DeletableTracker).delete(track)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ data class DummyTracker(
|
|||
|
||||
override fun indexToScore(index: Int): Float = getScoreList()[index].toFloat()
|
||||
|
||||
override fun displayScore(track: eu.kanade.tachiyomi.data.database.models.Track): String =
|
||||
override fun displayScore(track: Track): String =
|
||||
track.score.toString()
|
||||
|
||||
override suspend fun update(
|
||||
|
|
Reference in a new issue