More restore code cleanup, remove some SY-specific logic
This commit is contained in:
parent
5539e4591f
commit
368c30a2cc
4 changed files with 46 additions and 73 deletions
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
|
import eu.kanade.tachiyomi.util.chapter.NoChaptersException
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import okio.source
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -23,52 +24,38 @@ abstract class AbstractBackupRestore<T : AbstractBackupManager>(protected val co
|
||||||
protected val db: DatabaseHelper by injectLazy()
|
protected val db: DatabaseHelper by injectLazy()
|
||||||
protected val trackManager: TrackManager by injectLazy()
|
protected val trackManager: TrackManager by injectLazy()
|
||||||
|
|
||||||
protected lateinit var backupManager: T
|
|
||||||
|
|
||||||
var job: Job? = null
|
var job: Job? = null
|
||||||
|
|
||||||
/**
|
protected lateinit var backupManager: T
|
||||||
* The progress of a backup restore
|
|
||||||
*/
|
|
||||||
protected var restoreProgress = 0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Amount of manga in Json file (needed for restore)
|
|
||||||
*/
|
|
||||||
protected var restoreAmount = 0
|
protected var restoreAmount = 0
|
||||||
|
protected var restoreProgress = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping of source ID to source name from backup data
|
* Mapping of source ID to source name from backup data
|
||||||
*/
|
*/
|
||||||
protected var sourceMapping: Map<Long, String> = emptyMap()
|
protected var sourceMapping: Map<Long, String> = emptyMap()
|
||||||
|
|
||||||
/**
|
|
||||||
* List containing errors
|
|
||||||
*/
|
|
||||||
protected val errors = mutableListOf<Pair<Date, String>>()
|
protected val errors = mutableListOf<Pair<Date, String>>()
|
||||||
|
|
||||||
abstract fun restoreBackup(uri: Uri): Boolean
|
abstract fun performRestore(uri: Uri): Boolean
|
||||||
|
|
||||||
/**
|
fun restoreBackup(uri: Uri): Boolean {
|
||||||
* Write errors to error log
|
val startTime = System.currentTimeMillis()
|
||||||
*/
|
restoreProgress = 0
|
||||||
internal fun writeErrorLog(): File {
|
errors.clear()
|
||||||
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 ->
|
if (!performRestore(uri)) {
|
||||||
errors.forEach { (date, message) ->
|
return false
|
||||||
out.write("[${sdf.format(date)}] $message\n")
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return destFile
|
val endTime = System.currentTimeMillis()
|
||||||
}
|
val time = endTime - startTime
|
||||||
} catch (e: Exception) {
|
|
||||||
// Empty
|
val logFile = writeErrorLog()
|
||||||
}
|
|
||||||
return File("")
|
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,4 +117,23 @@ abstract class AbstractBackupRestore<T : AbstractBackupManager>(protected val co
|
||||||
) {
|
) {
|
||||||
notifier.showRestoreProgress(title, progress, amount)
|
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("")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores backup from a JSON file.
|
* Restores backup.
|
||||||
*/
|
*/
|
||||||
class BackupRestoreService : Service() {
|
class BackupRestoreService : Service() {
|
||||||
|
|
||||||
|
@ -118,13 +118,15 @@ class BackupRestoreService : Service() {
|
||||||
// Cancel any previous job if needed.
|
// Cancel any previous job if needed.
|
||||||
backupRestore?.job?.cancel()
|
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 ->
|
val handler = CoroutineExceptionHandler { _, exception ->
|
||||||
Timber.e(exception)
|
Timber.e(exception)
|
||||||
backupRestore?.writeErrorLog()
|
backupRestore?.writeErrorLog()
|
||||||
|
|
||||||
notifier.showRestoreError(exception.message)
|
notifier.showRestoreError(exception.message)
|
||||||
|
|
||||||
stopSelf(startId)
|
stopSelf(startId)
|
||||||
}
|
}
|
||||||
backupRestore?.job = GlobalScope.launch(handler) {
|
backupRestore?.job = GlobalScope.launch(handler) {
|
||||||
|
|
|
@ -23,23 +23,13 @@ import java.util.Date
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
class FullBackupRestore(context: Context, notifier: BackupNotifier, private val online: Boolean) : AbstractBackupRestore<FullBackupManager>(context, notifier) {
|
class FullBackupRestore(context: Context, notifier: BackupNotifier, private val online: Boolean) : AbstractBackupRestore<FullBackupManager>(context, notifier) {
|
||||||
|
|
||||||
/**
|
override fun performRestore(uri: Uri): Boolean {
|
||||||
* Restores data from backup file.
|
|
||||||
*
|
|
||||||
* @param uri backup file to restore
|
|
||||||
*/
|
|
||||||
override fun restoreBackup(uri: Uri): Boolean {
|
|
||||||
val startTime = System.currentTimeMillis()
|
|
||||||
|
|
||||||
// Initialize manager
|
|
||||||
backupManager = FullBackupManager(context)
|
backupManager = FullBackupManager(context)
|
||||||
|
|
||||||
val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() }
|
val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() }
|
||||||
val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
|
val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
|
||||||
|
|
||||||
restoreAmount = backup.backupManga.size + 1 // +1 for categories
|
restoreAmount = backup.backupManga.size + 1 // +1 for categories
|
||||||
restoreProgress = 0
|
|
||||||
errors.clear()
|
|
||||||
|
|
||||||
// Restore categories
|
// Restore categories
|
||||||
if (backup.backupCategories.isNotEmpty()) {
|
if (backup.backupCategories.isNotEmpty()) {
|
||||||
|
@ -49,7 +39,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
|
||||||
// Store source mapping for error messages
|
// Store source mapping for error messages
|
||||||
sourceMapping = backup.backupSources.map { it.sourceId to it.name }.toMap()
|
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 {
|
backup.backupManga.forEach {
|
||||||
if (job?.isActive != true) {
|
if (job?.isActive != true) {
|
||||||
return false
|
return false
|
||||||
|
@ -58,12 +48,6 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
|
||||||
restoreManga(it, backup.backupCategories, online)
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,28 +26,15 @@ import java.util.Date
|
||||||
|
|
||||||
class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<LegacyBackupManager>(context, notifier) {
|
class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<LegacyBackupManager>(context, notifier) {
|
||||||
|
|
||||||
/**
|
override fun performRestore(uri: Uri): Boolean {
|
||||||
* Restores data from backup file.
|
|
||||||
*
|
|
||||||
* @param uri backup file to restore
|
|
||||||
*/
|
|
||||||
override fun restoreBackup(uri: Uri): Boolean {
|
|
||||||
val startTime = System.currentTimeMillis()
|
|
||||||
|
|
||||||
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
|
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
|
||||||
val json = JsonParser.parseReader(reader).asJsonObject
|
val json = JsonParser.parseReader(reader).asJsonObject
|
||||||
|
|
||||||
// Get parser version
|
|
||||||
val version = json.get(Backup.VERSION)?.asInt ?: 1
|
val version = json.get(Backup.VERSION)?.asInt ?: 1
|
||||||
|
|
||||||
// Initialize manager
|
|
||||||
backupManager = LegacyBackupManager(context, version)
|
backupManager = LegacyBackupManager(context, version)
|
||||||
|
|
||||||
val mangasJson = json.get(MANGAS).asJsonArray
|
val mangasJson = json.get(MANGAS).asJsonArray
|
||||||
|
restoreAmount = mangasJson.size() + 1 // +1 for categories
|
||||||
restoreAmount = mangasJson.size() + 3 // +1 for categories, +1 for saved searches, +1 for merged manga references
|
|
||||||
restoreProgress = 0
|
|
||||||
errors.clear()
|
|
||||||
|
|
||||||
// Restore categories
|
// Restore categories
|
||||||
json.get(Backup.CATEGORIES)?.let { restoreCategories(it) }
|
json.get(Backup.CATEGORIES)?.let { restoreCategories(it) }
|
||||||
|
@ -64,12 +51,6 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract
|
||||||
restoreManga(it.asJsonObject)
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue