瀏覽代碼

Remove usage of RxJava from backup/restore

arkon 4 年之前
父節點
當前提交
990fb22d3e

+ 11 - 16
app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt

@@ -12,8 +12,6 @@ import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.source.model.toSChapter
 import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
-import eu.kanade.tachiyomi.util.lang.runAsObservable
-import rx.Observable
 import uy.kohesive.injekt.injectLazy
 
 abstract class AbstractBackupManager(protected val context: Context) {
@@ -34,25 +32,22 @@ abstract class AbstractBackupManager(protected val context: Context) {
         databaseHelper.getManga(manga.url, manga.source).executeAsBlocking()
 
     /**
-     * [Observable] that fetches chapter information
+     * 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
+     * @return Updated manga chapters.
      */
-    internal fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>): Observable<Pair<List<Chapter>, List<Chapter>>> {
-        return runAsObservable({
-            source.getChapterList(manga.toMangaInfo())
-                .map { it.toSChapter() }
-        })
-            .map { syncChaptersWithSource(databaseHelper, it, manga, source) }
-            .doOnNext { (first) ->
-                if (first.isNotEmpty()) {
-                    chapters.forEach { it.manga_id = manga.id }
-                    updateChapters(chapters)
-                }
-            }
+    internal suspend fun restoreChapters(source: Source, manga: Manga, chapters: List<Chapter>): Pair<List<Chapter>, List<Chapter>> {
+        val fetchedChapters = source.getChapterList(manga.toMangaInfo())
+            .map { it.toSChapter() }
+        val syncedChapters = syncChaptersWithSource(databaseHelper, fetchedChapters, manga, source)
+        if (syncedChapters.first.isNotEmpty()) {
+            chapters.forEach { it.manga_id = manga.id }
+            updateChapters(chapters)
+        }
+        return syncedChapters
     }
 
     /**

+ 28 - 30
app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt

@@ -10,9 +10,8 @@ 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 eu.kanade.tachiyomi.util.lang.runAsObservable
+import eu.kanade.tachiyomi.util.lang.await
 import kotlinx.coroutines.Job
-import rx.Observable
 import uy.kohesive.injekt.injectLazy
 import java.io.File
 import java.text.SimpleDateFormat
@@ -59,48 +58,47 @@ abstract class AbstractBackupRestore<T : AbstractBackupManager>(protected val co
     }
 
     /**
-     * [Observable] that fetches chapter information
+     * Fetches chapter information.
      *
      * @param source source of manga
      * @param manga manga that needs updating
-     * @return [Observable] that contains manga
+     * @return Updated manga chapters.
      */
-    internal fun chapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>): Observable<Pair<List<Chapter>, List<Chapter>>> {
-        return backupManager.restoreChapterFetchObservable(source, manga, chapters)
+    internal suspend fun updateChapters(source: Source, manga: Manga, chapters: List<Chapter>): Pair<List<Chapter>, List<Chapter>> {
+        return try {
+            backupManager.restoreChapters(source, manga, chapters)
+        } catch (e: Exception) {
             // 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())
+            val errorMessage = if (e is NoChaptersException) {
+                context.getString(R.string.no_chapters_error)
+            } else {
+                e.message
             }
+            errors.add(Date() to "${manga.title} - $errorMessage")
+            Pair(emptyList(), emptyList())
+        }
     }
 
     /**
-     * [Observable] that refreshes tracking information
+     * 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<Track>): Observable<Track> {
-        return Observable.from(tracks)
-            .flatMap { track ->
-                val service = trackManager.getService(track.sync_id)
-                if (service != null && service.isLogged) {
-                    runAsObservable({ 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()
+    internal suspend fun updateTracking(manga: Manga, tracks: List<Track>) {
+        tracks.forEach { track ->
+            val service = trackManager.getService(track.sync_id)
+            if (service != null && service.isLogged) {
+                try {
+                    val updatedTrack = service.refresh(track)
+                    db.insertTrack(updatedTrack).await()
+                } catch (e: Exception) {
+                    errors.add(Date() to "${manga.title} - ${e.message}")
                 }
+            } else {
+                errors.add(Date() to "${manga.title} - ${context.getString(R.string.tracker_not_logged_in, service?.name)}")
             }
+        }
     }
 
     /**

+ 14 - 19
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt

@@ -29,13 +29,11 @@ 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.util.lang.runAsObservable
 import kotlinx.serialization.ExperimentalSerializationApi
 import kotlinx.serialization.protobuf.ProtoBuf
 import okio.buffer
 import okio.gzip
 import okio.sink
-import rx.Observable
 import timber.log.Timber
 import kotlin.math.max
 
@@ -185,29 +183,26 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
     }
 
     /**
-     * [Observable] that fetches manga information
+     * Fetches manga information
      *
      * @param source source of manga
      * @param manga manga that needs updating
-     * @return [Observable] that contains manga
+     * @return Updated manga info.
      */
-    fun restoreMangaFetchObservable(source: Source?, manga: Manga, online: Boolean): Observable<Manga> {
+    suspend fun restoreMangaFetch(source: Source?, manga: Manga, online: Boolean): Manga {
         return if (online && source != null) {
-            return runAsObservable({
-                val networkManga = source.getMangaDetails(manga.toMangaInfo())
-                manga.copyFrom(networkManga.toSManga())
-                manga.favorite = manga.favorite
-                manga.initialized = true
-                manga.id = insertManga(manga)
-                manga
-            })
+            val networkManga = source.getMangaDetails(manga.toMangaInfo())
+            manga.also {
+                it.copyFrom(networkManga.toSManga())
+                it.favorite = manga.favorite
+                it.initialized = true
+                it.id = insertManga(manga)
+            }
         } else {
-            Observable.just(manga)
-                .map {
-                    it.initialized = it.description != null
-                    it.id = insertManga(it)
-                    it
-                }
+            manga.also {
+                it.initialized = it.description != null
+                it.id = insertManga(it)
+            }
         }
     }
 

+ 27 - 39
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt

@@ -13,11 +13,11 @@ 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.lang.launchIO
 import kotlinx.serialization.ExperimentalSerializationApi
 import okio.buffer
 import okio.gzip
 import okio.source
-import rx.Observable
 import java.util.Date
 
 @OptIn(ExperimentalSerializationApi::class)
@@ -120,7 +120,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
     }
 
     /**
-     * [Observable] that fetches manga information
+     * Fetches manga information
      *
      * @param manga manga that needs updating
      * @param chapters chapters of manga that needs updating
@@ -136,28 +136,24 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
         backupCategories: List<BackupCategory>,
         online: Boolean
     ) {
-        backupManager.restoreMangaFetchObservable(source, manga, online)
-            .doOnError {
-                errors.add(Date() to "${manga.title} - ${it.message}")
-            }
-            .filter { it.id != null }
-            .flatMap {
+        launchIO {
+            try {
+                val fetchedManga = backupManager.restoreMangaFetch(source, manga, online)
+                fetchedManga.id ?: (return@launchIO)
+
                 if (online && source != null) {
-                    chapterFetchObservable(source, it, chapters)
-                        // Convert to the manga that contains new chapters.
-                        .map { manga }
+                    updateChapters(source, fetchedManga, chapters)
                 } else {
-                    backupManager.restoreChaptersForMangaOffline(it, chapters)
-                    Observable.just(manga)
+                    backupManager.restoreChaptersForMangaOffline(fetchedManga, chapters)
                 }
+
+                restoreExtraForManga(fetchedManga, categories, history, tracks, backupCategories)
+
+                updateTracking(fetchedManga, tracks)
+            } catch (e: Exception) {
+                errors.add(Date() to "${manga.title} - ${e.message}")
             }
-            .doOnNext {
-                restoreExtraForManga(it, categories, history, tracks, backupCategories)
-            }
-            .flatMap {
-                trackingFetchObservable(it, tracks)
-            }
-            .subscribe()
+        }
     }
 
     private fun restoreMangaNoFetch(
@@ -170,27 +166,19 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier, private val
         backupCategories: List<BackupCategory>,
         online: Boolean
     ) {
-        Observable.just(backupManga)
-            .flatMap { manga ->
-                if (online && source != null) {
-                    if (!backupManager.restoreChaptersForManga(manga, chapters)) {
-                        chapterFetchObservable(source, manga, chapters)
-                            .map { manga }
-                    } else {
-                        Observable.just(manga)
-                    }
-                } else {
-                    backupManager.restoreChaptersForMangaOffline(manga, chapters)
-                    Observable.just(manga)
+        launchIO {
+            if (online && source != null) {
+                if (!backupManager.restoreChaptersForManga(backupManga, chapters)) {
+                    updateChapters(source, backupManga, chapters)
                 }
+            } else {
+                backupManager.restoreChaptersForMangaOffline(backupManga, chapters)
             }
-            .doOnNext {
-                restoreExtraForManga(it, categories, history, tracks, backupCategories)
-            }
-            .flatMap { manga ->
-                trackingFetchObservable(manga, tracks)
-            }
-            .subscribe()
+
+            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>) {

+ 10 - 13
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt

@@ -48,8 +48,6 @@ import eu.kanade.tachiyomi.data.database.models.toMangaInfo
 import eu.kanade.tachiyomi.source.LocalSource
 import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.source.model.toSManga
-import eu.kanade.tachiyomi.util.lang.runAsObservable
-import rx.Observable
 import timber.log.Timber
 import kotlin.math.max
 
@@ -252,21 +250,20 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab
     }
 
     /**
-     * [Observable] that fetches manga information
+     * Fetches manga information
      *
      * @param source source of manga
      * @param manga manga that needs updating
-     * @return [Observable] that contains manga
+     * @return Updated manga.
      */
-    fun restoreMangaFetchObservable(source: Source, manga: Manga): Observable<Manga> {
-        return runAsObservable({
-            val networkManga = source.getMangaDetails(manga.toMangaInfo())
-            manga.copyFrom(networkManga.toSManga())
-            manga.favorite = true
-            manga.initialized = true
-            manga.id = insertManga(manga)
-            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)
+        }
     }
 
     /**

+ 23 - 34
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt

@@ -21,7 +21,7 @@ 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 rx.Observable
+import eu.kanade.tachiyomi.util.lang.launchIO
 import java.util.Date
 
 class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<LegacyBackupManager>(context, notifier) {
@@ -137,7 +137,7 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract
     }
 
     /**
-     * [Observable] that fetches manga information
+     * Fetches manga information.
      *
      * @param manga manga that needs updating
      * @param chapters chapters of manga that needs updating
@@ -151,24 +151,20 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract
         history: List<DHistory>,
         tracks: List<Track>
     ) {
-        backupManager.restoreMangaFetchObservable(source, manga)
-            .onErrorReturn {
-                errors.add(Date() to "${manga.title} - ${it.message}")
-                manga
-            }
-            .filter { it.id != null }
-            .flatMap {
-                chapterFetchObservable(source, it, chapters)
-                    // Convert to the manga that contains new chapters.
-                    .map { manga }
-            }
-            .doOnNext {
-                restoreExtraForManga(it, categories, history, tracks)
-            }
-            .flatMap {
-                trackingFetchObservable(it, tracks)
+        launchIO {
+            try {
+                val fetchedManga = backupManager.fetchManga(source, manga)
+                fetchedManga.id ?: (return@launchIO)
+
+                updateChapters(source, fetchedManga, chapters)
+
+                restoreExtraForManga(fetchedManga, categories, history, tracks)
+
+                updateTracking(fetchedManga, tracks)
+            } catch (e: Exception) {
+                errors.add(Date() to "${manga.title} - ${e.message}")
             }
-            .subscribe()
+        }
     }
 
     private fun restoreMangaNoFetch(
@@ -179,22 +175,15 @@ class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : Abstract
         history: List<DHistory>,
         tracks: List<Track>
     ) {
-        Observable.just(backupManga)
-            .flatMap { manga ->
-                if (!backupManager.restoreChaptersForManga(manga, chapters)) {
-                    chapterFetchObservable(source, manga, chapters)
-                        .map { manga }
-                } else {
-                    Observable.just(manga)
-                }
-            }
-            .doOnNext {
-                restoreExtraForManga(it, categories, history, tracks)
-            }
-            .flatMap { manga ->
-                trackingFetchObservable(manga, tracks)
+        launchIO {
+            if (!backupManager.restoreChaptersForManga(backupManga, chapters)) {
+                updateChapters(source, backupManga, chapters)
             }
-            .subscribe()
+
+            restoreExtraForManga(backupManga, categories, history, tracks)
+
+            updateTracking(backupManga, tracks)
+        }
     }
 
     private fun restoreExtraForManga(manga: Manga, categories: List<String>, history: List<DHistory>, tracks: List<Track>) {

+ 2 - 2
app/src/test/java/eu/kanade/tachiyomi/data/backup/BackupTest.kt

@@ -211,7 +211,7 @@ class BackupTest {
         networkManga.description = "This is a description"
         `when`(source.fetchMangaDetails(jsonManga)).thenReturn(Observable.just(networkManga))
 
-        val obs = legacyBackupManager.restoreMangaFetchObservable(source, jsonManga)
+        val obs = legacyBackupManager.fetchManga(source, jsonManga)
         val testSubscriber = TestSubscriber<Manga>()
         obs.subscribe(testSubscriber)
 
@@ -255,7 +255,7 @@ class BackupTest {
         `when`(source.fetchChapterList(manga)).thenReturn(Observable.just(chaptersRemote))
 
         // Call restoreChapterFetchObservable
-        val obs = legacyBackupManager.restoreChapterFetchObservable(source, manga, restoredChapters)
+        val obs = legacyBackupManager.restoreChapters(source, manga, restoredChapters)
         val testSubscriber = TestSubscriber<Pair<List<Chapter>, List<Chapter>>>()
         obs.subscribe(testSubscriber)