Split up BackupCreator into smaller classes
This commit is contained in:
parent
54ba1d719e
commit
1a559124eb
11 changed files with 236 additions and 180 deletions
|
@ -6,47 +6,27 @@ import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_APP_PREFS
|
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_APP_PREFS
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_CATEGORY
|
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_CATEGORY
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_CHAPTER
|
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_HISTORY
|
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_SOURCE_PREFS
|
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_SOURCE_PREFS
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags.BACKUP_TRACK
|
import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator
|
||||||
|
import eu.kanade.tachiyomi.data.backup.create.creators.MangaBackupCreator
|
||||||
|
import eu.kanade.tachiyomi.data.backup.create.creators.PreferenceBackupCreator
|
||||||
|
import eu.kanade.tachiyomi.data.backup.create.creators.SourcesBackupCreator
|
||||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupHistory
|
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
|
import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
||||||
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.backup.models.backupCategoryMapper
|
|
||||||
import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper
|
|
||||||
import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper
|
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
|
||||||
import eu.kanade.tachiyomi.source.preferenceKey
|
|
||||||
import eu.kanade.tachiyomi.source.sourcePreferences
|
|
||||||
import kotlinx.serialization.protobuf.ProtoBuf
|
import kotlinx.serialization.protobuf.ProtoBuf
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.gzip
|
import okio.gzip
|
||||||
import okio.sink
|
import okio.sink
|
||||||
import tachiyomi.core.i18n.stringResource
|
import tachiyomi.core.i18n.stringResource
|
||||||
import tachiyomi.core.preference.Preference
|
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
|
||||||
import tachiyomi.core.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.data.DatabaseHandler
|
|
||||||
import tachiyomi.domain.category.interactor.GetCategories
|
|
||||||
import tachiyomi.domain.category.model.Category
|
|
||||||
import tachiyomi.domain.history.interactor.GetHistory
|
|
||||||
import tachiyomi.domain.manga.interactor.GetFavorites
|
import tachiyomi.domain.manga.interactor.GetFavorites
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
@ -54,15 +34,13 @@ import java.io.FileOutputStream
|
||||||
|
|
||||||
class BackupCreator(
|
class BackupCreator(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
private val categoriesBackupCreator: CategoriesBackupCreator = CategoriesBackupCreator(),
|
||||||
|
private val mangaBackupCreator: MangaBackupCreator = MangaBackupCreator(),
|
||||||
|
private val preferenceBackupCreator: PreferenceBackupCreator = PreferenceBackupCreator(),
|
||||||
|
private val sourcesBackupCreator: SourcesBackupCreator = SourcesBackupCreator(),
|
||||||
|
private val getFavorites: GetFavorites = Injekt.get(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val handler: DatabaseHandler = Injekt.get()
|
|
||||||
private val sourceManager: SourceManager = Injekt.get()
|
|
||||||
private val getCategories: GetCategories = Injekt.get()
|
|
||||||
private val getFavorites: GetFavorites = Injekt.get()
|
|
||||||
private val getHistory: GetHistory = Injekt.get()
|
|
||||||
private val preferenceStore: PreferenceStore = Injekt.get()
|
|
||||||
|
|
||||||
internal val parser = ProtoBuf
|
internal val parser = ProtoBuf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,16 +50,6 @@ class BackupCreator(
|
||||||
* @param isAutoBackup backup called from scheduled backup job
|
* @param isAutoBackup backup called from scheduled backup job
|
||||||
*/
|
*/
|
||||||
suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String {
|
suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String {
|
||||||
val databaseManga = getFavorites.await()
|
|
||||||
val backup = Backup(
|
|
||||||
backupMangas(databaseManga, flags),
|
|
||||||
backupCategories(flags),
|
|
||||||
emptyList(),
|
|
||||||
prepExtensionInfoForSync(databaseManga),
|
|
||||||
backupAppPreferences(flags),
|
|
||||||
backupSourcePreferences(flags),
|
|
||||||
)
|
|
||||||
|
|
||||||
var file: UniFile? = null
|
var file: UniFile? = null
|
||||||
try {
|
try {
|
||||||
file = (
|
file = (
|
||||||
|
@ -108,6 +76,15 @@ class BackupCreator(
|
||||||
throw IllegalStateException("Failed to get handle on a backup file")
|
throw IllegalStateException("Failed to get handle on a backup file")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val databaseManga = getFavorites.await()
|
||||||
|
val backup = Backup(
|
||||||
|
backupManga = backupMangas(databaseManga, flags),
|
||||||
|
backupCategories = backupCategories(flags),
|
||||||
|
backupSources = backupSources(databaseManga),
|
||||||
|
backupPreferences = backupAppPreferences(flags),
|
||||||
|
backupSourcePreferences = backupSourcePreferences(flags),
|
||||||
|
)
|
||||||
|
|
||||||
val byteArray = parser.encodeToByteArray(BackupSerializer, backup)
|
val byteArray = parser.encodeToByteArray(BackupSerializer, backup)
|
||||||
if (byteArray.isEmpty()) {
|
if (byteArray.isEmpty()) {
|
||||||
throw IllegalStateException(context.stringResource(MR.strings.empty_backup_error))
|
throw IllegalStateException(context.stringResource(MR.strings.empty_backup_error))
|
||||||
|
@ -130,134 +107,30 @@ class BackupCreator(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prepExtensionInfoForSync(mangas: List<Manga>): List<BackupSource> {
|
|
||||||
return mangas
|
|
||||||
.asSequence()
|
|
||||||
.map(Manga::source)
|
|
||||||
.distinct()
|
|
||||||
.map(sourceManager::getOrStub)
|
|
||||||
.map(BackupSource::copyFrom)
|
|
||||||
.toList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Backup the categories of library
|
|
||||||
*
|
|
||||||
* @return list of [BackupCategory] to be backed up
|
|
||||||
*/
|
|
||||||
private suspend fun backupCategories(options: Int): List<BackupCategory> {
|
private suspend fun backupCategories(options: Int): List<BackupCategory> {
|
||||||
// Check if user wants category information in backup
|
if (options and BACKUP_CATEGORY != BACKUP_CATEGORY) return emptyList()
|
||||||
return if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
|
||||||
getCategories.await()
|
return categoriesBackupCreator.backupCategories()
|
||||||
.filterNot(Category::isSystemCategory)
|
|
||||||
.map(backupCategoryMapper)
|
|
||||||
} else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun backupMangas(mangas: List<Manga>, flags: Int): List<BackupManga> {
|
private suspend fun backupMangas(mangas: List<Manga>, flags: Int): List<BackupManga> {
|
||||||
return mangas.map {
|
return mangaBackupCreator.backupMangas(mangas, flags)
|
||||||
backupManga(it, flags)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun backupSources(mangas: List<Manga>): List<BackupSource> {
|
||||||
* Convert a manga to Json
|
return sourcesBackupCreator.backupSources(mangas)
|
||||||
*
|
|
||||||
* @param manga manga that gets converted
|
|
||||||
* @param options options for the backup
|
|
||||||
* @return [BackupManga] containing manga in a serializable form
|
|
||||||
*/
|
|
||||||
private suspend fun backupManga(manga: Manga, options: Int): BackupManga {
|
|
||||||
// Entry for this manga
|
|
||||||
val mangaObject = BackupManga.copyFrom(manga)
|
|
||||||
|
|
||||||
// Check if user wants chapter information in backup
|
|
||||||
if (options and BACKUP_CHAPTER == BACKUP_CHAPTER) {
|
|
||||||
// Backup all the chapters
|
|
||||||
handler.awaitList {
|
|
||||||
chaptersQueries.getChaptersByMangaId(
|
|
||||||
mangaId = manga.id,
|
|
||||||
applyScanlatorFilter = 0, // false
|
|
||||||
mapper = backupChapterMapper,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.takeUnless(List<BackupChapter>::isEmpty)
|
|
||||||
?.let { mangaObject.chapters = it }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user wants category information in backup
|
|
||||||
if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
|
||||||
// Backup categories for this manga
|
|
||||||
val categoriesForManga = getCategories.await(manga.id)
|
|
||||||
if (categoriesForManga.isNotEmpty()) {
|
|
||||||
mangaObject.categories = categoriesForManga.map { it.order }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user wants track information in backup
|
|
||||||
if (options and BACKUP_TRACK == BACKUP_TRACK) {
|
|
||||||
val tracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id, backupTrackMapper) }
|
|
||||||
if (tracks.isNotEmpty()) {
|
|
||||||
mangaObject.tracking = tracks
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user wants history information in backup
|
|
||||||
if (options and BACKUP_HISTORY == BACKUP_HISTORY) {
|
|
||||||
val historyByMangaId = getHistory.await(manga.id)
|
|
||||||
if (historyByMangaId.isNotEmpty()) {
|
|
||||||
val history = historyByMangaId.map { history ->
|
|
||||||
val chapter = handler.awaitOne { chaptersQueries.getChapterById(history.chapterId) }
|
|
||||||
BackupHistory(chapter.url, history.readAt?.time ?: 0L, history.readDuration)
|
|
||||||
}
|
|
||||||
if (history.isNotEmpty()) {
|
|
||||||
mangaObject.history = history
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mangaObject
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun backupAppPreferences(flags: Int): List<BackupPreference> {
|
private fun backupAppPreferences(flags: Int): List<BackupPreference> {
|
||||||
if (flags and BACKUP_APP_PREFS != BACKUP_APP_PREFS) return emptyList()
|
if (flags and BACKUP_APP_PREFS != BACKUP_APP_PREFS) return emptyList()
|
||||||
|
|
||||||
return preferenceStore.getAll().toBackupPreferences()
|
return preferenceBackupCreator.backupAppPreferences()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun backupSourcePreferences(flags: Int): List<BackupSourcePreferences> {
|
private fun backupSourcePreferences(flags: Int): List<BackupSourcePreferences> {
|
||||||
if (flags and BACKUP_SOURCE_PREFS != BACKUP_SOURCE_PREFS) return emptyList()
|
if (flags and BACKUP_SOURCE_PREFS != BACKUP_SOURCE_PREFS) return emptyList()
|
||||||
|
|
||||||
return sourceManager.getCatalogueSources()
|
return preferenceBackupCreator.backupSourcePreferences()
|
||||||
.filterIsInstance<ConfigurableSource>()
|
|
||||||
.map {
|
|
||||||
BackupSourcePreferences(
|
|
||||||
it.preferenceKey(),
|
|
||||||
it.sourcePreferences().all.toBackupPreferences(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> {
|
|
||||||
return this.filterKeys {
|
|
||||||
!Preference.isPrivate(it) && !Preference.isAppState(it)
|
|
||||||
}
|
|
||||||
.mapNotNull { (key, value) ->
|
|
||||||
when (value) {
|
|
||||||
is Int -> BackupPreference(key, IntPreferenceValue(value))
|
|
||||||
is Long -> BackupPreference(key, LongPreferenceValue(value))
|
|
||||||
is Float -> BackupPreference(key, FloatPreferenceValue(value))
|
|
||||||
is String -> BackupPreference(key, StringPreferenceValue(value))
|
|
||||||
is Boolean -> BackupPreference(key, BooleanPreferenceValue(value))
|
|
||||||
is Set<*> -> (value as? Set<String>)?.let {
|
|
||||||
BackupPreference(key, StringSetPreferenceValue(it))
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.backupCategoryMapper
|
||||||
|
import tachiyomi.domain.category.interactor.GetCategories
|
||||||
|
import tachiyomi.domain.category.model.Category
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class CategoriesBackupCreator(
|
||||||
|
private val getCategories: GetCategories = Injekt.get(),
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun backupCategories(): List<BackupCategory> {
|
||||||
|
return getCategories.await()
|
||||||
|
.filterNot(Category::isSystemCategory)
|
||||||
|
.map(backupCategoryMapper)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupChapter
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupHistory
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.backupChapterMapper
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.backupTrackMapper
|
||||||
|
import tachiyomi.data.DatabaseHandler
|
||||||
|
import tachiyomi.domain.category.interactor.GetCategories
|
||||||
|
import tachiyomi.domain.history.interactor.GetHistory
|
||||||
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class MangaBackupCreator(
|
||||||
|
private val handler: DatabaseHandler = Injekt.get(),
|
||||||
|
private val getCategories: GetCategories = Injekt.get(),
|
||||||
|
private val getHistory: GetHistory = Injekt.get(),
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun backupMangas(mangas: List<Manga>, flags: Int): List<BackupManga> {
|
||||||
|
return mangas.map {
|
||||||
|
backupManga(it, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun backupManga(manga: Manga, options: Int): BackupManga {
|
||||||
|
// Entry for this manga
|
||||||
|
val mangaObject = BackupManga.copyFrom(manga)
|
||||||
|
|
||||||
|
// Check if user wants chapter information in backup
|
||||||
|
if (options and BackupCreateFlags.BACKUP_CHAPTER == BackupCreateFlags.BACKUP_CHAPTER) {
|
||||||
|
// Backup all the chapters
|
||||||
|
handler.awaitList {
|
||||||
|
chaptersQueries.getChaptersByMangaId(
|
||||||
|
mangaId = manga.id,
|
||||||
|
applyScanlatorFilter = 0, // false
|
||||||
|
mapper = backupChapterMapper,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.takeUnless(List<BackupChapter>::isEmpty)
|
||||||
|
?.let { mangaObject.chapters = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user wants category information in backup
|
||||||
|
if (options and BackupCreateFlags.BACKUP_CATEGORY == BackupCreateFlags.BACKUP_CATEGORY) {
|
||||||
|
// Backup categories for this manga
|
||||||
|
val categoriesForManga = getCategories.await(manga.id)
|
||||||
|
if (categoriesForManga.isNotEmpty()) {
|
||||||
|
mangaObject.categories = categoriesForManga.map { it.order }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user wants track information in backup
|
||||||
|
if (options and BackupCreateFlags.BACKUP_TRACK == BackupCreateFlags.BACKUP_TRACK) {
|
||||||
|
val tracks = handler.awaitList { manga_syncQueries.getTracksByMangaId(manga.id, backupTrackMapper) }
|
||||||
|
if (tracks.isNotEmpty()) {
|
||||||
|
mangaObject.tracking = tracks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user wants history information in backup
|
||||||
|
if (options and BackupCreateFlags.BACKUP_HISTORY == BackupCreateFlags.BACKUP_HISTORY) {
|
||||||
|
val historyByMangaId = getHistory.await(manga.id)
|
||||||
|
if (historyByMangaId.isNotEmpty()) {
|
||||||
|
val history = historyByMangaId.map { history ->
|
||||||
|
val chapter = handler.awaitOne { chaptersQueries.getChapterById(history.chapterId) }
|
||||||
|
BackupHistory(chapter.url, history.readAt?.time ?: 0L, history.readDuration)
|
||||||
|
}
|
||||||
|
if (history.isNotEmpty()) {
|
||||||
|
mangaObject.history = history
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mangaObject
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
||||||
|
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.source.ConfigurableSource
|
||||||
|
import eu.kanade.tachiyomi.source.preferenceKey
|
||||||
|
import eu.kanade.tachiyomi.source.sourcePreferences
|
||||||
|
import tachiyomi.core.preference.Preference
|
||||||
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class PreferenceBackupCreator(
|
||||||
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
|
private val preferenceStore: PreferenceStore = Injekt.get(),
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun backupAppPreferences(): List<BackupPreference> {
|
||||||
|
return preferenceStore.getAll().toBackupPreferences()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun backupSourcePreferences(): List<BackupSourcePreferences> {
|
||||||
|
return sourceManager.getCatalogueSources()
|
||||||
|
.filterIsInstance<ConfigurableSource>()
|
||||||
|
.map {
|
||||||
|
BackupSourcePreferences(
|
||||||
|
it.preferenceKey(),
|
||||||
|
it.sourcePreferences().all.toBackupPreferences(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun Map<String, *>.toBackupPreferences(): List<BackupPreference> {
|
||||||
|
return this.filterKeys {
|
||||||
|
!Preference.isPrivate(it) && !Preference.isAppState(it)
|
||||||
|
}
|
||||||
|
.mapNotNull { (key, value) ->
|
||||||
|
when (value) {
|
||||||
|
is Int -> BackupPreference(key, IntPreferenceValue(value))
|
||||||
|
is Long -> BackupPreference(key, LongPreferenceValue(value))
|
||||||
|
is Float -> BackupPreference(key, FloatPreferenceValue(value))
|
||||||
|
is String -> BackupPreference(key, StringPreferenceValue(value))
|
||||||
|
is Boolean -> BackupPreference(key, BooleanPreferenceValue(value))
|
||||||
|
is Set<*> -> (value as? Set<String>)?.let {
|
||||||
|
BackupPreference(key, StringSetPreferenceValue(it))
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
||||||
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class SourcesBackupCreator(
|
||||||
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun backupSources(mangas: List<Manga>): List<BackupSource> {
|
||||||
|
return mangas
|
||||||
|
.asSequence()
|
||||||
|
.map(Manga::source)
|
||||||
|
.distinct()
|
||||||
|
.map(sourceManager::getOrStub)
|
||||||
|
.map(BackupSource::copyFrom)
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,14 +4,6 @@ import eu.kanade.tachiyomi.source.Source
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.protobuf.ProtoNumber
|
import kotlinx.serialization.protobuf.ProtoNumber
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class BrokenBackupSource(
|
|
||||||
@ProtoNumber(0) var name: String = "",
|
|
||||||
@ProtoNumber(1) var sourceId: Long,
|
|
||||||
) {
|
|
||||||
fun toBackupSource() = BackupSource(name, sourceId)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class BackupSource(
|
data class BackupSource(
|
||||||
@ProtoNumber(1) var name: String = "",
|
@ProtoNumber(1) var name: String = "",
|
||||||
|
@ -26,3 +18,11 @@ data class BackupSource(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BrokenBackupSource(
|
||||||
|
@ProtoNumber(0) var name: String = "",
|
||||||
|
@ProtoNumber(1) var sourceId: Long,
|
||||||
|
) {
|
||||||
|
fun toBackupSource() = BackupSource(name, sourceId)
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@ import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
||||||
|
import eu.kanade.tachiyomi.data.backup.restore.restorers.CategoriesRestorer
|
||||||
|
import eu.kanade.tachiyomi.data.backup.restore.restorers.MangaRestorer
|
||||||
|
import eu.kanade.tachiyomi.data.backup.restore.restorers.PreferenceRestorer
|
||||||
import eu.kanade.tachiyomi.util.BackupUtil
|
import eu.kanade.tachiyomi.util.BackupUtil
|
||||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
@ -170,19 +173,3 @@ class BackupRestorer(
|
||||||
return File("")
|
return File("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class RestoreOptions(
|
|
||||||
val appSettings: Boolean = true,
|
|
||||||
val sourceSettings: Boolean = true,
|
|
||||||
val library: Boolean = true,
|
|
||||||
) {
|
|
||||||
fun toBooleanArray() = booleanArrayOf(appSettings, sourceSettings, library)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun fromBooleanArray(booleanArray: BooleanArray) = RestoreOptions(
|
|
||||||
appSettings = booleanArray[0],
|
|
||||||
sourceSettings = booleanArray[1],
|
|
||||||
library = booleanArray[2],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package eu.kanade.tachiyomi.data.backup.restore
|
||||||
|
|
||||||
|
data class RestoreOptions(
|
||||||
|
val appSettings: Boolean = true,
|
||||||
|
val sourceSettings: Boolean = true,
|
||||||
|
val library: Boolean = true,
|
||||||
|
) {
|
||||||
|
fun toBooleanArray() = booleanArrayOf(appSettings, sourceSettings, library)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromBooleanArray(booleanArray: BooleanArray) = RestoreOptions(
|
||||||
|
appSettings = booleanArray[0],
|
||||||
|
sourceSettings = booleanArray[1],
|
||||||
|
library = booleanArray[2],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.data.backup.restore
|
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||||
import tachiyomi.data.DatabaseHandler
|
import tachiyomi.data.DatabaseHandler
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.data.backup.restore
|
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||||
|
|
||||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.data.backup.restore
|
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
Reference in a new issue