fix restoring "full" backups with preferences

This commit is contained in:
jmir1 2023-04-07 21:09:29 +02:00
parent 183107c482
commit 2daac8b976
5 changed files with 155 additions and 2 deletions

View file

@ -3,15 +3,31 @@ package eu.kanade.tachiyomi.data.backup
import android.content.Context
import android.net.Uri
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.models.Backup
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue
import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.anime.AnimeSourceManager
import eu.kanade.tachiyomi.source.manga.MangaSourceManager
import kotlinx.serialization.SerializationException
import okio.buffer
import okio.gzip
import okio.source
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer as FullBackupSerializer
import eu.kanade.tachiyomi.data.backup.full.models.BooleanPreferenceValue as FullBooleanPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.FloatPreferenceValue as FullFloatPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.IntPreferenceValue as FullIntPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.LongPreferenceValue as FullLongPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.StringPreferenceValue as FullStringPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.StringSetPreferenceValue as FullStringSetPreferenceValue
class BackupFileValidator(
private val mangaSourceManager: MangaSourceManager = Injekt.get(),
@ -32,7 +48,34 @@ class BackupFileValidator(
val backupString =
context.contentResolver.openInputStream(uri)!!.source().gzip().buffer()
.use { it.readByteArray() }
backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
// Sadly, this is necessary because of old "full" backups.
try {
backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
} catch (e: SerializationException) {
val fullBackup = backupManager.parser.decodeFromByteArray(FullBackupSerializer, backupString)
val backupPreferences = fullBackup.backupPreferences.map {
val value = when (it.value) {
is FullIntPreferenceValue -> IntPreferenceValue(it.value.value)
is FullLongPreferenceValue -> LongPreferenceValue(it.value.value)
is FullFloatPreferenceValue -> FloatPreferenceValue(it.value.value)
is FullBooleanPreferenceValue -> BooleanPreferenceValue(it.value.value)
is FullStringPreferenceValue -> StringPreferenceValue(it.value.value)
is FullStringSetPreferenceValue -> StringSetPreferenceValue(it.value.value)
}
BackupPreference(it.key, value)
}
Backup(
fullBackup.backupManga,
fullBackup.backupCategories,
fullBackup.backupAnime,
fullBackup.backupAnimeCategories,
fullBackup.backupBrokenSources,
fullBackup.backupSources,
fullBackup.backupBrokenAnimeSources,
fullBackup.backupAnimeSources,
backupPreferences,
)
}
} catch (e: Exception) {
throw IllegalStateException(e)
}

View file

@ -4,6 +4,7 @@ import android.content.Context
import android.net.Uri
import androidx.preference.PreferenceManager
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.models.Backup
import eu.kanade.tachiyomi.data.backup.models.BackupAnime
import eu.kanade.tachiyomi.data.backup.models.BackupAnimeHistory
import eu.kanade.tachiyomi.data.backup.models.BackupAnimeSource
@ -27,6 +28,7 @@ import eu.kanade.tachiyomi.data.database.models.manga.Manga
import eu.kanade.tachiyomi.data.database.models.manga.MangaTrack
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
import kotlinx.coroutines.Job
import kotlinx.serialization.SerializationException
import okio.buffer
import okio.gzip
import okio.source
@ -34,6 +36,13 @@ import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer as FullBackupSerializer
import eu.kanade.tachiyomi.data.backup.full.models.BooleanPreferenceValue as FullBooleanPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.FloatPreferenceValue as FullFloatPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.IntPreferenceValue as FullIntPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.LongPreferenceValue as FullLongPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.StringPreferenceValue as FullStringPreferenceValue
import eu.kanade.tachiyomi.data.backup.full.models.StringSetPreferenceValue as FullStringSetPreferenceValue
class BackupRestorer(
private val context: Context,
@ -95,7 +104,35 @@ class BackupRestorer(
@Suppress("BlockingMethodInNonBlockingContext")
private suspend fun performRestore(uri: Uri): Boolean {
val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() }
val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
// Sadly, this is necessary because of old "full" backups.
val backup = try {
backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
} catch (e: SerializationException) {
val fullBackup = backupManager.parser.decodeFromByteArray(FullBackupSerializer, backupString)
val backupPreferences = fullBackup.backupPreferences.map {
val value = when (it.value) {
is FullIntPreferenceValue -> IntPreferenceValue(it.value.value)
is FullLongPreferenceValue -> LongPreferenceValue(it.value.value)
is FullFloatPreferenceValue -> FloatPreferenceValue(it.value.value)
is FullBooleanPreferenceValue -> BooleanPreferenceValue(it.value.value)
is FullStringPreferenceValue -> StringPreferenceValue(it.value.value)
is FullStringSetPreferenceValue -> StringSetPreferenceValue(it.value.value)
}
BackupPreference(it.key, value)
}
Backup(
fullBackup.backupManga,
fullBackup.backupCategories,
fullBackup.backupAnime,
fullBackup.backupAnimeCategories,
fullBackup.backupBrokenSources,
fullBackup.backupSources,
fullBackup.backupBrokenAnimeSources,
fullBackup.backupAnimeSources,
backupPreferences,
)
}
restoreAmount = backup.backupManga.size + backup.backupAnime.size + 2 // +2 for categories

View file

@ -0,0 +1,36 @@
package eu.kanade.tachiyomi.data.backup.full.models
import eu.kanade.tachiyomi.data.backup.models.BackupAnime
import eu.kanade.tachiyomi.data.backup.models.BackupAnimeSource
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
import eu.kanade.tachiyomi.data.backup.models.BackupManga
import eu.kanade.tachiyomi.data.backup.models.BackupSource
import eu.kanade.tachiyomi.data.backup.models.BrokenBackupAnimeSource
import eu.kanade.tachiyomi.data.backup.models.BrokenBackupSource
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@Serializable
data class Backup(
@ProtoNumber(1) val backupManga: List<BackupManga> = emptyList(),
@ProtoNumber(2) var backupCategories: List<BackupCategory> = emptyList(),
@ProtoNumber(3) val backupAnime: List<BackupAnime> = emptyList(),
@ProtoNumber(4) var backupAnimeCategories: List<BackupCategory> = emptyList(),
// Bump by 100 to specify this is a 0.x value
@ProtoNumber(100) var backupBrokenSources: List<BrokenBackupSource> = emptyList(),
@ProtoNumber(101) var backupSources: List<BackupSource> = emptyList(),
@ProtoNumber(102) var backupBrokenAnimeSources: List<BrokenBackupAnimeSource> = emptyList(),
@ProtoNumber(103) var backupAnimeSources: List<BackupAnimeSource> = emptyList(),
@ProtoNumber(104) var backupPreferences: List<BackupPreference> = emptyList(),
) {
companion object {
fun getBackupFilename(): String {
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
return "aniyomi_$date.proto.gz"
}
}
}

View file

@ -0,0 +1,31 @@
package eu.kanade.tachiyomi.data.backup.full.models
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@Serializable
data class BackupPreference(
@ProtoNumber(1) val key: String,
@ProtoNumber(2) val value: PreferenceValue,
)
@Serializable
sealed class PreferenceValue
@Serializable
data class IntPreferenceValue(val value: Int) : PreferenceValue()
@Serializable
data class LongPreferenceValue(val value: Long) : PreferenceValue()
@Serializable
data class FloatPreferenceValue(val value: Float) : PreferenceValue()
@Serializable
data class StringPreferenceValue(val value: String) : PreferenceValue()
@Serializable
data class BooleanPreferenceValue(val value: Boolean) : PreferenceValue()
@Serializable
data class StringSetPreferenceValue(val value: Set<String>) : PreferenceValue()

View file

@ -0,0 +1,6 @@
package eu.kanade.tachiyomi.data.backup.full.models
import kotlinx.serialization.Serializer
@Serializer(forClass = Backup::class)
object BackupSerializer