From 3d507600cb3ee456db128b6a0ad189c0f4387b07 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Thu, 11 Mar 2021 19:09:30 -0500 Subject: [PATCH] Experimental Backup Restore fix --- .../data/backup/AbstractBackupManager.kt | 22 ++--- .../data/backup/AbstractBackupRestore.kt | 5 +- .../data/backup/full/FullBackupManager.kt | 45 +++++------ .../data/backup/full/FullBackupRestore.kt | 81 ++++++++++++------- .../data/backup/legacy/LegacyBackupManager.kt | 21 +++-- .../data/backup/legacy/LegacyBackupRestore.kt | 53 +++++++----- 6 files changed, 130 insertions(+), 97 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt index 2c8c048bb..b8e9857c2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt @@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.toSChapter import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource @@ -33,6 +34,16 @@ abstract class AbstractBackupManager(protected val context: Context) { internal fun getMangaFromDatabase(manga: Manga): Manga? = databaseHelper.getManga(manga.url, manga.source).executeAsBlocking() + internal suspend fun getChapters(source: Source, manga: Manga /* SY --> */, throttleManager: EHentaiThrottleManager /* SY <-- */): List { + return if (source is EHentai) { + source.getChapterList(manga.toMangaInfo(), throttleManager::throttle) + .map { it.toSChapter() } + } else { + source.getChapterList(manga.toMangaInfo()) + .map { it.toSChapter() } + } + } + /** * Fetches chapter information. * @@ -41,16 +52,7 @@ abstract class AbstractBackupManager(protected val context: Context) { * @param chapters list of chapters in the backup * @return Updated manga chapters. */ - internal open suspend fun restoreChapters(source: Source, manga: Manga, chapters: List /* SY --> */, throttleManager: EHentaiThrottleManager /* SY <-- */): Pair, List> { - // SY --> - val fetchedChapters = if (source is EHentai) { - source.getChapterList(manga.toMangaInfo(), throttleManager::throttle) - .map { it.toSChapter() } - } else { - source.getChapterList(manga.toMangaInfo()) - .map { it.toSChapter() } - } - // SY <-- + internal open suspend fun restoreChapters(source: Source, manga: Manga, chapters: List, fetchedChapters: List): Pair, List> { val syncedChapters = syncChaptersWithSource(databaseHelper, fetchedChapters, manga, source) if (syncedChapters.first.isNotEmpty()) { chapters.forEach { it.manga_id = manga.id } 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 6a5ac9ad2..7e18945ea 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 @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.util.chapter.NoChaptersException import eu.kanade.tachiyomi.util.system.createFileInCacheDir import exh.eh.EHentaiThrottleManager @@ -69,9 +70,9 @@ abstract class AbstractBackupRestore(protected val co * @param manga manga that needs updating * @return Updated manga chapters. */ - internal suspend fun updateChapters(source: Source, manga: Manga, chapters: List): Pair, List> { + internal suspend fun updateChapters(source: Source, manga: Manga, chapters: List, fetchedChapters: List): Pair, List> { return try { - backupManager.restoreChapters(source, manga, chapters /* SY --> */, throttleManager /* SY <-- */) + backupManager.restoreChapters(source, manga, chapters, fetchedChapters) } catch (e: Exception) { // If there's any error, return empty update and continue. val errorMessage = if (e is NoChaptersException) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt index f2b419441..9ed3e937e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt @@ -29,11 +29,9 @@ 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 eu.kanade.tachiyomi.source.online.MetadataSource -import eu.kanade.tachiyomi.source.online.all.MergedSource import exh.metadata.metadata.base.getFlatMetadataForManga import exh.metadata.metadata.base.insertFlatMetadataAsync import exh.savedsearches.JsonSavedSearch @@ -47,6 +45,7 @@ import kotlinx.serialization.protobuf.ProtoBuf import okio.buffer import okio.gzip import okio.sink +import tachiyomi.source.model.MangaInfo import timber.log.Timber import kotlin.math.max @@ -241,20 +240,19 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { * @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 /* SY --> */ && source !is MergedSource /* SY <-- */) { - 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 restoreMangaFetch(manga: Manga, networkManga: MangaInfo) { + manga.apply { + copyFrom(networkManga.toSManga()) + favorite = manga.favorite + initialized = true + id = insertManga(manga) + } + } + + fun restoreMangaNoFetch(manga: Manga) { + manga.apply { + initialized = description != null + id = insertManga(this) } } @@ -499,21 +497,18 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { * @param backupMergedMangaReferences the list of backup manga references for the merged manga */ internal fun restoreMergedMangaReferencesForManga(manga: Manga, backupMergedMangaReferences: List) { + if (backupMergedMangaReferences.isEmpty()) return + // Get merged manga references from file and from db val dbMergedMangaReferences = databaseHelper.getMergedMangaReferences().executeAsBlocking() // Iterate over them backupMergedMangaReferences.forEach { backupMergedMangaReference -> // Used to know if the merged manga reference is already in the db - var found = false - for (dbMergedMangaReference in dbMergedMangaReferences) { - // If the backupMergedMangaReference is already in the db, assign the id to the file's backupMergedMangaReference - // and do nothing - if (backupMergedMangaReference.mergeUrl == dbMergedMangaReference.mergeUrl && backupMergedMangaReference.mangaUrl == dbMergedMangaReference.mangaUrl) { - found = true - break - } - } + // If the backupMergedMangaReference is already in the db, assign the id to the file's backupMergedMangaReference + // and do nothing + val found = dbMergedMangaReferences.any { backupMergedMangaReference.mergeUrl == it.mergeUrl && backupMergedMangaReference.mangaUrl == it.mangaUrl } + // If the backupMergedMangaReference isn't in the db, remove the id and insert a new backupMergedMangaReference // Store the inserted id in the backupMergedMangaReference if (!found) { 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 f2af3a24d..f22ce1007 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 @@ -15,6 +15,7 @@ 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.data.database.models.toMangaInfo import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.online.all.MergedSource import exh.EXHMigrations @@ -137,16 +138,14 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val ) { val dbManga = backupManager.getMangaFromDatabase(manga) - db.inTransaction { - if (dbManga == null) { - // Manga not in database - restoreMangaFetch(source, manga, chapters, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, online) - } 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, mergedMangaReferences, flatMetadata, online) - } + if (dbManga == null) { + // Manga not in database + restoreMangaFetch(source, manga, chapters, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, online) + } 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, mergedMangaReferences, flatMetadata, online) } } @@ -170,22 +169,36 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val online: Boolean ) { try { - val fetchedManga = backupManager.restoreMangaFetch(source, manga, online) - fetchedManga.id ?: return + val networkManga = if (online && source != null /* SY --> */ && source !is MergedSource /* SY <-- */) { + source.getMangaDetails(manga.toMangaInfo()) + } else null + val fetchedChapters = if (online && source != null && source !is MergedSource) { + backupManager.getChapters(source, manga, throttleManager) + } else null - if (online && source != null) { - // SY --> - if (source !is MergedSource) { - updateChapters(source, fetchedManga, chapters) + db.inTransaction { + if (networkManga != null) { + backupManager.restoreMangaFetch(manga, networkManga) + } else { + backupManager.restoreMangaNoFetch(manga) } - // SY <-- - } else { - backupManager.restoreChaptersForMangaOffline(fetchedManga, chapters) + + manga.id ?: return + + if (fetchedChapters != null && source != null) { + // SY --> + if (source !is MergedSource) { + updateChapters(source, manga, chapters, fetchedChapters) + } + // SY <-- + } else { + backupManager.restoreChaptersForMangaOffline(manga, chapters) + } + + restoreExtraForManga(manga, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata) } - restoreExtraForManga(fetchedManga, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata) - - updateTracking(fetchedManga, tracks) + updateTracking(manga, tracks) } catch (e: Exception) { errors.add(Date() to "${manga.title} - ${e.message}") } @@ -203,15 +216,23 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val flatMetadata: BackupFlatMetadata?, online: Boolean ) { - if (online && source != null) { - if (/* SY --> */ source !is MergedSource && /* SY <-- */ !backupManager.restoreChaptersForManga(backupManga, chapters)) { - updateChapters(source, backupManga, chapters) - } - } else { - backupManager.restoreChaptersForMangaOffline(backupManga, chapters) - } + val dbChapters = if (source !is MergedSource) backupManager.databaseHelper.getChapters(backupManga).executeAsBlocking() else emptyList() - restoreExtraForManga(backupManga, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata) + val fetchedChapters = if (online && source != null && source !is MergedSource && !(dbChapters.isNotEmpty() && dbChapters.size >= chapters.size)) { + backupManager.getChapters(source, backupManga, throttleManager) + } else null + + db.inTransaction { + if (fetchedChapters != null && source != null) { + if (/* SY --> */ source !is MergedSource && /* SY <-- */ !backupManager.restoreChaptersForManga(backupManga, chapters)) { + updateChapters(source, backupManga, chapters, fetchedChapters) + } + } else { + backupManager.restoreChaptersForMangaOffline(backupManga, chapters) + } + + restoreExtraForManga(backupManga, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata) + } updateTracking(backupManga, tracks) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt index 7b131fe15..7161a38c5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt @@ -48,19 +48,19 @@ import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.MangaImpl import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.TrackImpl -import eu.kanade.tachiyomi.data.database.models.toMangaInfo import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.all.MergedSource -import exh.eh.EHentaiThrottleManager import exh.merged.sql.models.MergedMangaReference import exh.savedsearches.JsonSavedSearch import exh.source.MERGED_SOURCE_ID import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import tachiyomi.source.model.MangaInfo import timber.log.Timber import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -278,13 +278,12 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab * @param manga manga that needs updating * @return Updated manga. */ - suspend fun fetchManga(source: Source, manga: Manga): Manga { - val networkManga = source.getMangaDetails(manga.toMangaInfo()) - return manga.also { - it.copyFrom(networkManga.toSManga()) - it.favorite = true - it.initialized = true - it.id = insertManga(manga) + fun fetchManga(networkManga: MangaInfo, manga: Manga) { + manga.apply { + copyFrom(networkManga.toSManga()) + favorite = true + initialized = true + id = insertManga(this) } } @@ -295,7 +294,7 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab * @param manga manga that needs updating * @return [Observable] that contains manga */ - override suspend fun restoreChapters(source: Source, manga: Manga, chapters: List, throttleManager: EHentaiThrottleManager): Pair, List> { + override suspend fun restoreChapters(source: Source, manga: Manga, chapters: List, fetchedChapters: List): Pair, List> { // SY --> return if (source is MergedSource) { val syncedChapters = source.fetchChaptersAndSync(manga, false) @@ -305,7 +304,7 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab updateChapters(syncedChapters.first) syncedChapters } else { - super.restoreChapters(source, manga, chapters, throttleManager) + super.restoreChapters(source, manga, chapters, fetchedChapters) } } 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 49d786c86..5e7734bf2 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 @@ -20,7 +20,9 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.MangaImpl import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.TrackImpl +import eu.kanade.tachiyomi.data.database.models.toMangaInfo import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.online.all.MergedSource import exh.EXHMigrations import java.util.Date @@ -154,16 +156,14 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract ) { val dbManga = backupManager.getMangaFromDatabase(manga) - db.inTransaction { - if (dbManga == null) { - // Manga not in database - restoreMangaFetch(source, manga, chapters, categories, history, tracks) - } 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) - } + if (dbManga == null) { + // Manga not in database + restoreMangaFetch(source, manga, chapters, categories, history, tracks) + } 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) } } @@ -183,14 +183,19 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract tracks: List ) { try { - val fetchedManga = backupManager.fetchManga(source, manga) - fetchedManga.id ?: return + val networkManga = source.getMangaDetails(manga.toMangaInfo()) + val fetchedChapters = if (source !is MergedSource) { + backupManager.getChapters(source, manga, throttleManager) + } else emptyList() + db.inTransaction { + backupManager.fetchManga(networkManga, manga) + manga.id ?: return - updateChapters(source, fetchedManga, chapters) + updateChapters(source, manga, chapters, fetchedChapters) - restoreExtraForManga(fetchedManga, categories, history, tracks) - - updateTracking(fetchedManga, tracks) + restoreExtraForManga(manga, categories, history, tracks) + } + updateTracking(manga, tracks) } catch (e: Exception) { errors.add(Date() to "${manga.title} - ${e.message}") } @@ -204,11 +209,21 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract history: List, tracks: List ) { - if (!backupManager.restoreChaptersForManga(backupManga, chapters)) { - updateChapters(source, backupManga, chapters) + val dbChapters = backupManager.databaseHelper.getChapters(backupManga).executeAsBlocking() + + val fetchedChapters = if (dbChapters.isNotEmpty() && dbChapters.size >= chapters.size) { + backupManager.getChapters(source, backupManga, throttleManager) + } else { + null } - restoreExtraForManga(backupManga, categories, history, tracks) + db.inTransaction { + if (!backupManager.restoreChaptersForManga(backupManga, chapters) && fetchedChapters != null) { + updateChapters(source, backupManga, chapters, fetchedChapters) + } + + restoreExtraForManga(backupManga, categories, history, tracks) + } updateTracking(backupManga, tracks) }