Warn about missing sources before restoring backup

This commit is contained in:
arkon
2020-05-16 11:18:47 -04:00
parent 1cf74a5396
commit a00d11701f
5 changed files with 108 additions and 14 deletions

View File

@ -110,6 +110,11 @@ class BackupRestoreService : Service() {
*/
private var restoreAmount = 0
/**
* Mapping of source ID to source name from backup data
*/
private var sourceMapping: Map<Long, String> = emptyMap()
/**
* List containing errors
*/
@ -212,6 +217,9 @@ class BackupRestoreService : Service() {
// Restore categories
restoreCategories(json.get(CATEGORIES))
// Store source mapping for error messages
sourceMapping = BackupRestoreValidator.getSourceMapping(json)
// Restore individual manga
mangasJson.forEach {
if (job?.isActive != true) {
@ -259,9 +267,20 @@ class BackupRestoreService : Service() {
)
try {
restoreMangaData(manga, chapters, categories, history, tracks)
val source = backupManager.sourceManager.get(manga.source)
if (source != null) {
restoreMangaData(manga, source, chapters, categories, history, tracks)
} else {
val message = if (manga.source in sourceMapping) {
getString(R.string.source_not_found_name, sourceMapping[manga.source])
} else {
getString(R.string.source_not_found)
}
errors.add(Date() to "${manga.title} - $message")
}
} catch (e: Exception) {
errors.add(Date() to "${manga.title} - ${getString(R.string.source_not_found)}")
errors.add(Date() to "${manga.title} - ${e.message}")
}
restoreProgress += 1
@ -272,6 +291,7 @@ class BackupRestoreService : Service() {
* Returns a manga restore observable
*
* @param manga manga data from json
* @param source source to get manga data from
* @param chapters chapters data from json
* @param categories categories data from json
* @param history history data from json
@ -279,13 +299,12 @@ class BackupRestoreService : Service() {
*/
private fun restoreMangaData(
manga: Manga,
source: Source,
chapters: List<Chapter>,
categories: List<String>,
history: List<DHistory>,
tracks: List<Track>
) {
// Get source
val source = backupManager.sourceManager.getOrStub(manga.source)
val dbManga = backupManager.getMangaFromDatabase(manga)
db.inTransaction {

View File

@ -0,0 +1,46 @@
package eu.kanade.tachiyomi.data.backup
import android.content.Context
import android.net.Uri
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.stream.JsonReader
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.models.Backup
object BackupRestoreValidator {
/**
* Checks for critical backup file data.
*
* @throws Exception if version or manga cannot be found.
* @return List of required sources.
*/
fun validate(context: Context, uri: Uri): Map<Long, String> {
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
val json = JsonParser.parseReader(reader).asJsonObject
val version = json.get(Backup.VERSION)
val mangasJson = json.get(Backup.MANGAS)
if (version == null || mangasJson == null) {
throw Exception(context.getString(R.string.invalid_backup_file_missing_data))
}
if (mangasJson.asJsonArray.size() == 0) {
throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
}
return getSourceMapping(json)
}
fun getSourceMapping(json: JsonObject): Map<Long, String> {
val extensionsMapping = json.get(Backup.EXTENSIONS) ?: return emptyMap()
return extensionsMapping.asJsonArray
.map {
val items = it.asString.split(":")
items[0].toLong() to items[1]
}
.toMap()
}
}

View File

@ -16,9 +16,11 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupCreateService
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
import eu.kanade.tachiyomi.data.backup.BackupRestoreValidator
import eu.kanade.tachiyomi.data.backup.models.Backup
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
import eu.kanade.tachiyomi.util.preference.defaultValue
@ -34,6 +36,8 @@ import eu.kanade.tachiyomi.util.system.getFilePicker
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class SettingsBackupController : SettingsController() {
@ -247,15 +251,36 @@ class SettingsBackupController : SettingsController() {
)
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
return MaterialDialog(activity!!)
.title(R.string.pref_restore_backup)
.message(R.string.backup_restore_content)
.positiveButton(R.string.action_restore) {
val context = applicationContext
if (context != null) {
BackupRestoreService.start(context, args.getParcelable(KEY_URI)!!)
val activity = activity!!
val uri: Uri = args.getParcelable(KEY_URI)!!
return try {
var message = activity.getString(R.string.backup_restore_content)
val sources = BackupRestoreValidator.validate(activity, uri)
if (sources.isNotEmpty()) {
val sourceManager = Injekt.get<SourceManager>()
val missingSources = sources
.filter { sourceManager.get(it.key) == null }
.values
.sorted()
if (missingSources.isNotEmpty()) {
message += "\n\n${activity.getString(R.string.backup_restore_missing_sources)}\n${missingSources.joinToString("\n") { "- $it" }}"
}
}
MaterialDialog(activity)
.title(R.string.pref_restore_backup)
.message(text = message)
.positiveButton(R.string.action_restore) {
BackupRestoreService.start(activity, uri)
}
} catch (e: Exception) {
MaterialDialog(activity)
.title(R.string.invalid_backup_file)
.message(text = e.message)
.positiveButton(android.R.string.cancel)
}
}
private companion object {