Backup scrobblings

This commit is contained in:
Vicente
2025-10-14 10:13:57 +02:00
committed by Koitharu
parent f3b42b9a42
commit a1ba0b8c21
5 changed files with 72 additions and 0 deletions

View File

@@ -26,6 +26,7 @@ import org.koitharu.kotatsu.backups.data.model.CategoryBackup
import org.koitharu.kotatsu.backups.data.model.FavouriteBackup
import org.koitharu.kotatsu.backups.data.model.HistoryBackup
import org.koitharu.kotatsu.backups.data.model.MangaBackup
import org.koitharu.kotatsu.backups.data.model.ScrobblingBackup
import org.koitharu.kotatsu.backups.data.model.SourceBackup
import org.koitharu.kotatsu.backups.domain.BackupSection
import org.koitharu.kotatsu.core.db.MangaDatabase
@@ -109,6 +110,12 @@ class BackupRepository @Inject constructor(
data = database.getSourcesDao().dumpEnabled().map { SourceBackup(it) },
serializer = serializer(),
)
BackupSection.SCROBBLING -> output.writeJsonArray(
section = BackupSection.SCROBBLING,
data = database.getScrobblingDao().dumpEnabled().map { ScrobblingBackup(it) },
serializer = serializer(),
)
}
progress?.emit(commonProgress)
commonProgress++
@@ -163,6 +170,10 @@ class BackupRepository @Inject constructor(
getSourcesDao().upsert(it.toEntity())
}
BackupSection.SCROBBLING -> input.readJsonArray<ScrobblingBackup>(serializer()).restoreToDb {
getScrobblingDao().upsert(it.toEntity())
}
null -> CompositeResult.EMPTY // skip unknown entries
}
progress?.emit(commonProgress)

View File

@@ -0,0 +1,40 @@
package org.koitharu.kotatsu.backups.data.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
@Serializable
class ScrobblingBackup(
@SerialName("scrobbler") val scrobbler: Int,
@SerialName("id") val id: Int,
@SerialName("manga_id") val mangaId: Long,
@SerialName("target_id") val targetId: Long,
@SerialName("status") val status: String?,
@SerialName("chapter") val chapter: Int,
@SerialName("comment") val comment: String?,
@SerialName("rating") val rating: Float,
) {
constructor(entity: ScrobblingEntity) : this(
scrobbler = entity.scrobbler,
id = entity.id,
mangaId = entity.mangaId,
targetId = entity.targetId,
status = entity.status,
chapter = entity.chapter,
comment = entity.comment,
rating = entity.rating,
)
fun toEntity() = ScrobblingEntity(
scrobbler = scrobbler,
id = id,
mangaId = mangaId,
targetId = targetId,
status = status,
chapter = chapter,
comment = comment,
rating = rating,
)
}

View File

@@ -15,6 +15,7 @@ enum class BackupSection(
SETTINGS_READER_GRID("reader_grid"),
BOOKMARKS("bookmarks"),
SOURCES("sources"),
SCROBBLING("scrobbling"),
;
companion object {

View File

@@ -23,6 +23,7 @@ data class BackupSectionModel(
BackupSection.SETTINGS_READER_GRID -> R.string.reader_actions
BackupSection.BOOKMARKS -> R.string.bookmarks
BackupSection.SOURCES -> R.string.remote_sources
BackupSection.SCROBBLING -> R.string.tracking
}
override fun areItemsTheSame(other: ListModel): Boolean {

View File

@@ -1,7 +1,10 @@
package org.koitharu.kotatsu.scrobbling.common.data
import androidx.room.*
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.isActive
@Dao
abstract class ScrobblingDao {
@@ -20,4 +23,20 @@ abstract class ScrobblingDao {
@Query("DELETE FROM scrobblings WHERE scrobbler = :scrobbler AND manga_id = :mangaId")
abstract suspend fun delete(scrobbler: Int, mangaId: Long)
@Query("SELECT * FROM scrobblings ORDER BY scrobbler LIMIT :limit OFFSET :offset")
protected abstract suspend fun findAll(offset: Int, limit: Int): List<ScrobblingEntity>
fun dumpEnabled(): Flow<ScrobblingEntity> = flow {
val window = 10
var offset = 0
while (currentCoroutineContext().isActive) {
val list = findAll(offset, window)
if (list.isEmpty()) {
break
}
offset += window
list.forEach { emit(it) }
}
}
}