diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt index 98860b8ee..19e41c429 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt @@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.util.chapter.NoChaptersException import kotlinx.coroutines.Job +import okio.source import rx.Observable import uy.kohesive.injekt.injectLazy import java.io.File @@ -23,52 +24,38 @@ abstract class AbstractBackupRestore(protected val co protected val db: DatabaseHelper by injectLazy() protected val trackManager: TrackManager by injectLazy() - protected lateinit var backupManager: T - var job: Job? = null - /** - * The progress of a backup restore - */ - protected var restoreProgress = 0 + protected lateinit var backupManager: T - /** - * Amount of manga in Json file (needed for restore) - */ protected var restoreAmount = 0 + protected var restoreProgress = 0 /** * Mapping of source ID to source name from backup data */ protected var sourceMapping: Map = emptyMap() - /** - * List containing errors - */ protected val errors = mutableListOf>() - abstract fun restoreBackup(uri: Uri): Boolean + abstract fun performRestore(uri: Uri): Boolean - /** - * Write errors to error log - */ - internal fun writeErrorLog(): File { - try { - if (errors.isNotEmpty()) { - val destFile = File(context.externalCacheDir, "tachiyomi_restore.txt") - val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()) + fun restoreBackup(uri: Uri): Boolean { + val startTime = System.currentTimeMillis() + restoreProgress = 0 + errors.clear() - destFile.bufferedWriter().use { out -> - errors.forEach { (date, message) -> - out.write("[${sdf.format(date)}] $message\n") - } - } - return destFile - } - } catch (e: Exception) { - // Empty + if (!performRestore(uri)) { + return false } - return File("") + + val endTime = System.currentTimeMillis() + val time = endTime - startTime + + val logFile = writeErrorLog() + + notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name) + return true } /** @@ -130,4 +117,23 @@ abstract class AbstractBackupRestore(protected val co ) { notifier.showRestoreProgress(title, progress, amount) } + + internal fun writeErrorLog(): File { + try { + if (errors.isNotEmpty()) { + val destFile = File(context.externalCacheDir, "tachiyomi_restore.txt") + val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()) + + destFile.bufferedWriter().use { out -> + errors.forEach { (date, message) -> + out.write("[${sdf.format(date)}] $message\n") + } + } + return destFile + } + } catch (e: Exception) { + // Empty + } + return File("") + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt index 3185b968a..10320b602 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt @@ -19,7 +19,7 @@ import kotlinx.coroutines.launch import timber.log.Timber /** - * Restores backup from a JSON file. + * Restores backup. */ class BackupRestoreService : Service() { @@ -118,13 +118,15 @@ class BackupRestoreService : Service() { // Cancel any previous job if needed. backupRestore?.job?.cancel() - backupRestore = if (mode == BackupConst.BACKUP_TYPE_FULL) FullBackupRestore(this, notifier, online) else LegacyBackupRestore(this, notifier) + backupRestore = when (mode) { + BackupConst.BACKUP_TYPE_FULL -> FullBackupRestore(this, notifier, online) + else -> LegacyBackupRestore(this, notifier) + } val handler = CoroutineExceptionHandler { _, exception -> Timber.e(exception) backupRestore?.writeErrorLog() notifier.showRestoreError(exception.message) - stopSelf(startId) } backupRestore?.job = GlobalScope.launch(handler) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt index 990e53f38..405d8b233 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt @@ -23,23 +23,13 @@ import java.util.Date @OptIn(ExperimentalSerializationApi::class) class FullBackupRestore(context: Context, notifier: BackupNotifier, private val online: Boolean) : AbstractBackupRestore(context, notifier) { - /** - * Restores data from backup file. - * - * @param uri backup file to restore - */ - override fun restoreBackup(uri: Uri): Boolean { - val startTime = System.currentTimeMillis() - - // Initialize manager + override fun performRestore(uri: Uri): Boolean { backupManager = FullBackupManager(context) val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() } val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString) restoreAmount = backup.backupManga.size + 1 // +1 for categories - restoreProgress = 0 - errors.clear() // Restore categories if (backup.backupCategories.isNotEmpty()) { @@ -49,7 +39,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val // Store source mapping for error messages sourceMapping = backup.backupSources.map { it.sourceId to it.name }.toMap() - // Restore individual manga, sort by merged source so that merged source manga go last and merged references get the proper ids + // Restore individual manga backup.backupManga.forEach { if (job?.isActive != true) { return false @@ -58,12 +48,6 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val restoreManga(it, backup.backupCategories, online) } - val endTime = System.currentTimeMillis() - val time = endTime - startTime - - val logFile = writeErrorLog() - - notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name) return true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt index 575f7d09b..8ba6e83c3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt @@ -26,28 +26,15 @@ import java.util.Date class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore(context, notifier) { - /** - * Restores data from backup file. - * - * @param uri backup file to restore - */ - override fun restoreBackup(uri: Uri): Boolean { - val startTime = System.currentTimeMillis() - + override fun performRestore(uri: Uri): Boolean { val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader()) val json = JsonParser.parseReader(reader).asJsonObject - // Get parser version val version = json.get(Backup.VERSION)?.asInt ?: 1 - - // Initialize manager backupManager = LegacyBackupManager(context, version) val mangasJson = json.get(MANGAS).asJsonArray - - restoreAmount = mangasJson.size() + 3 // +1 for categories, +1 for saved searches, +1 for merged manga references - restoreProgress = 0 - errors.clear() + restoreAmount = mangasJson.size() + 1 // +1 for categories // Restore categories json.get(Backup.CATEGORIES)?.let { restoreCategories(it) } @@ -64,12 +51,6 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract restoreManga(it.asJsonObject) } - val endTime = System.currentTimeMillis() - val time = endTime - startTime - - val logFile = writeErrorLog() - - notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name) return true }