diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index 927ea0dcf..6c2f20792 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -263,8 +263,9 @@ class MangaInfoScreenModel( if (chapters.isNotEmpty() && manga.isEhBasedManga() && DebugToggles.ENABLE_EXH_ROOT_REDIRECT.enabled) { // Check for gallery in library and accept manga with lowest id // Find chapters sharing same root - updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters) - .onEach { (acceptedChain, _) -> + launchIO { + try { + val (acceptedChain) = updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters) // Redirect if we are not the accepted root if (manga.id != acceptedChain.manga.id && acceptedChain.manga.favorite) { // Update if any of our chapters are not in accepted manga's chapters @@ -273,7 +274,10 @@ class MangaInfoScreenModel( EXHRedirect(acceptedChain.manga.id), ) } - }.launchIn(coroutineScope) + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) { "Error loading accepted chapter chain" } + } + } } } .combine( diff --git a/app/src/main/java/exh/eh/EHentaiUpdateHelper.kt b/app/src/main/java/exh/eh/EHentaiUpdateHelper.kt index dc60455d5..9d6835059 100644 --- a/app/src/main/java/exh/eh/EHentaiUpdateHelper.kt +++ b/app/src/main/java/exh/eh/EHentaiUpdateHelper.kt @@ -20,9 +20,6 @@ import eu.kanade.domain.manga.model.MangaUpdate import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.map import uy.kohesive.injekt.injectLazy import java.io.File @@ -50,111 +47,101 @@ class EHentaiUpdateHelper(context: Context) { * * @return Triple */ - fun findAcceptedRootAndDiscardOthers(sourceId: Long, chapters: List): Flow, Boolean>> { + suspend fun findAcceptedRootAndDiscardOthers(sourceId: Long, chapters: List): Triple, Boolean> { // Find other chains - val chainsFlow = flowOf(chapters) - .map { chapterList -> - chapterList.flatMap { chapter -> - getChapterByUrl.await(chapter.url).map { it.mangaId } - }.distinct() + val chains = chapters + .flatMap { chapter -> + getChapterByUrl.await(chapter.url).map { it.mangaId } } - .map { mangaIds -> - mangaIds - .mapNotNull { mangaId -> - coroutineScope { - val manga = async(Dispatchers.IO) { - getManga.await(mangaId) - } - val chapterList = async(Dispatchers.IO) { - getChapterByMangaId.await(mangaId) - } - val history = async(Dispatchers.IO) { - getHistoryByMangaId.await(mangaId) - } - ChapterChain( - manga.await() ?: return@coroutineScope null, - chapterList.await(), - history.await(), - ) - } + .distinct() + .mapNotNull { mangaId -> + coroutineScope { + val manga = async(Dispatchers.IO) { + getManga.await(mangaId) } - .filter { it.manga.source == sourceId } + val chapterList = async(Dispatchers.IO) { + getChapterByMangaId.await(mangaId) + } + val history = async(Dispatchers.IO) { + getHistoryByMangaId.await(mangaId) + } + ChapterChain( + manga.await() ?: return@coroutineScope null, + chapterList.await(), + history.await(), + ) + } } + .filter { it.manga.source == sourceId } // Accept oldest chain - val chainsWithAccepted = chainsFlow.map { chains -> - val acceptedChain = chains.minBy { it.manga.id } + val accepted = chains.minBy { it.manga.id } - acceptedChain to chains - } + val toDiscard = chains.filter { it.manga.favorite && it.manga.id != accepted.manga.id } + val mangaUpdates = mutableListOf() - return chainsWithAccepted.map { (accepted, chains) -> - val toDiscard = chains.filter { it.manga.favorite && it.manga.id != accepted.manga.id } - val mangaUpdates = mutableListOf() + val chainsAsChapters = chains.flatMap { it.chapters } + val chainsAsHistory = chains.flatMap { it.history } - val chainsAsChapters = chains.flatMap { it.chapters } - val chainsAsHistory = chains.flatMap { it.history } + return if (toDiscard.isNotEmpty()) { + // Copy chain chapters to curChapters + val (chapterUpdates, newChapters, new) = getChapterList(accepted, toDiscard, chainsAsChapters) - if (toDiscard.isNotEmpty()) { - // Copy chain chapters to curChapters - val (chapterUpdates, newChapters, new) = getChapterList(accepted, toDiscard, chainsAsChapters) - - toDiscard.forEach { - mangaUpdates += MangaUpdate( - id = it.manga.id, - favorite = false, - dateAdded = 0, - ) - } - if (!accepted.manga.favorite) { - mangaUpdates += MangaUpdate( - id = accepted.manga.id, - favorite = true, - dateAdded = System.currentTimeMillis(), - ) - } - - val newAccepted = ChapterChain(accepted.manga, newChapters, emptyList()) - val rootsToMutate = toDiscard + newAccepted - - // Apply changes to all manga - updateManga.awaitAll(mangaUpdates) - // Insert new chapters for accepted manga - chapterRepository.updateAll(chapterUpdates) - chapterRepository.addAll(newChapters) - - val (newHistory, deleteHistory) = getHistory(getChapterByMangaId.await(accepted.manga.id), chainsAsChapters, chainsAsHistory) - - // Delete the duplicate history first - deleteHistory.forEach { - removeHistory.awaitById(it) - } - - // Insert new history - newHistory.forEach { - upsertHistory.await(it) - } - - // Copy categories from all chains to accepted manga - - val newCategories = rootsToMutate.flatMap { chapterChain -> - getCategories.await(chapterChain.manga.id).map { it.id } - }.distinct() - rootsToMutate.forEach { - setMangaCategories.await(it.manga.id, newCategories) - } - - Triple(newAccepted, toDiscard, new) - } else { - /*val notNeeded = chains.filter { it.manga.id != accepted.manga.id } - val (newChapters, new) = getChapterList(accepted, notNeeded, chainsAsChapters) - val newAccepted = ChapterChain(accepted.manga, newChapters) - - // Insert new chapters for accepted manga - db.insertChapters(newAccepted.chapters).await()*/ - - Triple(accepted, emptyList(), false) + toDiscard.forEach { + mangaUpdates += MangaUpdate( + id = it.manga.id, + favorite = false, + dateAdded = 0, + ) } + if (!accepted.manga.favorite) { + mangaUpdates += MangaUpdate( + id = accepted.manga.id, + favorite = true, + dateAdded = System.currentTimeMillis(), + ) + } + + val newAccepted = ChapterChain(accepted.manga, newChapters, emptyList()) + val rootsToMutate = toDiscard + newAccepted + + // Apply changes to all manga + updateManga.awaitAll(mangaUpdates) + // Insert new chapters for accepted manga + chapterRepository.updateAll(chapterUpdates) + chapterRepository.addAll(newChapters) + + val (newHistory, deleteHistory) = getHistory(getChapterByMangaId.await(accepted.manga.id), chainsAsChapters, chainsAsHistory) + + // Delete the duplicate history first + deleteHistory.forEach { + removeHistory.awaitById(it) + } + + // Insert new history + newHistory.forEach { + upsertHistory.await(it) + } + + // Copy categories from all chains to accepted manga + + val newCategories = rootsToMutate.flatMap { chapterChain -> + getCategories.await(chapterChain.manga.id).map { it.id } + }.distinct() + rootsToMutate.forEach { + setMangaCategories.await(it.manga.id, newCategories) + } + + Triple(newAccepted, toDiscard, new) + } else { + /*val notNeeded = chains.filter { it.manga.id != accepted.manga.id } + val (newChapters, new) = getChapterList(accepted, notNeeded, chainsAsChapters) + val newAccepted = ChapterChain(accepted.manga, newChapters) + + // Insert new chapters for accepted manga + db.insertChapters(newAccepted.chapters).await()*/ + + Triple(accepted, emptyList(), false) } } diff --git a/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt b/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt index df4624970..dca8d1fa8 100644 --- a/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt +++ b/app/src/main/java/exh/eh/EHentaiUpdateWorker.kt @@ -33,7 +33,6 @@ import exh.metadata.metadata.EHentaiSearchMetadata import exh.util.cancellable import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.mapNotNull -import kotlinx.coroutines.flow.single import kotlinx.coroutines.flow.toList import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -165,7 +164,7 @@ class EHentaiUpdateWorker(private val context: Context, workerParams: WorkerPara // Find accepted root and discard others val (acceptedRoot, discardedRoots, hasNew) = - updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters).single() + updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters) if ((new.isNotEmpty() && manga.id == acceptedRoot.manga.id) || (hasNew && updatedManga.none { it.first.id == acceptedRoot.manga.id })