diff --git a/app/src/main/java/exh/GalleryAdder.kt b/app/src/main/java/exh/GalleryAdder.kt index c71544736..c59712cdb 100755 --- a/app/src/main/java/exh/GalleryAdder.kt +++ b/app/src/main/java/exh/GalleryAdder.kt @@ -16,7 +16,7 @@ import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import exh.log.xLogStack import exh.source.getMainSource -import exh.util.executeOnIO +import exh.util.maybeRunBlocking import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy @@ -53,7 +53,8 @@ class GalleryAdder { url: String, fav: Boolean = false, forceSource: UrlImportableSource? = null, - throttleFunc: suspend () -> Unit = {} + throttleFunc: suspend () -> Unit = {}, + protectTrans: Boolean = false ): GalleryAddEvent { logger.d(context.getString(R.string.gallery_adder_importing_manga, url, fav.toString(), forceSource)) try { @@ -118,7 +119,7 @@ class GalleryAdder { } ?: return GalleryAddEvent.Fail.UnknownType(url, context) // Use manga in DB if possible, otherwise, make a new manga - val manga = db.getManga(cleanedMangaUrl, source.id).executeOnIO() + val manga = db.getManga(cleanedMangaUrl, source.id).executeAsBlocking() ?: Manga.create(source.id).apply { this.url = cleanedMangaUrl title = realMangaUrl @@ -146,14 +147,16 @@ class GalleryAdder { // Fetch and copy chapters try { - val chapterList = if (source is EHentai) { - source.getChapterList(manga.toMangaInfo(), throttleFunc) - } else { - source.getChapterList(manga.toMangaInfo()) - }.map { it.toSChapter() } + maybeRunBlocking(protectTrans) { + val chapterList = if (source is EHentai) { + source.getChapterList(manga.toMangaInfo(), throttleFunc) + } else { + source.getChapterList(manga.toMangaInfo()) + }.map { it.toSChapter() } - if (chapterList.isNotEmpty()) { - syncChaptersWithSource(db, chapterList, manga, source) + if (chapterList.isNotEmpty()) { + syncChaptersWithSource(db, chapterList, manga, source) + } } } catch (e: Exception) { logger.w(context.getString(R.string.gallery_adder_chapter_fetch_error, manga.title), e) @@ -161,7 +164,7 @@ class GalleryAdder { } return if (cleanedChapterUrl != null) { - val chapter = db.getChapter(cleanedChapterUrl, manga.id!!).executeOnIO() + val chapter = db.getChapter(cleanedChapterUrl, manga.id!!).executeAsBlocking() if (chapter != null) { GalleryAddEvent.Success(url, manga, context, chapter) } else { diff --git a/app/src/main/java/exh/favorites/FavoritesSyncHelper.kt b/app/src/main/java/exh/favorites/FavoritesSyncHelper.kt index 662dde8fe..7b6ff3732 100644 --- a/app/src/main/java/exh/favorites/FavoritesSyncHelper.kt +++ b/app/src/main/java/exh/favorites/FavoritesSyncHelper.kt @@ -14,6 +14,7 @@ import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.util.lang.launchUI +import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.system.powerManager import eu.kanade.tachiyomi.util.system.toast import exh.GalleryAddEvent @@ -24,7 +25,6 @@ import exh.log.xLog import exh.source.EH_SOURCE_ID import exh.source.EXH_SOURCE_ID import exh.source.isEhBasedManga -import exh.util.executeOnIO import exh.util.ignore import exh.util.trans import exh.util.wifiManager @@ -85,13 +85,13 @@ class FavoritesSyncHelper(val context: Context) { // Validate library state status.value = FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_verifying_library), context = context) - val libraryManga = db.getLibraryMangas().executeOnIO() + val libraryManga = db.getLibraryMangas().executeAsBlocking() val seenManga = HashSet(libraryManga.size) libraryManga.forEach { if (!it.isEhBasedManga()) return@forEach if (it.id in seenManga) { - val inCategories = db.getCategoriesForManga(it).executeOnIO() + val inCategories = db.getCategoriesForManga(it).executeAsBlocking() status.value = FavoritesSyncStatus.BadLibraryState.MangaInMultipleCategories(it, inCategories, context) logger.w(context.getString(R.string.favorites_sync_manga_multiple_categories_error, it.id)) @@ -194,8 +194,8 @@ class FavoritesSyncHelper(val context: Context) { } } - private suspend fun applyRemoteCategories(categories: List) { - val localCategories = db.getCategories().executeOnIO() + private fun applyRemoteCategories(categories: List) { + val localCategories = db.getCategories().executeAsBlocking() val newLocalCategories = localCategories.toMutableList() @@ -233,7 +233,7 @@ class FavoritesSyncHelper(val context: Context) { // Only insert categories if changed if (changed) { - db.insertCategories(newLocalCategories).executeOnIO() + db.insertCategories(newLocalCategories).executeAsBlocking() } } @@ -267,7 +267,7 @@ class FavoritesSyncHelper(val context: Context) { for (i in 1..retryCount) { try { - val resp = exh.client.newCall(request).await() + val resp = withIOContext { exh.client.newCall(request).await() } if (resp.isSuccessful) { success = true @@ -340,7 +340,7 @@ class FavoritesSyncHelper(val context: Context) { db.getManga(url, EXH_SOURCE_ID), db.getManga(url, EH_SOURCE_ID) ).forEach { - val manga = it.executeOnIO() + val manga = it.executeAsBlocking() if (manga?.favorite == true) { manga.favorite = false @@ -357,7 +357,7 @@ class FavoritesSyncHelper(val context: Context) { } val insertedMangaCategories = mutableListOf>() - val categories = db.getCategories().executeOnIO() + val categories = db.getCategories().executeAsBlocking() // Apply additions throttleManager.resetThrottle() @@ -376,7 +376,8 @@ class FavoritesSyncHelper(val context: Context) { "${exh.baseUrl}${it.getUrl()}", true, exh, - throttleManager::throttle + throttleManager::throttle, + true ) if (result is GalleryAddEvent.Fail) { diff --git a/app/src/main/java/exh/favorites/LocalFavoritesStorage.kt b/app/src/main/java/exh/favorites/LocalFavoritesStorage.kt index c7a255595..34d1b9857 100644 --- a/app/src/main/java/exh/favorites/LocalFavoritesStorage.kt +++ b/app/src/main/java/exh/favorites/LocalFavoritesStorage.kt @@ -5,7 +5,6 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.source.online.all.EHentai import exh.metadata.metadata.EHentaiSearchMetadata import exh.source.isEhBasedManga -import exh.util.executeOnIO import io.realm.Realm import io.realm.RealmConfiguration import uy.kohesive.injekt.injectLazy @@ -20,13 +19,13 @@ class LocalFavoritesStorage { fun getRealm(): Realm = Realm.getInstance(realmConfig) - suspend fun getChangedDbEntries(realm: Realm) = + fun getChangedDbEntries(realm: Realm) = getChangedEntries( realm, parseToFavoriteEntries( loadDbCategories( db.getFavoriteMangas() - .executeOnIO() + .executeAsBlocking() .asSequence() ) ) @@ -45,11 +44,11 @@ class LocalFavoritesStorage { ) ) - suspend fun snapshotEntries(realm: Realm) { + fun snapshotEntries(realm: Realm) { val dbMangas = parseToFavoriteEntries( loadDbCategories( db.getFavoriteMangas() - .executeOnIO() + .executeAsBlocking() .asSequence() ) ) @@ -97,8 +96,8 @@ class LocalFavoritesStorage { it.category == entry.category } - private suspend fun loadDbCategories(manga: Sequence): Sequence> { - val dbCategories = db.getCategories().executeOnIO() + private fun loadDbCategories(manga: Sequence): Sequence> { + val dbCategories = db.getCategories().executeAsBlocking() return manga.filter(this::validateDbManga).mapNotNull { val category = db.getCategoriesForManga(it).executeAsBlocking() diff --git a/app/src/main/java/exh/util/CoroutineUtil.kt b/app/src/main/java/exh/util/CoroutineUtil.kt index 5ba733aa8..0daa273f0 100644 --- a/app/src/main/java/exh/util/CoroutineUtil.kt +++ b/app/src/main/java/exh/util/CoroutineUtil.kt @@ -3,8 +3,25 @@ package exh.util import kotlinx.coroutines.ensureActive import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.runBlocking +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.coroutines.coroutineContext fun Flow.cancellable() = onEach { coroutineContext.ensureActive() } + +@Suppress("BlockingMethodInNonBlockingContext") +@OptIn(ExperimentalContracts::class) +suspend inline fun maybeRunBlocking(runBlocking: Boolean, crossinline block: suspend () -> T): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return if (runBlocking) { + runBlocking { block() } + } else { + block() + } +}