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 0827169d2..f211b7038 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 @@ -7,10 +7,14 @@ import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga 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.util.chapter.syncChaptersWithSource +import rx.Observable import uy.kohesive.injekt.injectLazy abstract class AbstractBackupManager(protected val context: Context) { + internal val databaseHelper: DatabaseHelper by injectLazy() internal val sourceManager: SourceManager by injectLazy() internal val trackManager: TrackManager by injectLazy() @@ -26,6 +30,25 @@ abstract class AbstractBackupManager(protected val context: Context) { internal fun getMangaFromDatabase(manga: Manga): Manga? = databaseHelper.getManga(manga.url, manga.source).executeAsBlocking() + /** + * [Observable] that fetches chapter information + * + * @param source source of manga + * @param manga manga that needs updating + * @param chapters list of chapters in the backup + * @return [Observable] that contains manga + */ + internal fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List): Observable, List>> { + return source.fetchChapterList(manga) + .map { syncChaptersWithSource(databaseHelper, it, manga, source) } + .doOnNext { pair -> + if (pair.first.isNotEmpty()) { + chapters.forEach { it.manga_id = manga.id } + updateChapters(chapters) + } + } + } + /** * Returns list containing manga from library * 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 0c3ff6d74..98860b8ee 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 @@ -2,20 +2,29 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context import android.net.Uri +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.DatabaseHelper +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.track.TrackManager +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.util.chapter.NoChaptersException import kotlinx.coroutines.Job +import rx.Observable import uy.kohesive.injekt.injectLazy import java.io.File import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -abstract class AbstractBackupRestore(protected val context: Context, protected val notifier: BackupNotifier) { - protected val db: DatabaseHelper by injectLazy() +abstract class AbstractBackupRestore(protected val context: Context, protected val notifier: BackupNotifier) { + protected val db: DatabaseHelper by injectLazy() protected val trackManager: TrackManager by injectLazy() + protected lateinit var backupManager: T + var job: Job? = null /** @@ -43,7 +52,7 @@ abstract class AbstractBackupRestore(protected val context: Context, protected v /** * Write errors to error log */ - fun writeErrorLog(): File { + internal fun writeErrorLog(): File { try { if (errors.isNotEmpty()) { val destFile = File(context.externalCacheDir, "tachiyomi_restore.txt") @@ -61,4 +70,64 @@ abstract class AbstractBackupRestore(protected val context: Context, protected v } return File("") } + + /** + * [Observable] that fetches chapter information + * + * @param source source of manga + * @param manga manga that needs updating + * @return [Observable] that contains manga + */ + internal fun chapterFetchObservable(source: Source, manga: Manga, chapters: List): Observable, List>> { + return backupManager.restoreChapterFetchObservable(source, manga, chapters) + // If there's any error, return empty update and continue. + .onErrorReturn { + val errorMessage = if (it is NoChaptersException) { + context.getString(R.string.no_chapters_error) + } else { + it.message + } + errors.add(Date() to "${manga.title} - $errorMessage") + Pair(emptyList(), emptyList()) + } + } + + /** + * [Observable] that refreshes tracking information + * @param manga manga that needs updating. + * @param tracks list containing tracks from restore file. + * @return [Observable] that contains updated track item + */ + internal fun trackingFetchObservable(manga: Manga, tracks: List): Observable { + return Observable.from(tracks) + .flatMap { track -> + val service = trackManager.getService(track.sync_id) + if (service != null && service.isLogged) { + service.refresh(track) + .doOnNext { db.insertTrack(it).executeAsBlocking() } + .onErrorReturn { + errors.add(Date() to "${manga.title} - ${it.message}") + track + } + } else { + errors.add(Date() to "${manga.title} - ${context.getString(R.string.tracker_not_logged_in, service?.name)}") + Observable.empty() + } + } + } + + /** + * Called to update dialog in [BackupConst] + * + * @param progress restore progress + * @param amount total restoreAmount of manga + * @param title title of restored manga + */ + internal fun showRestoreProgress( + progress: Int, + amount: Int, + title: String + ) { + notifier.showRestoreProgress(title, progress, amount) + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt index 249f5d7c8..3185b968a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt @@ -68,7 +68,7 @@ class BackupRestoreService : Service() { */ private lateinit var wakeLock: PowerManager.WakeLock - private var backupRestore: AbstractBackupRestore? = null + private var backupRestore: AbstractBackupRestore<*>? = null private lateinit var notifier: BackupNotifier override fun onCreate() { 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 6b1c0501c..8052e96c0 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 @@ -27,7 +27,6 @@ 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.source.Source -import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.protobuf.ProtoBuf import okio.buffer @@ -209,25 +208,6 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { } } - /** - * [Observable] that fetches chapter information - * - * @param source source of manga - * @param manga manga that needs updating - * @param chapters list of chapters in the backup - * @return [Observable] that contains manga - */ - fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List): Observable, List>> { - return source.fetchChapterList(manga) - .map { syncChaptersWithSource(databaseHelper, it, manga, source) } - .doOnNext { pair -> - if (pair.first.isNotEmpty()) { - chapters.forEach { it.manga_id = manga.id } - updateChapters(chapters) - } - } - } - /** * Restore the categories from Json * 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 6748e42e8..990e53f38 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 @@ -13,7 +13,6 @@ 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 eu.kanade.tachiyomi.util.chapter.NoChaptersException import kotlinx.serialization.ExperimentalSerializationApi import okio.buffer import okio.gzip @@ -22,8 +21,7 @@ import rx.Observable import java.util.Date @OptIn(ExperimentalSerializationApi::class) -class FullBackupRestore(context: Context, notifier: BackupNotifier, private val online: Boolean) : AbstractBackupRestore(context, notifier) { - private lateinit var fullBackupManager: FullBackupManager +class FullBackupRestore(context: Context, notifier: BackupNotifier, private val online: Boolean) : AbstractBackupRestore(context, notifier) { /** * Restores data from backup file. @@ -34,10 +32,10 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val val startTime = System.currentTimeMillis() // Initialize manager - fullBackupManager = FullBackupManager(context) + backupManager = FullBackupManager(context) val backupString = context.contentResolver.openInputStream(uri)!!.source().gzip().buffer().use { it.readByteArray() } - val backup = fullBackupManager.parser.decodeFromByteArray(BackupSerializer, backupString) + val backup = backupManager.parser.decodeFromByteArray(BackupSerializer, backupString) restoreAmount = backup.backupManga.size + 1 // +1 for categories restoreProgress = 0 @@ -71,7 +69,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val private fun restoreCategories(backupCategories: List) { db.inTransaction { - fullBackupManager.restoreCategories(backupCategories) + backupManager.restoreCategories(backupCategories) } restoreProgress += 1 @@ -86,7 +84,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val val tracks = backupManga.getTrackingImpl() try { - val source = fullBackupManager.sourceManager.get(manga.source) + val source = backupManager.sourceManager.get(manga.source) if (source != null || !online) { restoreMangaData(manga, source, chapters, categories, history, tracks, backupCategories, online) } else { @@ -121,7 +119,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val backupCategories: List, online: Boolean ) { - val dbManga = fullBackupManager.getMangaFromDatabase(manga) + val dbManga = backupManager.getMangaFromDatabase(manga) db.inTransaction { if (dbManga == null) { @@ -129,7 +127,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val restoreMangaFetch(source, manga, chapters, categories, history, tracks, backupCategories, online) } else { // Manga in database // Copy information from manga already in database - fullBackupManager.restoreMangaNoFetch(manga, dbManga) + backupManager.restoreMangaNoFetch(manga, dbManga) // Fetch rest of manga information restoreMangaNoFetch(source, manga, chapters, categories, history, tracks, backupCategories, online) } @@ -153,7 +151,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val backupCategories: List, online: Boolean ) { - fullBackupManager.restoreMangaFetchObservable(source, manga, online) + backupManager.restoreMangaFetchObservable(source, manga, online) .doOnError { errors.add(Date() to "${manga.title} - ${it.message}") } @@ -164,7 +162,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val // Convert to the manga that contains new chapters. .map { manga } } else { - fullBackupManager.restoreChaptersForMangaOffline(it, chapters) + backupManager.restoreChaptersForMangaOffline(it, chapters) Observable.just(manga) } } @@ -190,14 +188,14 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val Observable.just(backupManga) .flatMap { manga -> if (online && source != null) { - if (!fullBackupManager.restoreChaptersForManga(manga, chapters)) { + if (!backupManager.restoreChaptersForManga(manga, chapters)) { chapterFetchObservable(source, manga, chapters) .map { manga } } else { Observable.just(manga) } } else { - fullBackupManager.restoreChaptersForMangaOffline(manga, chapters) + backupManager.restoreChaptersForMangaOffline(manga, chapters) Observable.just(manga) } } @@ -212,72 +210,12 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val private fun restoreExtraForManga(manga: Manga, categories: List, history: List, tracks: List, backupCategories: List) { // Restore categories - fullBackupManager.restoreCategoriesForManga(manga, categories, backupCategories) + backupManager.restoreCategoriesForManga(manga, categories, backupCategories) // Restore history - fullBackupManager.restoreHistoryForManga(history) + backupManager.restoreHistoryForManga(history) // Restore tracking - fullBackupManager.restoreTrackForManga(manga, tracks) - } - - /** - * [Observable] that fetches chapter information - * - * @param source source of manga - * @param manga manga that needs updating - * @return [Observable] that contains manga - */ - private fun chapterFetchObservable(source: Source, manga: Manga, chapters: List): Observable, List>> { - return fullBackupManager.restoreChapterFetchObservable(source, manga, chapters) - // If there's any error, return empty update and continue. - .onErrorReturn { - val errorMessage = if (it is NoChaptersException) { - context.getString(R.string.no_chapters_error) - } else { - it.message - } - errors.add(Date() to "${manga.title} - $errorMessage") - Pair(emptyList(), emptyList()) - } - } - - /** - * [Observable] that refreshes tracking information - * @param manga manga that needs updating. - * @param tracks list containing tracks from restore file. - * @return [Observable] that contains updated track item - */ - private fun trackingFetchObservable(manga: Manga, tracks: List): Observable { - return Observable.from(tracks) - .flatMap { track -> - val service = trackManager.getService(track.sync_id) - if (service != null && service.isLogged) { - service.refresh(track) - .doOnNext { db.insertTrack(it).executeAsBlocking() } - .onErrorReturn { - errors.add(Date() to "${manga.title} - ${it.message}") - track - } - } else { - errors.add(Date() to "${manga.title} - ${context.getString(R.string.tracker_not_logged_in, service?.name)}") - Observable.empty() - } - } - } - - /** - * Called to update dialog in [BackupConst] - * - * @param progress restore progress - * @param amount total restoreAmount of manga - * @param title title of restored manga - */ - private fun showRestoreProgress( - progress: Int, - amount: Int, - title: String - ) { - notifier.showRestoreProgress(title, progress, amount) + backupManager.restoreTrackForManga(manga, 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 76eb73999..9107d6d39 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 @@ -46,16 +46,13 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.TrackImpl import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.Source -import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import rx.Observable import timber.log.Timber import kotlin.math.max class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : AbstractBackupManager(context) { - /** - * Version of parser - */ - var version: Int = version + + var parserVersion: Int = version private set var parser: Gson = initParser() @@ -66,11 +63,11 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab * @param version version of parser */ internal fun setVersion(version: Int) { - this.version = version + this.parserVersion = version parser = initParser() } - private fun initParser(): Gson = when (version) { + private fun initParser(): Gson = when (parserVersion) { 2 -> GsonBuilder() .registerTypeAdapter(MangaTypeAdapter.build()) @@ -269,24 +266,6 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab } } - /** - * [Observable] that fetches chapter information - * - * @param source source of manga - * @param manga manga that needs updating - * @return [Observable] that contains manga - */ - fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List): Observable, List>> { - return source.fetchChapterList(manga) - .map { syncChaptersWithSource(databaseHelper, it, manga, source) } - .doOnNext { pair -> - if (pair.first.isNotEmpty()) { - chapters.forEach { it.manga_id = manga.id } - updateChapters(chapters) - } - } - } - /** * Restore the categories from Json * 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 1aaabbd44..575f7d09b 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 @@ -10,7 +10,6 @@ import com.google.gson.JsonParser import com.google.gson.stream.JsonReader import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.AbstractBackupRestore -import eu.kanade.tachiyomi.data.backup.BackupConst import eu.kanade.tachiyomi.data.backup.BackupNotifier import eu.kanade.tachiyomi.data.backup.legacy.models.Backup import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.MANGAS @@ -22,13 +21,10 @@ 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.source.Source -import eu.kanade.tachiyomi.util.chapter.NoChaptersException import rx.Observable import java.util.Date -class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore(context, notifier) { - - private lateinit var backupManager: LegacyBackupManager +class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore(context, notifier) { /** * Restores data from backup file. @@ -229,64 +225,4 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract // Restore tracking backupManager.restoreTrackForManga(manga, tracks) } - - /** - * [Observable] that fetches chapter information - * - * @param source source of manga - * @param manga manga that needs updating - * @return [Observable] that contains manga - */ - private fun chapterFetchObservable(source: Source, manga: Manga, chapters: List): Observable, List>> { - return backupManager.restoreChapterFetchObservable(source, manga, chapters) - // If there's any error, return empty update and continue. - .onErrorReturn { - val errorMessage = if (it is NoChaptersException) { - context.getString(R.string.no_chapters_error) - } else { - it.message - } - errors.add(Date() to "${manga.title} - $errorMessage") - Pair(emptyList(), emptyList()) - } - } - - /** - * [Observable] that refreshes tracking information - * @param manga manga that needs updating. - * @param tracks list containing tracks from restore file. - * @return [Observable] that contains updated track item - */ - private fun trackingFetchObservable(manga: Manga, tracks: List): Observable { - return Observable.from(tracks) - .flatMap { track -> - val service = trackManager.getService(track.sync_id) - if (service != null && service.isLogged) { - service.refresh(track) - .doOnNext { db.insertTrack(it).executeAsBlocking() } - .onErrorReturn { - errors.add(Date() to "${manga.title} - ${it.message}") - track - } - } else { - errors.add(Date() to "${manga.title} - ${context.getString(R.string.tracker_not_logged_in, service?.name)}") - Observable.empty() - } - } - } - - /** - * Called to update dialog in [BackupConst] - * - * @param progress restore progress - * @param amount total restoreAmount of manga - * @param title title of restored manga - */ - private fun showRestoreProgress( - progress: Int, - amount: Int, - title: String - ) { - notifier.showRestoreProgress(title, progress, amount) - } }