Clean up category restoring logic
(cherry picked from commit 0f9895eec8f5808210f291d1e0ef5cc9f73ccb44) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt # app/src/main/java/eu/kanade/tachiyomi/data/backup/models/BackupCategory.kt
This commit is contained in:
parent
581e2851bc
commit
3ba70183ec
@ -26,8 +26,6 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
|
|||||||
private val notifier = BackupNotifier(context)
|
private val notifier = BackupNotifier(context)
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
if (isRunning(context)) return Result.failure()
|
|
||||||
|
|
||||||
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
||||||
?: return Result.failure()
|
?: return Result.failure()
|
||||||
val sync = inputData.getBoolean(SYNC_KEY, false)
|
val sync = inputData.getBoolean(SYNC_KEY, false)
|
||||||
|
@ -27,7 +27,7 @@ import exh.EXHMigrations
|
|||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
import exh.util.nullIfBlank
|
import exh.util.nullIfBlank
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.ensureActive
|
||||||
import tachiyomi.core.i18n.stringResource
|
import tachiyomi.core.i18n.stringResource
|
||||||
import tachiyomi.core.preference.AndroidPreferenceStore
|
import tachiyomi.core.preference.AndroidPreferenceStore
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
@ -93,14 +93,12 @@ class BackupRestorer(
|
|||||||
|
|
||||||
private val errors = mutableListOf<Pair<Date, String>>()
|
private val errors = mutableListOf<Pair<Date, String>>()
|
||||||
|
|
||||||
suspend fun syncFromBackup(uri: Uri, sync: Boolean): Boolean {
|
suspend fun syncFromBackup(uri: Uri, sync: Boolean) {
|
||||||
val startTime = System.currentTimeMillis()
|
val startTime = System.currentTimeMillis()
|
||||||
restoreProgress = 0
|
restoreProgress = 0
|
||||||
errors.clear()
|
errors.clear()
|
||||||
|
|
||||||
if (!performRestore(uri, sync)) {
|
performRestore(uri, sync)
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val endTime = System.currentTimeMillis()
|
val endTime = System.currentTimeMillis()
|
||||||
val time = endTime - startTime
|
val time = endTime - startTime
|
||||||
@ -118,7 +116,6 @@ class BackupRestorer(
|
|||||||
} else {
|
} else {
|
||||||
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
|
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeErrorLog(): File {
|
private fun writeErrorLog(): File {
|
||||||
@ -140,81 +137,62 @@ class BackupRestorer(
|
|||||||
return File("")
|
return File("")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun performRestore(uri: Uri, sync: Boolean): Boolean {
|
private suspend fun performRestore(uri: Uri, sync: Boolean) {
|
||||||
val backup = BackupUtil.decodeBackup(context, uri)
|
val backup = BackupUtil.decodeBackup(context, uri)
|
||||||
|
|
||||||
restoreAmount = backup.backupManga.size + 4 // +4 for categories, app prefs, source prefs, saved searches
|
restoreAmount = backup.backupManga.size + 4 // +4 for categories, app prefs, source prefs, saved searches
|
||||||
|
|
||||||
// Restore categories
|
|
||||||
if (backup.backupCategories.isNotEmpty()) {
|
|
||||||
restoreCategories(backup.backupCategories)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SY -->
|
|
||||||
if (backup.backupSavedSearches.isNotEmpty()) {
|
|
||||||
restoreSavedSearches(backup.backupSavedSearches)
|
|
||||||
}
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
// Store source mapping for error messages
|
// Store source mapping for error messages
|
||||||
val backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources
|
val backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources
|
||||||
sourceMapping = backupMaps.associate { it.sourceId to it.name }
|
sourceMapping = backupMaps.associate { it.sourceId to it.name }
|
||||||
now = ZonedDateTime.now()
|
now = ZonedDateTime.now()
|
||||||
currentFetchWindow = fetchInterval.getWindow(now)
|
currentFetchWindow = fetchInterval.getWindow(now)
|
||||||
|
|
||||||
return coroutineScope {
|
coroutineScope {
|
||||||
|
ensureActive()
|
||||||
|
restoreCategories(backup.backupCategories)
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
ensureActive()
|
||||||
|
restoreSavedSearches(backup.backupSavedSearches)
|
||||||
|
// SY <--
|
||||||
|
|
||||||
|
ensureActive()
|
||||||
restoreAppPreferences(backup.backupPreferences)
|
restoreAppPreferences(backup.backupPreferences)
|
||||||
|
|
||||||
|
ensureActive()
|
||||||
restoreSourcePreferences(backup.backupSourcePreferences)
|
restoreSourcePreferences(backup.backupSourcePreferences)
|
||||||
|
|
||||||
// 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 /* SY --> */.sortedBy { it.source == MERGED_SOURCE_ID } /* SY <-- */.forEach {
|
backup.backupManga/* SY --> */.sortedBy { it.source == MERGED_SOURCE_ID } /* SY <-- */.forEach {
|
||||||
if (!isActive) {
|
ensureActive()
|
||||||
return@coroutineScope false
|
|
||||||
}
|
|
||||||
|
|
||||||
restoreManga(it, backup.backupCategories, sync)
|
restoreManga(it, backup.backupCategories, sync)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optionally trigger online library + tracker update
|
// TODO: optionally trigger online library + tracker update
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun restoreCategories(backupCategories: List<BackupCategory>) {
|
private suspend fun restoreCategories(backupCategories: List<BackupCategory>) {
|
||||||
// Get categories from file and from db
|
if (backupCategories.isNotEmpty()) {
|
||||||
val dbCategories = getCategories.await()
|
val dbCategories = getCategories.await()
|
||||||
|
val dbCategoriesByName = dbCategories.associateBy { it.name }
|
||||||
|
|
||||||
val categories = backupCategories.map {
|
val categories = backupCategories.map {
|
||||||
var category = it.getCategory()
|
dbCategoriesByName[it.name]
|
||||||
var found = false
|
?: handler.awaitOneExecutable {
|
||||||
for (dbCategory in dbCategories) {
|
categoriesQueries.insert(it.name, it.order, it.flags)
|
||||||
// If the category is already in the db, assign the id to the file's category
|
categoriesQueries.selectLastInsertedRowId()
|
||||||
// and do nothing
|
}.let { id -> it.toCategory(id) }
|
||||||
if (category.name == dbCategory.name) {
|
|
||||||
category = category.copy(id = dbCategory.id)
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
// Let the db assign the id
|
|
||||||
val id = handler.awaitOneExecutable {
|
|
||||||
categoriesQueries.insert(category.name, category.order, category.flags)
|
|
||||||
categoriesQueries.selectLastInsertedRowId()
|
|
||||||
}
|
|
||||||
category = category.copy(id = id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
category
|
libraryPreferences.categorizedDisplaySettings().set(
|
||||||
|
(dbCategories + categories)
|
||||||
|
.distinctBy { it.flags }
|
||||||
|
.size > 1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryPreferences.categorizedDisplaySettings().set(
|
|
||||||
(dbCategories + categories)
|
|
||||||
.distinctBy { it.flags }
|
|
||||||
.size > 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
restoreProgress += 1
|
restoreProgress += 1
|
||||||
showRestoreProgress(
|
showRestoreProgress(
|
||||||
restoreProgress,
|
restoreProgress,
|
||||||
@ -226,6 +204,8 @@ class BackupRestorer(
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
private suspend fun restoreSavedSearches(backupSavedSearches: List<BackupSavedSearch>) {
|
private suspend fun restoreSavedSearches(backupSavedSearches: List<BackupSavedSearch>) {
|
||||||
|
if (backupSavedSearches.isEmpty()) return
|
||||||
|
|
||||||
val currentSavedSearches = handler.awaitList {
|
val currentSavedSearches = handler.awaitList {
|
||||||
saved_searchQueries.selectNamesAndSources()
|
saved_searchQueries.selectNamesAndSources()
|
||||||
}
|
}
|
||||||
|
@ -13,15 +13,13 @@ class BackupCategory(
|
|||||||
// SY specific values
|
// SY specific values
|
||||||
/*@ProtoNumber(600) var mangaOrder: List<Long> = emptyList(),*/
|
/*@ProtoNumber(600) var mangaOrder: List<Long> = emptyList(),*/
|
||||||
) {
|
) {
|
||||||
fun getCategory(): Category {
|
fun toCategory(id: Long) = Category(
|
||||||
return Category(
|
id = id,
|
||||||
id = 0,
|
name = this@BackupCategory.name,
|
||||||
name = this@BackupCategory.name,
|
flags = this@BackupCategory.flags,
|
||||||
flags = this@BackupCategory.flags,
|
order = this@BackupCategory.order,
|
||||||
order = this@BackupCategory.order,
|
/*mangaOrder = this@BackupCategory.mangaOrder*/
|
||||||
/*mangaOrder = this@BackupCategory.mangaOrder*/
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val backupCategoryMapper = { category: Category ->
|
val backupCategoryMapper = { category: Category ->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user