Experimental Backup Restore fix

This commit is contained in:
Jobobby04 2021-03-11 19:09:30 -05:00
parent 84abe044a3
commit 3d507600cb
6 changed files with 130 additions and 97 deletions

View File

@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager 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.model.toSChapter
import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
@ -33,6 +34,16 @@ abstract class AbstractBackupManager(protected val context: Context) {
internal fun getMangaFromDatabase(manga: Manga): Manga? = internal fun getMangaFromDatabase(manga: Manga): Manga? =
databaseHelper.getManga(manga.url, manga.source).executeAsBlocking() databaseHelper.getManga(manga.url, manga.source).executeAsBlocking()
internal suspend fun getChapters(source: Source, manga: Manga /* SY --> */, throttleManager: EHentaiThrottleManager /* SY <-- */): List<SChapter> {
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. * Fetches chapter information.
* *
@ -41,16 +52,7 @@ abstract class AbstractBackupManager(protected val context: Context) {
* @param chapters list of chapters in the backup * @param chapters list of chapters in the backup
* @return Updated manga chapters. * @return Updated manga chapters.
*/ */
internal open suspend fun restoreChapters(source: Source, manga: Manga, chapters: List<Chapter> /* SY --> */, throttleManager: EHentaiThrottleManager /* SY <-- */): Pair<List<Chapter>, List<Chapter>> { internal open suspend fun restoreChapters(source: Source, manga: Manga, chapters: List<Chapter>, fetchedChapters: List<SChapter>): Pair<List<Chapter>, List<Chapter>> {
// 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 <--
val syncedChapters = syncChaptersWithSource(databaseHelper, fetchedChapters, manga, source) val syncedChapters = syncChaptersWithSource(databaseHelper, fetchedChapters, manga, source)
if (syncedChapters.first.isNotEmpty()) { if (syncedChapters.first.isNotEmpty()) {
chapters.forEach { it.manga_id = manga.id } chapters.forEach { it.manga_id = manga.id }

View File

@ -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.database.models.Track
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.Source 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.chapter.NoChaptersException
import eu.kanade.tachiyomi.util.system.createFileInCacheDir import eu.kanade.tachiyomi.util.system.createFileInCacheDir
import exh.eh.EHentaiThrottleManager import exh.eh.EHentaiThrottleManager
@ -69,9 +70,9 @@ abstract class AbstractBackupRestore<T : AbstractBackupManager>(protected val co
* @param manga manga that needs updating * @param manga manga that needs updating
* @return Updated manga chapters. * @return Updated manga chapters.
*/ */
internal suspend fun updateChapters(source: Source, manga: Manga, chapters: List<Chapter>): Pair<List<Chapter>, List<Chapter>> { internal suspend fun updateChapters(source: Source, manga: Manga, chapters: List<Chapter>, fetchedChapters: List<SChapter>): Pair<List<Chapter>, List<Chapter>> {
return try { return try {
backupManager.restoreChapters(source, manga, chapters /* SY --> */, throttleManager /* SY <-- */) backupManager.restoreChapters(source, manga, chapters, fetchedChapters)
} catch (e: Exception) { } catch (e: Exception) {
// If there's any error, return empty update and continue. // If there's any error, return empty update and continue.
val errorMessage = if (e is NoChaptersException) { val errorMessage = if (e is NoChaptersException) {

View File

@ -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.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.Track 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.Source
import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.model.toSManga
import eu.kanade.tachiyomi.source.online.MetadataSource 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.getFlatMetadataForManga
import exh.metadata.metadata.base.insertFlatMetadataAsync import exh.metadata.metadata.base.insertFlatMetadataAsync
import exh.savedsearches.JsonSavedSearch import exh.savedsearches.JsonSavedSearch
@ -47,6 +45,7 @@ import kotlinx.serialization.protobuf.ProtoBuf
import okio.buffer import okio.buffer
import okio.gzip import okio.gzip
import okio.sink import okio.sink
import tachiyomi.source.model.MangaInfo
import timber.log.Timber import timber.log.Timber
import kotlin.math.max import kotlin.math.max
@ -241,20 +240,19 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
* @param manga manga that needs updating * @param manga manga that needs updating
* @return Updated manga info. * @return Updated manga info.
*/ */
suspend fun restoreMangaFetch(source: Source?, manga: Manga, online: Boolean): Manga { fun restoreMangaFetch(manga: Manga, networkManga: MangaInfo) {
return if (online && source != null /* SY --> */ && source !is MergedSource /* SY <-- */) { manga.apply {
val networkManga = source.getMangaDetails(manga.toMangaInfo()) copyFrom(networkManga.toSManga())
manga.also { favorite = manga.favorite
it.copyFrom(networkManga.toSManga()) initialized = true
it.favorite = manga.favorite id = insertManga(manga)
it.initialized = true }
it.id = insertManga(manga) }
}
} else { fun restoreMangaNoFetch(manga: Manga) {
manga.also { manga.apply {
it.initialized = it.description != null initialized = description != null
it.id = insertManga(it) 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 * @param backupMergedMangaReferences the list of backup manga references for the merged manga
*/ */
internal fun restoreMergedMangaReferencesForManga(manga: Manga, backupMergedMangaReferences: List<BackupMergedMangaReference>) { internal fun restoreMergedMangaReferencesForManga(manga: Manga, backupMergedMangaReferences: List<BackupMergedMangaReference>) {
if (backupMergedMangaReferences.isEmpty()) return
// Get merged manga references from file and from db // Get merged manga references from file and from db
val dbMergedMangaReferences = databaseHelper.getMergedMangaReferences().executeAsBlocking() val dbMergedMangaReferences = databaseHelper.getMergedMangaReferences().executeAsBlocking()
// Iterate over them // Iterate over them
backupMergedMangaReferences.forEach { backupMergedMangaReference -> backupMergedMangaReferences.forEach { backupMergedMangaReference ->
// Used to know if the merged manga reference is already in the db // Used to know if the merged manga reference is already in the db
var found = false // If the backupMergedMangaReference is already in the db, assign the id to the file's backupMergedMangaReference
for (dbMergedMangaReference in dbMergedMangaReferences) { // and do nothing
// If the backupMergedMangaReference is already in the db, assign the id to the file's backupMergedMangaReference val found = dbMergedMangaReferences.any { backupMergedMangaReference.mergeUrl == it.mergeUrl && backupMergedMangaReference.mangaUrl == it.mangaUrl }
// and do nothing
if (backupMergedMangaReference.mergeUrl == dbMergedMangaReference.mergeUrl && backupMergedMangaReference.mangaUrl == dbMergedMangaReference.mangaUrl) {
found = true
break
}
}
// If the backupMergedMangaReference isn't in the db, remove the id and insert a new backupMergedMangaReference // If the backupMergedMangaReference isn't in the db, remove the id and insert a new backupMergedMangaReference
// Store the inserted id in the backupMergedMangaReference // Store the inserted id in the backupMergedMangaReference
if (!found) { if (!found) {

View File

@ -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.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.Track 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.Source
import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.source.online.all.MergedSource
import exh.EXHMigrations import exh.EXHMigrations
@ -137,16 +138,14 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
) { ) {
val dbManga = backupManager.getMangaFromDatabase(manga) val dbManga = backupManager.getMangaFromDatabase(manga)
db.inTransaction { if (dbManga == null) {
if (dbManga == null) { // Manga not in database
// Manga not in database restoreMangaFetch(source, manga, chapters, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, online)
restoreMangaFetch(source, manga, chapters, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, online) } else { // Manga in database
} else { // Manga in database // Copy information from manga already in database
// Copy information from manga already in database backupManager.restoreMangaNoFetch(manga, dbManga)
backupManager.restoreMangaNoFetch(manga, dbManga) // Fetch rest of manga information
// Fetch rest of manga information restoreMangaNoFetch(source, manga, chapters, categories, history, tracks, backupCategories, mergedMangaReferences, flatMetadata, online)
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 online: Boolean
) { ) {
try { try {
val fetchedManga = backupManager.restoreMangaFetch(source, manga, online) val networkManga = if (online && source != null /* SY --> */ && source !is MergedSource /* SY <-- */) {
fetchedManga.id ?: return 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) { db.inTransaction {
// SY --> if (networkManga != null) {
if (source !is MergedSource) { backupManager.restoreMangaFetch(manga, networkManga)
updateChapters(source, fetchedManga, chapters) } else {
backupManager.restoreMangaNoFetch(manga)
} }
// SY <--
} else { manga.id ?: return
backupManager.restoreChaptersForMangaOffline(fetchedManga, chapters)
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(manga, tracks)
updateTracking(fetchedManga, tracks)
} catch (e: Exception) { } catch (e: Exception) {
errors.add(Date() to "${manga.title} - ${e.message}") errors.add(Date() to "${manga.title} - ${e.message}")
} }
@ -203,15 +216,23 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
flatMetadata: BackupFlatMetadata?, flatMetadata: BackupFlatMetadata?,
online: Boolean online: Boolean
) { ) {
if (online && source != null) { val dbChapters = if (source !is MergedSource) backupManager.databaseHelper.getChapters(backupManga).executeAsBlocking() else emptyList()
if (/* SY --> */ source !is MergedSource && /* SY <-- */ !backupManager.restoreChaptersForManga(backupManga, chapters)) {
updateChapters(source, backupManga, chapters)
}
} else {
backupManager.restoreChaptersForMangaOffline(backupManga, chapters)
}
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) updateTracking(backupManga, tracks)
} }

View File

@ -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.MangaImpl
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl 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.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.Source 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.model.toSManga
import eu.kanade.tachiyomi.source.online.all.MergedSource import eu.kanade.tachiyomi.source.online.all.MergedSource
import exh.eh.EHentaiThrottleManager
import exh.merged.sql.models.MergedMangaReference import exh.merged.sql.models.MergedMangaReference
import exh.savedsearches.JsonSavedSearch import exh.savedsearches.JsonSavedSearch
import exh.source.MERGED_SOURCE_ID import exh.source.MERGED_SOURCE_ID
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import tachiyomi.source.model.MangaInfo
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get 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 * @param manga manga that needs updating
* @return Updated manga. * @return Updated manga.
*/ */
suspend fun fetchManga(source: Source, manga: Manga): Manga { fun fetchManga(networkManga: MangaInfo, manga: Manga) {
val networkManga = source.getMangaDetails(manga.toMangaInfo()) manga.apply {
return manga.also { copyFrom(networkManga.toSManga())
it.copyFrom(networkManga.toSManga()) favorite = true
it.favorite = true initialized = true
it.initialized = true id = insertManga(this)
it.id = insertManga(manga)
} }
} }
@ -295,7 +294,7 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab
* @param manga manga that needs updating * @param manga manga that needs updating
* @return [Observable] that contains manga * @return [Observable] that contains manga
*/ */
override suspend fun restoreChapters(source: Source, manga: Manga, chapters: List<Chapter>, throttleManager: EHentaiThrottleManager): Pair<List<Chapter>, List<Chapter>> { override suspend fun restoreChapters(source: Source, manga: Manga, chapters: List<Chapter>, fetchedChapters: List<SChapter>): Pair<List<Chapter>, List<Chapter>> {
// SY --> // SY -->
return if (source is MergedSource) { return if (source is MergedSource) {
val syncedChapters = source.fetchChaptersAndSync(manga, false) val syncedChapters = source.fetchChaptersAndSync(manga, false)
@ -305,7 +304,7 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab
updateChapters(syncedChapters.first) updateChapters(syncedChapters.first)
syncedChapters syncedChapters
} else { } else {
super.restoreChapters(source, manga, chapters, throttleManager) super.restoreChapters(source, manga, chapters, fetchedChapters)
} }
} }

View File

@ -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.MangaImpl
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.TrackImpl 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.Source
import eu.kanade.tachiyomi.source.online.all.MergedSource
import exh.EXHMigrations import exh.EXHMigrations
import java.util.Date import java.util.Date
@ -154,16 +156,14 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract
) { ) {
val dbManga = backupManager.getMangaFromDatabase(manga) val dbManga = backupManager.getMangaFromDatabase(manga)
db.inTransaction { if (dbManga == null) {
if (dbManga == null) { // Manga not in database
// Manga not in database restoreMangaFetch(source, manga, chapters, categories, history, tracks)
restoreMangaFetch(source, manga, chapters, categories, history, tracks) } else { // Manga in database
} else { // Manga in database // Copy information from manga already in database
// Copy information from manga already in database backupManager.restoreMangaNoFetch(manga, dbManga)
backupManager.restoreMangaNoFetch(manga, dbManga) // Fetch rest of manga information
// Fetch rest of manga information restoreMangaNoFetch(source, manga, chapters, categories, history, tracks)
restoreMangaNoFetch(source, manga, chapters, categories, history, tracks)
}
} }
} }
@ -183,14 +183,19 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract
tracks: List<Track> tracks: List<Track>
) { ) {
try { try {
val fetchedManga = backupManager.fetchManga(source, manga) val networkManga = source.getMangaDetails(manga.toMangaInfo())
fetchedManga.id ?: return 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) restoreExtraForManga(manga, categories, history, tracks)
}
updateTracking(fetchedManga, tracks) updateTracking(manga, tracks)
} catch (e: Exception) { } catch (e: Exception) {
errors.add(Date() to "${manga.title} - ${e.message}") errors.add(Date() to "${manga.title} - ${e.message}")
} }
@ -204,11 +209,21 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract
history: List<DHistory>, history: List<DHistory>,
tracks: List<Track> tracks: List<Track>
) { ) {
if (!backupManager.restoreChaptersForManga(backupManga, chapters)) { val dbChapters = backupManager.databaseHelper.getChapters(backupManga).executeAsBlocking()
updateChapters(source, backupManga, chapters)
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) updateTracking(backupManga, tracks)
} }