Fix scrobbling chapter index

This commit is contained in:
Koitharu
2024-01-31 13:56:30 +02:00
parent 95aaa967a8
commit 892f95a7a6
12 changed files with 49 additions and 40 deletions

View File

@@ -109,10 +109,7 @@ class HistoryRepository @Inject constructor(
),
)
trackingRepository.syncWithHistory(manga, chapterId)
val chapter = manga.chapters?.findById(chapterId)
if (chapter != null) {
scrobblers.forEach { it.tryScrobble(manga.id, chapter) }
}
scrobblers.forEach { it.tryScrobble(manga, chapterId) }
}
}

View File

@@ -11,7 +11,6 @@ import org.json.JSONObject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.parsers.exception.GraphQLException
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.json.mapJSON
@@ -154,11 +153,11 @@ class AniListRepository @Inject constructor(
saveRate(response.getJSONObject("data").getJSONObject("SaveMediaListEntry"), mangaId)
}
override suspend fun updateRate(rateId: Int, mangaId: Long, chapter: MangaChapter) {
override suspend fun updateRate(rateId: Int, mangaId: Long, chapter: Int) {
val response = doRequest(
REQUEST_MUTATION,
"""
SaveMediaListEntry(id: $rateId, progress: ${chapter.number}) {
SaveMediaListEntry(id: $rateId, progress: $chapter) {
id
mediaId
status

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.scrobbling.anilist.domain
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.scrobbling.anilist.data.AniListRepository
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
@@ -12,7 +13,8 @@ import javax.inject.Singleton
class AniListScrobbler @Inject constructor(
private val repository: AniListRepository,
db: MangaDatabase,
) : Scrobbler(db, ScrobblerService.ANILIST, repository) {
mangaRepositoryFactory: MangaRepository.Factory,
) : Scrobbler(db, ScrobblerService.ANILIST, repository, mangaRepositoryFactory) {
init {
statuses[ScrobblingStatus.PLANNED] = "PLANNING"

View File

@@ -1,6 +1,5 @@
package org.koitharu.kotatsu.scrobbling.common.data
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerMangaInfo
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
@@ -27,7 +26,7 @@ interface ScrobblerRepository {
suspend fun createRate(mangaId: Long, scrobblerMangaId: Long)
suspend fun updateRate(rateId: Int, mangaId: Long, chapter: MangaChapter)
suspend fun updateRate(rateId: Int, mangaId: Long, chapter: Int)
suspend fun updateRate(rateId: Int, mangaId: Long, rating: Float, status: String?, comment: String?)
}

View File

@@ -11,10 +11,12 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.model.findById
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.util.ext.findKeyByValue
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.sanitize
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
@@ -30,6 +32,7 @@ abstract class Scrobbler(
protected val db: MangaDatabase,
val scrobblerService: ScrobblerService,
private val repository: ScrobblerRepository,
private val mangaRepositoryFactory: MangaRepository.Factory,
) {
private val infoCache = LongSparseArray<ScrobblerMangaInfo>()
@@ -68,9 +71,23 @@ abstract class Scrobbler(
repository.createRate(mangaId, targetId)
}
suspend fun scrobble(mangaId: Long, chapter: MangaChapter) {
val entity = db.getScrobblingDao().find(scrobblerService.id, mangaId) ?: return
repository.updateRate(entity.id, entity.mangaId, chapter)
suspend fun scrobble(manga: Manga, chapterId: Long) {
var chapters = manga.chapters
if (chapters.isNullOrEmpty()) {
chapters = mangaRepositoryFactory.create(manga.source).getDetails(manga).chapters
}
requireNotNull(chapters)
val chapter = checkNotNull(chapters.findById(chapterId)) {
"Chapter $chapterId not found in this manga"
}
val number = if (chapter.number > 0f) {
chapter.number.toInt()
} else {
chapters = chapters.filter { x -> x.branch == chapter.branch }
chapters.indexOf(chapter) + 1
}
val entity = db.getScrobblingDao().find(scrobblerService.id, manga.id) ?: return
repository.updateRate(entity.id, entity.mangaId, number)
}
suspend fun getScrobblingInfoOrNull(mangaId: Long): ScrobblingInfo? {
@@ -137,9 +154,9 @@ abstract class Scrobbler(
}
}
suspend fun Scrobbler.tryScrobble(mangaId: Long, chapter: MangaChapter): Boolean {
suspend fun Scrobbler.tryScrobble(manga: Manga, chapterId: Long): Boolean {
return runCatchingCancellable {
scrobble(mangaId, chapter)
scrobble(manga, chapterId)
}.onFailure {
it.printStackTraceDebug()
}.isSuccess

View File

@@ -14,10 +14,8 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.findById
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.parser.MangaIntent
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call
@@ -40,7 +38,6 @@ class ScrobblingSelectorViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
scrobblers: Set<@JvmSuppressWildcards Scrobbler>,
private val historyRepository: HistoryRepository,
private val mangaRepositoryFactory: MangaRepository.Factory,
) : BaseViewModel() {
val manga = savedStateHandle.require<ParcelableManga>(MangaIntent.KEY_MANGA).manga
@@ -164,15 +161,10 @@ class ScrobblingSelectorViewModel @Inject constructor(
comment = prevInfo?.comment,
)
if (history != null) {
val chapter = mangaRepositoryFactory.create(manga.source)
.getDetails(manga)
.chapters?.findById(history.chapterId)
if (chapter != null) {
currentScrobbler.scrobble(
mangaId = manga.id,
chapter = chapter,
)
}
currentScrobbler.scrobble(
manga = manga,
chapterId = history.chapterId,
)
}
onClose.call(Unit)
}

View File

@@ -12,7 +12,6 @@ import org.json.JSONObject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.util.ext.parseJsonOrNull
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.json.getFloatOrDefault
import org.koitharu.kotatsu.parsers.util.json.getIntOrDefault
@@ -161,13 +160,13 @@ class KitsuRepository(
saveRate(response, mangaId)
}
override suspend fun updateRate(rateId: Int, mangaId: Long, chapter: MangaChapter) {
override suspend fun updateRate(rateId: Int, mangaId: Long, chapter: Int) {
val payload = JSONObject()
payload.putJO("data") {
put("type", "libraryEntries")
put("id", rateId)
putJO("attributes") {
put("progress", chapter.number.toInt()) // TODO
put("progress", chapter)
}
}
val request = Request.Builder()

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.scrobbling.kitsu.domain
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
@@ -10,7 +11,8 @@ import javax.inject.Inject
class KitsuScrobbler @Inject constructor(
private val repository: KitsuRepository,
db: MangaDatabase,
) : Scrobbler(db, ScrobblerService.KITSU, repository) {
mangaRepositoryFactory: MangaRepository.Factory,
) : Scrobbler(db, ScrobblerService.KITSU, repository, mangaRepositoryFactory) {
init {
statuses[ScrobblingStatus.PLANNED] = "planned"

View File

@@ -10,7 +10,6 @@ import okhttp3.Request
import org.json.JSONObject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull
@@ -132,9 +131,9 @@ class MALRepository @Inject constructor(
saveRate(response, mangaId, scrobblerMangaId)
}
override suspend fun updateRate(rateId: Int, mangaId: Long, chapter: MangaChapter) {
override suspend fun updateRate(rateId: Int, mangaId: Long, chapter: Int) {
val body = FormBody.Builder()
.add("num_chapters_read", chapter.number.toString())
.add("num_chapters_read", chapter.toString())
val url = BASE_API_URL.toHttpUrl().newBuilder()
.addPathSegment("manga")
.addPathSegment(rateId.toString())

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.scrobbling.mal.domain
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
@@ -14,7 +15,8 @@ private const val RATING_MAX = 10f
class MALScrobbler @Inject constructor(
private val repository: MALRepository,
db: MangaDatabase,
) : Scrobbler(db, ScrobblerService.MAL, repository) {
mangaRepositoryFactory: MangaRepository.Factory,
) : Scrobbler(db, ScrobblerService.MAL, repository, mangaRepositoryFactory) {
init {
statuses[ScrobblingStatus.PLANNED] = "plan_to_read"

View File

@@ -10,7 +10,6 @@ import org.json.JSONObject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.util.ext.toRequestBody
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.json.mapJSON
@@ -130,12 +129,12 @@ class ShikimoriRepository @Inject constructor(
saveRate(response, mangaId)
}
override suspend fun updateRate(rateId: Int, mangaId: Long, chapter: MangaChapter) {
override suspend fun updateRate(rateId: Int, mangaId: Long, chapter: Int) {
val payload = JSONObject()
payload.put(
"user_rate",
JSONObject().apply {
put("chapters", chapter.number)
put("chapters", chapter)
},
)
val url = BASE_URL.toHttpUrl().newBuilder()

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.scrobbling.shikimori.domain
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.scrobbling.common.domain.Scrobbler
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
@@ -14,7 +15,8 @@ private const val RATING_MAX = 10f
class ShikimoriScrobbler @Inject constructor(
private val repository: ShikimoriRepository,
db: MangaDatabase,
) : Scrobbler(db, ScrobblerService.SHIKIMORI, repository) {
mangaRepositoryFactory: MangaRepository.Factory,
) : Scrobbler(db, ScrobblerService.SHIKIMORI, repository, mangaRepositoryFactory) {
init {
statuses[ScrobblingStatus.PLANNED] = "planned"