From 5908bd19305b3461165fcfe2da5d2217115562b9 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 24 Dec 2023 17:38:01 -0500 Subject: [PATCH] Move backup models to domain module --- .../screen/data/CreateBackupScreen.kt | 4 +- .../screen/data/RestoreBackupScreen.kt | 2 +- .../screen/debug/BackupSchemaScreen.kt | 2 +- .../backup/BackupDecoder.kt} | 22 +++--- .../data/backup/BackupFileValidator.kt | 7 +- .../data/backup/create/BackupCreateJob.kt | 8 +-- .../data/backup/create/BackupCreator.kt | 71 ++++++++++++------- .../creators/CategoriesBackupCreator.kt | 4 +- .../create/creators/MangaBackupCreator.kt | 34 +++++++-- .../creators/PreferenceBackupCreator.kt | 16 ++--- .../create/creators/SourcesBackupCreator.kt | 11 ++- .../data/backup/models/BackupSerializer.kt | 6 -- .../data/backup/restore/BackupRestorer.kt | 12 ++-- .../restore/restorers/CategoriesRestorer.kt | 2 +- .../backup/restore/restorers/MangaRestorer.kt | 10 +-- .../restore/restorers/PreferenceRestorer.kt | 16 ++--- .../java/eu/kanade/tachiyomi/di/AppModule.kt | 4 ++ domain/build.gradle.kts | 2 + .../tachiyomi/domain/backup/model}/Backup.kt | 22 ++---- .../domain/backup/model}/BackupCategory.kt | 2 +- .../domain/backup/model}/BackupChapter.kt | 2 +- .../domain/backup/model}/BackupHistory.kt | 2 +- .../domain/backup/model}/BackupManga.kt | 27 +------ .../domain/backup/model}/BackupPreference.kt | 2 +- .../domain/backup/model}/BackupSource.kt | 14 +--- .../domain/backup/model}/BackupTracking.kt | 2 +- 26 files changed, 155 insertions(+), 151 deletions(-) rename app/src/main/java/eu/kanade/tachiyomi/{util/BackupUtil.kt => data/backup/BackupDecoder.kt} (56%) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSerializer.kt rename {app/src/main/java/eu/kanade/tachiyomi/data/backup/models => domain/src/main/java/tachiyomi/domain/backup/model}/Backup.kt (54%) rename {app/src/main/java/eu/kanade/tachiyomi/data/backup/models => domain/src/main/java/tachiyomi/domain/backup/model}/BackupCategory.kt (94%) rename {app/src/main/java/eu/kanade/tachiyomi/data/backup/models => domain/src/main/java/tachiyomi/domain/backup/model}/BackupChapter.kt (97%) rename {app/src/main/java/eu/kanade/tachiyomi/data/backup/models => domain/src/main/java/tachiyomi/domain/backup/model}/BackupHistory.kt (94%) rename {app/src/main/java/eu/kanade/tachiyomi/data/backup/models => domain/src/main/java/tachiyomi/domain/backup/model}/BackupManga.kt (73%) rename {app/src/main/java/eu/kanade/tachiyomi/data/backup/models => domain/src/main/java/tachiyomi/domain/backup/model}/BackupPreference.kt (95%) rename {app/src/main/java/eu/kanade/tachiyomi/data/backup/models => domain/src/main/java/tachiyomi/domain/backup/model}/BackupSource.kt (57%) rename {app/src/main/java/eu/kanade/tachiyomi/data/backup/models => domain/src/main/java/tachiyomi/domain/backup/model}/BackupTracking.kt (98%) diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt index cb758be40d..1d1dfd1b52 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt @@ -31,7 +31,7 @@ import eu.kanade.presentation.components.WarningBanner import eu.kanade.presentation.util.Screen import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob -import eu.kanade.tachiyomi.data.backup.models.Backup +import eu.kanade.tachiyomi.data.backup.create.BackupCreator import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.toast import kotlinx.collections.immutable.PersistentSet @@ -123,7 +123,7 @@ class CreateBackupScreen : Screen() { onClick = { if (!BackupCreateJob.isManualJobRunning(context)) { try { - chooseBackupDir.launch(Backup.getFilename()) + chooseBackupDir.launch(BackupCreator.getFilename()) } catch (e: ActivityNotFoundException) { context.toast(MR.strings.file_picker_error) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt index f1f3be877a..2d6aebced9 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/RestoreBackupScreen.kt @@ -154,7 +154,7 @@ class RestoreBackupScreen : Screen() { } val results = try { - BackupFileValidator().validate(context, it) + BackupFileValidator(context).validate(it) } catch (e: Exception) { model.setError(InvalidRestore(it, e.message.toString())) return@rememberLauncherForActivityResult diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt index d5652b16ac..7d42ebb42c 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/debug/BackupSchemaScreen.kt @@ -17,10 +17,10 @@ import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.util.Screen -import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.util.system.copyToClipboard import kotlinx.collections.immutable.persistentListOf import kotlinx.serialization.protobuf.schema.ProtoBufSchemaGenerator +import tachiyomi.domain.backup.model.Backup import tachiyomi.i18n.MR import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.i18n.stringResource diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/BackupUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt similarity index 56% rename from app/src/main/java/eu/kanade/tachiyomi/util/BackupUtil.kt rename to app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt index 05401603fd..e7778aad54 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/BackupUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupDecoder.kt @@ -1,21 +1,25 @@ -package eu.kanade.tachiyomi.util +package eu.kanade.tachiyomi.data.backup import android.content.Context import android.net.Uri -import eu.kanade.tachiyomi.data.backup.create.BackupCreator -import eu.kanade.tachiyomi.data.backup.models.Backup -import eu.kanade.tachiyomi.data.backup.models.BackupSerializer +import kotlinx.serialization.protobuf.ProtoBuf import okio.buffer import okio.gzip import okio.source +import tachiyomi.domain.backup.model.Backup +import tachiyomi.domain.backup.model.BackupSerializer +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +class BackupDecoder( + private val context: Context, + private val parser: ProtoBuf = Injekt.get(), +) { -object BackupUtil { /** * Decode a potentially-gzipped backup. */ - fun decodeBackup(context: Context, uri: Uri): Backup { - val backupCreator = BackupCreator(context) - + fun decode(uri: Uri): Backup { val backupStringSource = context.contentResolver.openInputStream(uri)!!.source().buffer() val peeked = backupStringSource.peek() @@ -27,6 +31,6 @@ object BackupUtil { backupStringSource }.use { it.readByteArray() } - return backupCreator.parser.decodeFromByteArray(BackupSerializer, backupString) + return parser.decodeFromByteArray(BackupSerializer, backupString) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt index fdf3d68d99..acc768e5a1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt @@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context import android.net.Uri import eu.kanade.tachiyomi.data.track.TrackerManager -import eu.kanade.tachiyomi.util.BackupUtil import tachiyomi.core.i18n.stringResource import tachiyomi.domain.source.service.SourceManager import tachiyomi.i18n.MR @@ -11,6 +10,8 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class BackupFileValidator( + private val context: Context, + private val sourceManager: SourceManager = Injekt.get(), private val trackerManager: TrackerManager = Injekt.get(), ) { @@ -21,9 +22,9 @@ class BackupFileValidator( * @throws Exception if manga cannot be found. * @return List of missing sources or missing trackers. */ - fun validate(context: Context, uri: Uri): Results { + fun validate(uri: Uri): Results { val backup = try { - BackupUtil.decodeBackup(context, uri) + BackupDecoder(context).decode(uri) } catch (e: Exception) { throw IllegalStateException(e) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateJob.kt index 4ca6b056b5..c2f1e5ded7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreateJob.kt @@ -29,7 +29,6 @@ import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.storage.service.StorageManager import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.time.Instant import java.util.concurrent.TimeUnit class BackupCreateJob(private val context: Context, workerParams: WorkerParameters) : @@ -49,13 +48,10 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete setForegroundSafely() val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupCreateFlags.AutomaticDefaults) - val backupPreferences = Injekt.get() return try { - val location = BackupCreator(context).createBackup(uri, flags, isAutoBackup) - if (isAutoBackup) { - backupPreferences.lastAutoBackupTimestamp().set(Instant.now().toEpochMilli()) - } else { + val location = BackupCreator(context, isAutoBackup).backup(uri, flags) + if (!isAutoBackup) { notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())!!) } Result.success() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt index 4dc2585cbb..ef2a5328db 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.backup.create import android.content.Context import android.net.Uri import com.hippo.unifile.UniFile +import eu.kanade.tachiyomi.BuildConfig 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 @@ -11,13 +12,6 @@ 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.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 kotlinx.serialization.protobuf.ProtoBuf import logcat.LogPriority import okio.buffer @@ -25,31 +19,40 @@ import okio.gzip import okio.sink import tachiyomi.core.i18n.stringResource import tachiyomi.core.util.system.logcat +import tachiyomi.domain.backup.model.Backup +import tachiyomi.domain.backup.model.BackupCategory +import tachiyomi.domain.backup.model.BackupManga +import tachiyomi.domain.backup.model.BackupPreference +import tachiyomi.domain.backup.model.BackupSerializer +import tachiyomi.domain.backup.model.BackupSource +import tachiyomi.domain.backup.model.BackupSourcePreferences +import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.manga.interactor.GetFavorites import tachiyomi.domain.manga.model.Manga import tachiyomi.i18n.MR import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.io.FileOutputStream +import java.text.SimpleDateFormat +import java.time.Instant +import java.util.Date +import java.util.Locale class BackupCreator( private val context: Context, + private val isAutoBackup: Boolean, + + private val parser: ProtoBuf = Injekt.get(), + private val getFavorites: GetFavorites = Injekt.get(), + private val backupPreferences: BackupPreferences = Injekt.get(), + 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(), ) { - internal val parser = ProtoBuf - - /** - * Create backup file. - * - * @param uri path of Uri - * @param isAutoBackup backup called from scheduled backup job - */ - suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String { + suspend fun backup(uri: Uri, flags: Int): String { var file: UniFile? = null try { file = ( @@ -58,14 +61,14 @@ class BackupCreator( val dir = UniFile.fromUri(context, uri) // Delete older backups - dir?.listFiles { _, filename -> Backup.filenameRegex.matches(filename) } + dir?.listFiles { _, filename -> FILENAME_REGEX.matches(filename) } .orEmpty() .sortedByDescending { it.name } .drop(MAX_AUTO_BACKUPS - 1) .forEach { it.delete() } // Create new file to place backup - dir?.createFile(Backup.getFilename()) + dir?.createFile(BackupCreator.getFilename()) } else { UniFile.fromUri(context, uri) } @@ -90,14 +93,22 @@ class BackupCreator( throw IllegalStateException(context.stringResource(MR.strings.empty_backup_error)) } - file.openOutputStream().also { - // Force overwrite old file - (it as? FileOutputStream)?.channel?.truncate(0) - }.sink().gzip().buffer().use { it.write(byteArray) } + file.openOutputStream() + .also { + // Force overwrite old file + (it as? FileOutputStream)?.channel?.truncate(0) + } + .sink().gzip().buffer().use { + it.write(byteArray) + } val fileUri = file.uri // Make sure it's a valid backup file - BackupFileValidator().validate(context, fileUri) + BackupFileValidator(context).validate(fileUri) + + if (isAutoBackup) { + backupPreferences.lastAutoBackupTimestamp().set(Instant.now().toEpochMilli()) + } return fileUri.toString() } catch (e: Exception) { @@ -132,6 +143,14 @@ class BackupCreator( return preferenceBackupCreator.backupSourcePreferences() } -} -private val MAX_AUTO_BACKUPS: Int = 4 + companion object { + private const val MAX_AUTO_BACKUPS: Int = 4 + private val FILENAME_REGEX = """${BuildConfig.APPLICATION_ID}_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}.tachibk""".toRegex() + + fun getFilename(): String { + val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.ENGLISH).format(Date()) + return "${BuildConfig.APPLICATION_ID}_$date.tachibk" + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt index e1ed56ee1a..1649577683 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/CategoriesBackupCreator.kt @@ -1,7 +1,7 @@ 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.backup.model.BackupCategory +import tachiyomi.domain.backup.model.backupCategoryMapper import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.model.Category import uy.kohesive.injekt.Injekt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt index 7a176dec20..94a550e310 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/MangaBackupCreator.kt @@ -1,12 +1,13 @@ 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 eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import tachiyomi.data.DatabaseHandler +import tachiyomi.domain.backup.model.BackupChapter +import tachiyomi.domain.backup.model.BackupHistory +import tachiyomi.domain.backup.model.BackupManga +import tachiyomi.domain.backup.model.backupChapterMapper +import tachiyomi.domain.backup.model.backupTrackMapper import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.manga.model.Manga @@ -27,7 +28,7 @@ class MangaBackupCreator( private suspend fun backupManga(manga: Manga, options: Int): BackupManga { // Entry for this manga - val mangaObject = BackupManga.copyFrom(manga) + val mangaObject = manga.toBackupManga() // Check if user wants chapter information in backup if (options and BackupCreateFlags.BACKUP_CHAPTER == BackupCreateFlags.BACKUP_CHAPTER) { @@ -77,3 +78,24 @@ class MangaBackupCreator( return mangaObject } } + +private fun Manga.toBackupManga() = + BackupManga( + url = this.url, + title = this.title, + artist = this.artist, + author = this.author, + description = this.description, + genre = this.genre.orEmpty(), + status = this.status.toInt(), + thumbnailUrl = this.thumbnailUrl, + favorite = this.favorite, + source = this.source, + dateAdded = this.dateAdded, + viewer = (this.viewerFlags.toInt() and ReadingMode.MASK), + viewer_flags = this.viewerFlags.toInt(), + chapterFlags = this.chapterFlags.toInt(), + updateStrategy = this.updateStrategy, + lastModifiedAt = this.lastModifiedAt, + favoriteModifiedAt = this.favoriteModifiedAt, + ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt index c75612de94..74e36da192 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/PreferenceBackupCreator.kt @@ -1,18 +1,18 @@ 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.backup.model.BackupPreference +import tachiyomi.domain.backup.model.BackupSourcePreferences +import tachiyomi.domain.backup.model.BooleanPreferenceValue +import tachiyomi.domain.backup.model.FloatPreferenceValue +import tachiyomi.domain.backup.model.IntPreferenceValue +import tachiyomi.domain.backup.model.LongPreferenceValue +import tachiyomi.domain.backup.model.StringPreferenceValue +import tachiyomi.domain.backup.model.StringSetPreferenceValue import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt index 8b964029c7..bf1c7ba368 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/create/creators/SourcesBackupCreator.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.data.backup.create.creators -import eu.kanade.tachiyomi.data.backup.models.BackupSource +import eu.kanade.tachiyomi.source.Source +import tachiyomi.domain.backup.model.BackupSource import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt @@ -16,7 +17,13 @@ class SourcesBackupCreator( .map(Manga::source) .distinct() .map(sourceManager::getOrStub) - .map(BackupSource::copyFrom) + .map { it.toBackupSource() } .toList() } } + +private fun Source.toBackupSource() = + BackupSource( + name = this.name, + sourceId = this.id, + ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSerializer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSerializer.kt deleted file mode 100644 index 2e79ebecd9..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSerializer.kt +++ /dev/null @@ -1,6 +0,0 @@ -package eu.kanade.tachiyomi.data.backup.models - -import kotlinx.serialization.Serializer - -@Serializer(forClass = Backup::class) -object BackupSerializer diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt index b99421baa1..5d9fd8f999 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt @@ -2,21 +2,21 @@ package eu.kanade.tachiyomi.data.backup.restore import android.content.Context import android.net.Uri +import eu.kanade.tachiyomi.data.backup.BackupDecoder import eu.kanade.tachiyomi.data.backup.BackupNotifier -import eu.kanade.tachiyomi.data.backup.models.BackupCategory -import eu.kanade.tachiyomi.data.backup.models.BackupManga -import eu.kanade.tachiyomi.data.backup.models.BackupPreference -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.system.createFileInCacheDir import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.ensureActive import kotlinx.coroutines.launch import tachiyomi.core.i18n.stringResource +import tachiyomi.domain.backup.model.BackupCategory +import tachiyomi.domain.backup.model.BackupManga +import tachiyomi.domain.backup.model.BackupPreference +import tachiyomi.domain.backup.model.BackupSourcePreferences import tachiyomi.i18n.MR import java.io.File import java.text.SimpleDateFormat @@ -61,7 +61,7 @@ class BackupRestorer( } private suspend fun restoreFromFile(uri: Uri, options: RestoreOptions) { - val backup = BackupUtil.decodeBackup(context, uri) + val backup = BackupDecoder(context).decode(uri) // Store source mapping for error messages val backupMaps = backup.backupSources + backup.backupBrokenSources.map { it.toBackupSource() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt index f98af10453..00f7fe96cb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/CategoriesRestorer.kt @@ -1,7 +1,7 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers -import eu.kanade.tachiyomi.data.backup.models.BackupCategory import tachiyomi.data.DatabaseHandler +import tachiyomi.domain.backup.model.BackupCategory import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.library.service.LibraryPreferences import uy.kohesive.injekt.Injekt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt index aba2f17229..deb4e5553d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/MangaRestorer.kt @@ -1,13 +1,13 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers import eu.kanade.domain.manga.interactor.UpdateManga -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.BackupTracking import tachiyomi.data.DatabaseHandler import tachiyomi.data.UpdateStrategyColumnAdapter +import tachiyomi.domain.backup.model.BackupCategory +import tachiyomi.domain.backup.model.BackupChapter +import tachiyomi.domain.backup.model.BackupHistory +import tachiyomi.domain.backup.model.BackupManga +import tachiyomi.domain.backup.model.BackupTracking import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId import tachiyomi.domain.chapter.model.Chapter diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt index 1062937d43..ac215fbb6b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/restorers/PreferenceRestorer.kt @@ -2,18 +2,18 @@ package eu.kanade.tachiyomi.data.backup.restore.restorers import android.content.Context import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob -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.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.source.sourcePreferences import tachiyomi.core.preference.AndroidPreferenceStore import tachiyomi.core.preference.PreferenceStore +import tachiyomi.domain.backup.model.BackupPreference +import tachiyomi.domain.backup.model.BackupSourcePreferences +import tachiyomi.domain.backup.model.BooleanPreferenceValue +import tachiyomi.domain.backup.model.FloatPreferenceValue +import tachiyomi.domain.backup.model.IntPreferenceValue +import tachiyomi.domain.backup.model.LongPreferenceValue +import tachiyomi.domain.backup.model.StringPreferenceValue +import tachiyomi.domain.backup.model.StringSetPreferenceValue import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get diff --git a/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt index 3477cb2960..4e4abe744f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/di/AppModule.kt @@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.source.AndroidSourceManager import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory import kotlinx.serialization.json.Json +import kotlinx.serialization.protobuf.ProtoBuf import nl.adaptivity.xmlutil.XmlDeclMode import nl.adaptivity.xmlutil.core.XmlVersion import nl.adaptivity.xmlutil.serialization.XML @@ -106,6 +107,9 @@ class AppModule(val app: Application) : InjektModule { xmlVersion = XmlVersion.XML10 } } + addSingletonFactory { + ProtoBuf + } addSingletonFactory { ChapterCache(app) } addSingletonFactory { CoverCache(app) } diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index 4df15c79a9..425551ca03 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("com.android.library") kotlin("android") + kotlin("plugin.serialization") } android { @@ -18,6 +19,7 @@ dependencies { implementation(platform(kotlinx.coroutines.bom)) implementation(kotlinx.bundles.coroutines) + implementation(kotlinx.bundles.serialization) implementation(libs.unifile) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt b/domain/src/main/java/tachiyomi/domain/backup/model/Backup.kt similarity index 54% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt rename to domain/src/main/java/tachiyomi/domain/backup/model/Backup.kt index 0bfe17e597..2c3ecff5f7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/Backup.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/model/Backup.kt @@ -1,11 +1,11 @@ -package eu.kanade.tachiyomi.data.backup.models +package tachiyomi.domain.backup.model -import eu.kanade.tachiyomi.BuildConfig import kotlinx.serialization.Serializable +import kotlinx.serialization.Serializer import kotlinx.serialization.protobuf.ProtoNumber -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale + +@Serializer(forClass = Backup::class) +object BackupSerializer @Serializable data class Backup( @@ -15,14 +15,4 @@ data class Backup( @ProtoNumber(101) var backupSources: List = emptyList(), @ProtoNumber(104) var backupPreferences: List = emptyList(), @ProtoNumber(105) var backupSourcePreferences: List = emptyList(), -) { - - companion object { - val filenameRegex = """${BuildConfig.APPLICATION_ID}_\d+-\d+-\d+_\d+-\d+.tachibk""".toRegex() - - fun getFilename(): String { - val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date()) - return "${BuildConfig.APPLICATION_ID}_$date.tachibk" - } - } -} +) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt b/domain/src/main/java/tachiyomi/domain/backup/model/BackupCategory.kt similarity index 94% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt rename to domain/src/main/java/tachiyomi/domain/backup/model/BackupCategory.kt index df517e8eda..1a39ecee95 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/model/BackupCategory.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.data.backup.models +package tachiyomi.domain.backup.model import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt b/domain/src/main/java/tachiyomi/domain/backup/model/BackupChapter.kt similarity index 97% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt rename to domain/src/main/java/tachiyomi/domain/backup/model/BackupChapter.kt index 567ca372cd..c232ffa4b3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupChapter.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/model/BackupChapter.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.data.backup.models +package tachiyomi.domain.backup.model import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupHistory.kt b/domain/src/main/java/tachiyomi/domain/backup/model/BackupHistory.kt similarity index 94% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupHistory.kt rename to domain/src/main/java/tachiyomi/domain/backup/model/BackupHistory.kt index 1108a376e7..cb692cde27 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupHistory.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/model/BackupHistory.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.data.backup.models +package tachiyomi.domain.backup.model import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt b/domain/src/main/java/tachiyomi/domain/backup/model/BackupManga.kt similarity index 73% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt rename to domain/src/main/java/tachiyomi/domain/backup/model/BackupManga.kt index 003b1ae192..b34a29cd47 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupManga.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/model/BackupManga.kt @@ -1,7 +1,6 @@ -package eu.kanade.tachiyomi.data.backup.models +package tachiyomi.domain.backup.model import eu.kanade.tachiyomi.source.model.UpdateStrategy -import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber import tachiyomi.domain.manga.model.Manga @@ -60,28 +59,4 @@ data class BackupManga( favoriteModifiedAt = this@BackupManga.favoriteModifiedAt, ) } - - companion object { - fun copyFrom(manga: Manga): BackupManga { - return BackupManga( - url = manga.url, - title = manga.title, - artist = manga.artist, - author = manga.author, - description = manga.description, - genre = manga.genre.orEmpty(), - status = manga.status.toInt(), - thumbnailUrl = manga.thumbnailUrl, - favorite = manga.favorite, - source = manga.source, - dateAdded = manga.dateAdded, - viewer = (manga.viewerFlags.toInt() and ReadingMode.MASK), - viewer_flags = manga.viewerFlags.toInt(), - chapterFlags = manga.chapterFlags.toInt(), - updateStrategy = manga.updateStrategy, - lastModifiedAt = manga.lastModifiedAt, - favoriteModifiedAt = manga.favoriteModifiedAt, - ) - } - } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt b/domain/src/main/java/tachiyomi/domain/backup/model/BackupPreference.kt similarity index 95% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt rename to domain/src/main/java/tachiyomi/domain/backup/model/BackupPreference.kt index 3884f37e3f..516d4dac2d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupPreference.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/model/BackupPreference.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.data.backup.models +package tachiyomi.domain.backup.model import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSource.kt b/domain/src/main/java/tachiyomi/domain/backup/model/BackupSource.kt similarity index 57% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSource.kt rename to domain/src/main/java/tachiyomi/domain/backup/model/BackupSource.kt index cb75805aeb..aae2cf03d2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupSource.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/model/BackupSource.kt @@ -1,6 +1,5 @@ -package eu.kanade.tachiyomi.data.backup.models +package tachiyomi.domain.backup.model -import eu.kanade.tachiyomi.source.Source import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber @@ -8,16 +7,7 @@ import kotlinx.serialization.protobuf.ProtoNumber data class BackupSource( @ProtoNumber(1) var name: String = "", @ProtoNumber(2) var sourceId: Long, -) { - companion object { - fun copyFrom(source: Source): BackupSource { - return BackupSource( - name = source.name, - sourceId = source.id, - ) - } - } -} +) @Serializable data class BrokenBackupSource( diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt b/domain/src/main/java/tachiyomi/domain/backup/model/BackupTracking.kt similarity index 98% rename from app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt rename to domain/src/main/java/tachiyomi/domain/backup/model/BackupTracking.kt index 35d4864925..caa727ad38 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupTracking.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/model/BackupTracking.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.data.backup.models +package tachiyomi.domain.backup.model import kotlinx.serialization.Serializable import kotlinx.serialization.protobuf.ProtoNumber