|
@@ -6,47 +6,27 @@ import com.hippo.unifile.UniFile
|
|
|
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_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_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.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.BackupPreference
|
|
|
import eu.kanade.tachiyomi.data.backup.models.BackupSerializer
|
|
|
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
|
|
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 logcat.LogPriority
|
|
|
import okio.buffer
|
|
|
import okio.gzip
|
|
|
import okio.sink
|
|
|
import tachiyomi.core.i18n.stringResource
|
|
|
-import tachiyomi.core.preference.Preference
|
|
|
-import tachiyomi.core.preference.PreferenceStore
|
|
|
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.model.Manga
|
|
|
-import tachiyomi.domain.source.service.SourceManager
|
|
|
import tachiyomi.i18n.MR
|
|
|
import uy.kohesive.injekt.Injekt
|
|
|
import uy.kohesive.injekt.api.get
|
|
@@ -54,15 +34,13 @@ import java.io.FileOutputStream
|
|
|
|
|
|
class BackupCreator(
|
|
|
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
|
|
|
|
|
|
/**
|
|
@@ -72,16 +50,6 @@ class BackupCreator(
|
|
|
* @param isAutoBackup backup called from scheduled backup job
|
|
|
*/
|
|
|
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
|
|
|
try {
|
|
|
file = (
|
|
@@ -108,6 +76,15 @@ class BackupCreator(
|
|
|
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)
|
|
|
if (byteArray.isEmpty()) {
|
|
|
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> {
|
|
|
- // Check if user wants category information in backup
|
|
|
- return if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
|
|
- getCategories.await()
|
|
|
- .filterNot(Category::isSystemCategory)
|
|
|
- .map(backupCategoryMapper)
|
|
|
- } else {
|
|
|
- emptyList()
|
|
|
- }
|
|
|
+ if (options and BACKUP_CATEGORY != BACKUP_CATEGORY) return emptyList()
|
|
|
+
|
|
|
+ return categoriesBackupCreator.backupCategories()
|
|
|
}
|
|
|
|
|
|
private suspend fun backupMangas(mangas: List<Manga>, flags: Int): List<BackupManga> {
|
|
|
- return mangas.map {
|
|
|
- backupManga(it, flags)
|
|
|
- }
|
|
|
+ return mangaBackupCreator.backupMangas(mangas, flags)
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Convert a manga to Json
|
|
|
- *
|
|
|
- * @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 backupSources(mangas: List<Manga>): List<BackupSource> {
|
|
|
+ return sourcesBackupCreator.backupSources(mangas)
|
|
|
}
|
|
|
|
|
|
private fun backupAppPreferences(flags: Int): List<BackupPreference> {
|
|
|
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> {
|
|
|
if (flags and BACKUP_SOURCE_PREFS != BACKUP_SOURCE_PREFS) return emptyList()
|
|
|
|
|
|
- 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
|
|
|
- }
|
|
|
- }
|
|
|
+ return preferenceBackupCreator.backupSourcePreferences()
|
|
|
}
|
|
|
}
|
|
|
|