Remove online protobuf backup restore option

This commit is contained in:
arkon 2021-03-13 18:45:22 -05:00
parent 112e233498
commit 94f5117941
5 changed files with 63 additions and 158 deletions

View File

@ -43,12 +43,11 @@ class BackupRestoreService : Service() {
* @param context context of application
* @param uri path of Uri
*/
fun start(context: Context, uri: Uri, mode: Int, online: Boolean?) {
fun start(context: Context, uri: Uri, mode: Int) {
if (!isRunning(context)) {
val intent = Intent(context, BackupRestoreService::class.java).apply {
putExtra(BackupConst.EXTRA_URI, uri)
putExtra(BackupConst.EXTRA_MODE, mode)
online?.let { putExtra(BackupConst.EXTRA_TYPE, it) }
}
ContextCompat.startForegroundService(context, intent)
}
@ -119,13 +118,12 @@ class BackupRestoreService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
val mode = intent.getIntExtra(BackupConst.EXTRA_MODE, BackupConst.BACKUP_TYPE_FULL)
val online = intent.getBooleanExtra(BackupConst.EXTRA_TYPE, true)
// Cancel any previous job if needed.
backupRestore?.job?.cancel()
backupRestore = when (mode) {
BackupConst.BACKUP_TYPE_FULL -> FullBackupRestore(this, notifier, online)
BackupConst.BACKUP_TYPE_FULL -> FullBackupRestore(this, notifier)
else -> LegacyBackupRestore(this, notifier)
}

View File

@ -26,9 +26,6 @@ import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.model.toSManga
import kotlinx.serialization.protobuf.ProtoBuf
import okio.buffer
import okio.gzip
@ -183,24 +180,13 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
/**
* Fetches manga information
*
* @param source source of manga
* @param manga manga that needs updating
* @return Updated manga info.
*/
suspend fun restoreMangaFetch(source: Source?, manga: Manga, online: Boolean): Manga {
return if (online && source != null) {
val networkManga = source.getMangaDetails(manga.toMangaInfo())
manga.also {
it.copyFrom(networkManga.toSManga())
it.favorite = manga.favorite
it.initialized = true
it.id = insertManga(manga)
}
} else {
manga.also {
it.initialized = it.description != null
it.id = insertManga(it)
}
fun restoreManga(manga: Manga): Manga {
return manga.also {
it.initialized = it.description != null
it.id = insertManga(it)
}
}
@ -309,29 +295,26 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
val trackToUpdate = mutableListOf<Track>()
tracks.forEach { track ->
val service = trackManager.getService(track.sync_id)
if (service != null && service.isLogged) {
var isInDatabase = false
for (dbTrack in dbTracks) {
if (track.sync_id == dbTrack.sync_id) {
// The sync is already in the db, only update its fields
if (track.media_id != dbTrack.media_id) {
dbTrack.media_id = track.media_id
}
if (track.library_id != dbTrack.library_id) {
dbTrack.library_id = track.library_id
}
dbTrack.last_chapter_read = max(dbTrack.last_chapter_read, track.last_chapter_read)
isInDatabase = true
trackToUpdate.add(dbTrack)
break
var isInDatabase = false
for (dbTrack in dbTracks) {
if (track.sync_id == dbTrack.sync_id) {
// The sync is already in the db, only update its fields
if (track.media_id != dbTrack.media_id) {
dbTrack.media_id = track.media_id
}
if (track.library_id != dbTrack.library_id) {
dbTrack.library_id = track.library_id
}
dbTrack.last_chapter_read = max(dbTrack.last_chapter_read, track.last_chapter_read)
isInDatabase = true
trackToUpdate.add(dbTrack)
break
}
if (!isInDatabase) {
// Insert new sync. Let the db assign the id
track.id = null
trackToUpdate.add(track)
}
}
if (!isInDatabase) {
// Insert new sync. Let the db assign the id
track.id = null
trackToUpdate.add(track)
}
}
// Update database
@ -340,47 +323,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
}
}
/**
* Restore the chapters for manga if chapters already in database
*
* @param manga manga of chapters
* @param chapters list containing chapters that get restored
* @return boolean answering if chapter fetch is not needed
*/
internal fun restoreChaptersForManga(manga: Manga, chapters: List<Chapter>): Boolean {
val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
// Return if fetch is needed
if (dbChapters.isEmpty() || dbChapters.size < chapters.size) {
return false
}
chapters.forEach { chapter ->
val dbChapter = dbChapters.find { it.url == chapter.url }
if (dbChapter != null) {
chapter.id = dbChapter.id
chapter.copyFrom(dbChapter)
if (dbChapter.read && !chapter.read) {
chapter.read = dbChapter.read
chapter.last_page_read = dbChapter.last_page_read
} else if (chapter.last_page_read == 0 && dbChapter.last_page_read != 0) {
chapter.last_page_read = dbChapter.last_page_read
}
if (!chapter.bookmark && dbChapter.bookmark) {
chapter.bookmark = dbChapter.bookmark
}
}
chapter.manga_id = manga.id
}
// Filter the chapters that couldn't be found.
updateChapters(chapters.filter { it.id != null })
return true
}
internal fun restoreChaptersForMangaOffline(manga: Manga, chapters: List<Chapter>) {
internal fun restoreChaptersForManga(manga: Manga, chapters: List<Chapter>) {
val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
chapters.forEach { chapter ->

View File

@ -12,13 +12,12 @@ import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.source.Source
import okio.buffer
import okio.gzip
import okio.source
import java.util.Date
class FullBackupRestore(context: Context, notifier: BackupNotifier, private val online: Boolean) : AbstractBackupRestore<FullBackupManager>(context, notifier) {
class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<FullBackupManager>(context, notifier) {
override suspend fun performRestore(uri: Uri): Boolean {
backupManager = FullBackupManager(context)
@ -42,7 +41,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
return false
}
restoreManga(it, backup.backupCategories, online)
restoreManga(it, backup.backupCategories)
}
return true
@ -57,7 +56,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
}
private suspend fun restoreManga(backupManga: BackupManga, backupCategories: List<BackupCategory>, online: Boolean) {
private fun restoreManga(backupManga: BackupManga, backupCategories: List<BackupCategory>) {
val manga = backupManga.getMangaImpl()
val chapters = backupManga.getChaptersImpl()
val categories = backupManga.categories
@ -68,8 +67,8 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
try {
if (source != null || !online) {
restoreMangaData(manga, source, chapters, categories, history, tracks, backupCategories, online)
if (source != null) {
restoreMangaData(manga, chapters, categories, history, tracks, backupCategories)
} else {
errors.add(Date() to "${manga.title} [$sourceName]: ${context.getString(R.string.source_not_found_name, sourceName)}")
}
@ -85,33 +84,30 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
* 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
* @param tracks tracking data from json
*/
private suspend fun restoreMangaData(
private fun restoreMangaData(
manga: Manga,
source: Source?,
chapters: List<Chapter>,
categories: List<Int>,
history: List<BackupHistory>,
tracks: List<Track>,
backupCategories: List<BackupCategory>,
online: Boolean
backupCategories: List<BackupCategory>
) {
val dbManga = backupManager.getMangaFromDatabase(manga)
db.inTransaction {
val dbManga = backupManager.getMangaFromDatabase(manga)
if (dbManga == null) {
// Manga not in database
restoreMangaFetch(source, manga, chapters, categories, history, tracks, backupCategories, online)
} else { // Manga in database
restoreMangaFetch(manga, chapters, categories, history, tracks, backupCategories)
} else {
// Manga in database
// Copy information from manga already in database
backupManager.restoreMangaNoFetch(manga, dbManga)
// Fetch rest of manga information
restoreMangaNoFetch(source, manga, chapters, categories, history, tracks, backupCategories, online)
restoreMangaNoFetch(manga, chapters, categories, history, tracks, backupCategories)
}
}
}
@ -123,55 +119,37 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
* @param chapters chapters of manga that needs updating
* @param categories categories that need updating
*/
private suspend fun restoreMangaFetch(
source: Source?,
private fun restoreMangaFetch(
manga: Manga,
chapters: List<Chapter>,
categories: List<Int>,
history: List<BackupHistory>,
tracks: List<Track>,
backupCategories: List<BackupCategory>,
online: Boolean
backupCategories: List<BackupCategory>
) {
try {
val fetchedManga = backupManager.restoreMangaFetch(source, manga, online)
val fetchedManga = backupManager.restoreManga(manga)
fetchedManga.id ?: return
if (online && source != null) {
updateChapters(source, fetchedManga, chapters)
} else {
backupManager.restoreChaptersForMangaOffline(fetchedManga, chapters)
}
backupManager.restoreChaptersForManga(fetchedManga, chapters)
restoreExtraForManga(fetchedManga, categories, history, tracks, backupCategories)
updateTracking(fetchedManga, tracks)
} catch (e: Exception) {
errors.add(Date() to "${manga.title} - ${e.message}")
}
}
private suspend fun restoreMangaNoFetch(
source: Source?,
private fun restoreMangaNoFetch(
backupManga: Manga,
chapters: List<Chapter>,
categories: List<Int>,
history: List<BackupHistory>,
tracks: List<Track>,
backupCategories: List<BackupCategory>,
online: Boolean
backupCategories: List<BackupCategory>
) {
if (online && source != null) {
if (!backupManager.restoreChaptersForManga(backupManga, chapters)) {
updateChapters(source, backupManga, chapters)
}
} else {
backupManager.restoreChaptersForMangaOffline(backupManga, chapters)
}
backupManager.restoreChaptersForManga(backupManga, chapters)
restoreExtraForManga(backupManga, categories, history, tracks, backupCategories)
updateTracking(backupManga, tracks)
}
private fun restoreExtraForManga(manga: Manga, categories: List<Int>, history: List<BackupHistory>, tracks: List<Track>, backupCategories: List<BackupCategory>) {

View File

@ -15,7 +15,6 @@ import androidx.documentfile.provider.DocumentFile
import androidx.preference.PreferenceScreen
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.afollestad.materialdialogs.list.listItemsSingleChoice
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupConst
@ -206,31 +205,15 @@ class SettingsBackupController : SettingsController() {
val fileName = DocumentFile.fromSingleUri(activity, uri)?.name ?: uri.toString()
when {
fileName.endsWith(".proto.gz") -> {
val options = arrayOf(
R.string.full_restore_offline,
R.string.full_restore_online
)
.map { activity.getString(it) }
MaterialDialog(activity)
.title(R.string.full_restore_mode)
.listItemsSingleChoice(
items = options,
initialSelection = 0
) { _, index, _ ->
RestoreBackupDialog(
uri,
BackupConst.BACKUP_TYPE_FULL,
isOnline = index != 0
).showDialog(router)
}
.positiveButton(R.string.action_restore)
.show()
RestoreBackupDialog(
uri,
BackupConst.BACKUP_TYPE_FULL
).showDialog(router)
}
fileName.endsWith(".json") -> {
RestoreBackupDialog(
uri,
BackupConst.BACKUP_TYPE_LEGACY,
isOnline = true
BackupConst.BACKUP_TYPE_LEGACY
).showDialog(router)
}
else -> {
@ -326,11 +309,10 @@ class SettingsBackupController : SettingsController() {
}
class RestoreBackupDialog(bundle: Bundle? = null) : DialogController(bundle) {
constructor(uri: Uri, type: Int, isOnline: Boolean) : this(
constructor(uri: Uri, type: Int) : this(
bundleOf(
KEY_URI to uri,
KEY_TYPE to type,
KEY_MODE to isOnline
KEY_TYPE to type
)
)
@ -338,12 +320,19 @@ class SettingsBackupController : SettingsController() {
val activity = activity!!
val uri: Uri = args.getParcelable(KEY_URI)!!
val type: Int = args.getInt(KEY_TYPE)
val isOnline: Boolean = args.getBoolean(KEY_MODE, true)
return try {
var message = activity.getString(R.string.backup_restore_content)
var message = if (type == BackupConst.BACKUP_TYPE_FULL) {
activity.getString(R.string.backup_restore_content_full)
} else {
activity.getString(R.string.backup_restore_content)
}
val validator = if (type == BackupConst.BACKUP_TYPE_FULL) FullBackupRestoreValidator() else LegacyBackupRestoreValidator()
val validator = if (type == BackupConst.BACKUP_TYPE_FULL) {
FullBackupRestoreValidator()
} else {
LegacyBackupRestoreValidator()
}
val results = validator.validate(activity, uri)
if (results.missingSources.isNotEmpty()) {
@ -357,7 +346,7 @@ class SettingsBackupController : SettingsController() {
.title(R.string.pref_restore_backup)
.message(text = message)
.positiveButton(R.string.action_restore) {
BackupRestoreService.start(activity, uri, type, isOnline)
BackupRestoreService.start(activity, uri, type)
}
} catch (e: Exception) {
MaterialDialog(activity)
@ -370,7 +359,6 @@ class SettingsBackupController : SettingsController() {
private companion object {
const val KEY_URI = "RestoreBackupDialog.uri"
const val KEY_TYPE = "RestoreBackupDialog.type"
const val KEY_MODE = "RestoreBackupDialog.mode"
}
}

View File

@ -377,9 +377,6 @@
<string name="pref_backup_service_category">Automatic backups</string>
<string name="pref_backup_interval">Backup frequency</string>
<string name="pref_backup_slots">Maximum backups</string>
<string name="full_restore_mode">Network Mode</string>
<string name="full_restore_online">Restore online, much slower but gives you more updated info and chapters</string>
<string name="full_restore_offline">Restore offline, finishes quickly but contains only what your backup has</string>
<string name="source_not_found_name">Source not found: %1$s</string>
<string name="tracker_not_logged_in">Not logged in: %1$s</string>
<string name="backup_created">Backup created</string>
@ -390,6 +387,7 @@
<string name="backup_restore_missing_sources">Missing sources:</string>
<string name="backup_restore_missing_trackers">Trackers not logged into:</string>
<string name="backup_restore_content">Restore uses sources to fetch data, carrier costs may apply.\n\nMake sure you have installed all necessary extensions and are logged in to sources and tracking services before restoring.</string>
<string name="backup_restore_content_full">Data from the backup file will be restored.\n\nYou will need to install any missing extensions and log in to tracking services afterwards to use them.</string>
<string name="restore_completed">Restore completed</string>
<string name="restore_duration">%02d min, %02d sec</string>
<plurals name="restore_completed_message">