diff --git a/CHANGELOG.md b/CHANGELOG.md index e3479b197..9b5c6fbd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co - Add markdown support for manga descriptions ([@Secozzi](https://github.com/Secozzi)) ([#1948](https://github.com/mihonapp/mihon/pull/1948)) - Add Nord Theme ([@Riztard](https://github.com/Riztard)) ([#1951](https://github.com/mihonapp/mihon/pull/1951)) +### Improved +- Significantly improve browsing speed (near instantaneous) ([@AntsyLich](https://github.com/AntsyLich)) ([#1946](https://github.com/mihonapp/mihon/pull/1946)) + ### Fixes - Fix Bangumi search results including novels ([@MajorTanya](https://github.com/MajorTanya)) ([#1885](https://github.com/mihonapp/mihon/pull/1885)) - Fix next chapter button occasionally jumping to the last page of the current chapter ([@perokhe](https://github.com/perokhe)) ([#1920](https://github.com/mihonapp/mihon/pull/1920)) diff --git a/app/src/main/java/eu/kanade/domain/manga/interactor/SmartSearchMerge.kt b/app/src/main/java/eu/kanade/domain/manga/interactor/SmartSearchMerge.kt index e2f8be4ee..b66092ede 100644 --- a/app/src/main/java/eu/kanade/domain/manga/interactor/SmartSearchMerge.kt +++ b/app/src/main/java/eu/kanade/domain/manga/interactor/SmartSearchMerge.kt @@ -121,7 +121,7 @@ class SmartSearchMerge( existingManga = getManga.await(mergedManga.url, mergedManga.source) } - mergedManga = networkToLocalManga.await(mergedManga) + mergedManga = networkToLocalManga(mergedManga) getCategories.await(originalMangaId) .let { categories -> diff --git a/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt b/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt index d91598d37..1ef35cc8a 100644 --- a/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt +++ b/app/src/main/java/eu/kanade/domain/manga/model/Manga.kt @@ -76,24 +76,6 @@ fun Manga.copyFrom(other: SManga): Manga { ) } -fun SManga.toDomainManga(sourceId: Long): Manga { - return Manga.create().copy( - url = url, - // SY --> - ogTitle = title, - ogArtist = artist, - ogAuthor = author, - ogThumbnailUrl = thumbnail_url, - ogDescription = description, - ogGenre = getGenres(), - ogStatus = status.toLong(), - // SY <-- - updateStrategy = update_strategy, - initialized = initialized, - source = sourceId, - ) -} - fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean { return coverCache.getCustomCoverFile(id).exists() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt index d4d602f8b..10c56c093 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt @@ -568,7 +568,7 @@ class LibraryUpdateJob(private val context: Context, private val workerParams: W var dbManga = getManga.await(networkManga.url, mangaDex.id) if (dbManga == null) { - dbManga = networkToLocalManga.await( + dbManga = networkToLocalManga( Manga.create().copy( url = networkManga.url, ogTitle = networkManga.title, diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt index 81b66ae18..e812ca48a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt @@ -166,7 +166,7 @@ class MergedSource : HttpSource() { var manga = getManga.await(mangaUrl, mangaSourceId) val source = sourceManager.getOrStub(manga?.source ?: mangaSourceId) if (manga == null) { - val newManga = networkToLocalManga.await( + val newManga = networkToLocalManga( Manga.create().copy( source = mangaSourceId, url = mangaUrl, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedScreenModel.kt index 15fd3e179..aff6f8acd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedScreenModel.kt @@ -8,7 +8,6 @@ import androidx.compose.runtime.produceState import androidx.compose.ui.util.fastAny import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.browse.FeedItemUI import eu.kanade.tachiyomi.source.CatalogueSource @@ -32,6 +31,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json +import mihon.domain.manga.model.toDomainManga import tachiyomi.core.common.util.lang.launchIO import tachiyomi.core.common.util.lang.launchNonCancellable import tachiyomi.core.common.util.lang.withIOContext @@ -302,7 +302,7 @@ open class FeedScreenModel( val result = withIOContext { itemUI.copy( results = page.map { - networkToLocalManga.await(it.toDomainManga(itemUI.source!!.id)) + networkToLocalManga(it.toDomainManga(itemUI.source!!.id)) } // KMK --> .filter { !hideInLibraryFeedItems.get() || !it.favorite }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListScreenModel.kt index bf7384d28..dfed10d3c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListScreenModel.kt @@ -235,7 +235,7 @@ class MigrationListScreenModel( if (searchResult != null && !(searchResult.url == mangaObj.url && source.id == mangaObj.source) ) { - val localManga = networkToLocalManga.await(searchResult) + val localManga = networkToLocalManga(searchResult) val chapters = if (source is EHentai) { source.getChapterList(localManga.toSManga(), throttleManager::throttle) @@ -273,7 +273,7 @@ class MigrationListScreenModel( } if (searchResult != null) { - val localManga = networkToLocalManga.await(searchResult) + val localManga = networkToLocalManga(searchResult) val chapters = try { if (source is EHentai) { source.getChapterList(localManga.toSManga(), throttleManager::throttle) @@ -514,7 +514,7 @@ class MigrationListScreenModel( screenModelScope.launchIO { val result = migratingManga.migrationScope.async { val manga = getManga(newMangaId)!! - val localManga = networkToLocalManga.await(manga) + val localManga = networkToLocalManga(manga) try { val source = sourceManager.get(manga.source)!! val chapters = source.getChapterList(localManga.toSManga()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index 14b022efc..f51288666 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -16,7 +16,6 @@ import cafe.adriel.voyager.core.model.screenModelScope import dev.icerock.moko.resources.StringResource import eu.kanade.core.preference.asState import eu.kanade.domain.manga.interactor.UpdateManga -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.interactor.GetExhSavedSearch import eu.kanade.domain.source.interactor.GetIncognitoState import eu.kanade.domain.source.service.SourcePreferences @@ -39,7 +38,6 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.emptyFlow -import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf @@ -66,7 +64,6 @@ import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga import tachiyomi.domain.manga.interactor.GetFlatMetadataById import tachiyomi.domain.manga.interactor.GetManga -import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.toMangaUpdate import tachiyomi.domain.source.interactor.DeleteSavedSearchById @@ -74,7 +71,7 @@ import tachiyomi.domain.source.interactor.GetRemoteManga import tachiyomi.domain.source.interactor.InsertSavedSearch import tachiyomi.domain.source.model.EXHSavedSearch import tachiyomi.domain.source.model.SavedSearch -import tachiyomi.domain.source.repository.SourcePagingSourceType +import tachiyomi.domain.source.repository.SourcePagingSource import tachiyomi.domain.source.service.SourceManager import tachiyomi.i18n.sy.SYMR import uy.kohesive.injekt.Injekt @@ -100,7 +97,6 @@ open class BrowseSourceScreenModel( private val setMangaCategories: SetMangaCategories = Injekt.get(), private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(), private val getManga: GetManga = Injekt.get(), - private val networkToLocalManga: NetworkToLocalManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val addTracks: AddTracks = Injekt.get(), private val getIncognitoState: GetIncognitoState = Injekt.get(), @@ -207,10 +203,9 @@ open class BrowseSourceScreenModel( createSourcePagingSource(listing.query ?: "", listing.filters) // SY <-- }.flow.map { pagingData -> - pagingData.map { (it, metadata) -> - networkToLocalManga.await(it.toDomainManga(sourceId)) - .let { localManga -> getManga.subscribe(localManga.url, localManga.source) } - .filterNotNull() + pagingData.map { (manga, metadata) -> + getManga.subscribe(manga.url, manga.source) + .map { it ?: manga } // SY --> .combineMetadata(metadata) // SY <-- @@ -422,8 +417,8 @@ open class BrowseSourceScreenModel( } // SY --> - open fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType { - return getRemoteManga.subscribe(sourceId, query, filters) + open fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSource { + return getRemoteManga(sourceId, query, filters) } // SY <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedScreenModel.kt index 37d8ba975..f8f8be0b9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedScreenModel.kt @@ -9,7 +9,6 @@ import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import dev.icerock.moko.resources.StringResource import eu.kanade.core.preference.asState -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.interactor.GetExhSavedSearch import eu.kanade.domain.ui.UiPreferences import eu.kanade.presentation.browse.SourceFeedUI @@ -34,6 +33,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json +import mihon.domain.manga.model.toDomainManga import tachiyomi.core.common.util.lang.launchIO import tachiyomi.core.common.util.lang.launchNonCancellable import tachiyomi.core.common.util.lang.withIOContext @@ -212,7 +212,7 @@ open class SourceFeedScreenModel( val titles = withIOContext { page.map { - networkToLocalManga.await(it.toDomainManga(source.id)) + networkToLocalManga(it.toDomainManga(source.id)) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index f2246b47c..7819527a1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -5,7 +5,6 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.produceState import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.tachiyomi.extension.ExtensionManager @@ -25,6 +24,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import mihon.domain.manga.model.toDomainManga import tachiyomi.core.common.preference.toggle import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga @@ -186,9 +186,8 @@ abstract class SearchScreenModel( source.getSearchManga(1, query, source.getFilterList()) } - val titles = page.mangas.map { - networkToLocalManga.await(it.toDomainManga(source.id)) - } + val titles = page.mangas.map { it.toDomainManga(source.id) } + .let { networkToLocalManga(it) } if (isActive) { updateItem(source, SearchItemResult.Success(titles)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt index 5bef14675..8c71e414c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/deeplink/DeepLinkScreenModel.kt @@ -4,18 +4,16 @@ import androidx.compose.runtime.Immutable import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.manga.model.toSManga import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.model.SChapter -import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.ResolvableSource import eu.kanade.tachiyomi.source.online.UriType import kotlinx.coroutines.flow.update +import mihon.domain.manga.model.toDomainManga import tachiyomi.core.common.util.lang.launchIO import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId import tachiyomi.domain.chapter.model.Chapter -import tachiyomi.domain.manga.interactor.GetMangaByUrlAndSourceId import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager @@ -27,7 +25,6 @@ class DeepLinkScreenModel( private val sourceManager: SourceManager = Injekt.get(), private val networkToLocalManga: NetworkToLocalManga = Injekt.get(), private val getChapterByUrlAndMangaId: GetChapterByUrlAndMangaId = Injekt.get(), - private val getMangaByUrlAndSourceId: GetMangaByUrlAndSourceId = Injekt.get(), private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), ) : StateScreenModel(State.Loading) { @@ -38,7 +35,7 @@ class DeepLinkScreenModel( .firstOrNull { it.getUriType(query) != UriType.Unknown } val manga = source?.getManga(query)?.let { - getMangaFromSManga(it, source.id) + networkToLocalManga(it.toDomainManga(source.id)) } val chapter = if (source?.getUriType(query) == UriType.Chapter && manga != null) { @@ -73,11 +70,6 @@ class DeepLinkScreenModel( } } - private suspend fun getMangaFromSManga(sManga: SManga, sourceId: Long): Manga { - return getMangaByUrlAndSourceId.await(sManga.url, sourceId) - ?: networkToLocalManga.await(sManga.toDomainManga(sourceId)) - } - sealed interface State { @Immutable data object Loading : State 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 17be57192..7e5089d0e 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 @@ -35,7 +35,6 @@ import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.PagePreview import eu.kanade.domain.manga.model.chaptersFiltered import eu.kanade.domain.manga.model.downloadedFilter -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.domain.manga.model.toSManga import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.track.interactor.AddTracks @@ -105,6 +104,7 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import logcat.LogPriority import mihon.domain.chapter.interactor.FilterChaptersForDownload +import mihon.domain.manga.model.toDomainManga import tachiyomi.core.common.i18n.stringResource import tachiyomi.core.common.preference.CheckboxState import tachiyomi.core.common.preference.TriState @@ -1152,7 +1152,7 @@ class MangaScreenModel( /* Push found related mangas into collection */ val relatedManga = RelatedManga.Success.fromPair(pair) { mangaList -> mangaList.map { - networkToLocalManga.await(it.toDomainManga(state.source.id)) + networkToLocalManga(it.toDomainManga(state.source.id)) } } diff --git a/app/src/main/java/exh/GalleryAdder.kt b/app/src/main/java/exh/GalleryAdder.kt index 1f035ecb5..f9927a43c 100644 --- a/app/src/main/java/exh/GalleryAdder.kt +++ b/app/src/main/java/exh/GalleryAdder.kt @@ -136,7 +136,7 @@ class GalleryAdder( // Use manga in DB if possible, otherwise, make a new manga var manga = getManga.await(cleanedMangaUrl, source.id) - ?: networkToLocalManga.await( + ?: networkToLocalManga( Manga.create().copy( source = source.id, url = cleanedMangaUrl, diff --git a/app/src/main/java/exh/favorites/LocalFavoritesStorage.kt b/app/src/main/java/exh/favorites/LocalFavoritesStorage.kt index 652e39980..d7d655d44 100644 --- a/app/src/main/java/exh/favorites/LocalFavoritesStorage.kt +++ b/app/src/main/java/exh/favorites/LocalFavoritesStorage.kt @@ -1,6 +1,5 @@ package exh.favorites -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.tachiyomi.source.online.all.EHentai import exh.metadata.metadata.EHentaiSearchMetadata import exh.source.EXH_SOURCE_ID @@ -11,6 +10,7 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.toList +import mihon.domain.manga.model.toDomainManga import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.model.Category import tachiyomi.domain.manga.interactor.DeleteFavoriteEntries diff --git a/app/src/main/java/exh/md/follows/MangaDexFollowsPagingSource.kt b/app/src/main/java/exh/md/follows/MangaDexFollowsPagingSource.kt index dc8e6c501..0c6ca0670 100644 --- a/app/src/main/java/exh/md/follows/MangaDexFollowsPagingSource.kt +++ b/app/src/main/java/exh/md/follows/MangaDexFollowsPagingSource.kt @@ -2,12 +2,12 @@ package exh.md.follows import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.online.all.MangaDex -import tachiyomi.data.source.SourcePagingSource +import tachiyomi.data.source.BaseSourcePagingSource /** * LatestUpdatesPager inherited from the general Pager. */ -class MangaDexFollowsPagingSource(val mangadex: MangaDex) : SourcePagingSource(mangadex) { +class MangaDexFollowsPagingSource(val mangadex: MangaDex) : BaseSourcePagingSource(mangadex) { override suspend fun requestNextPage(currentPage: Int): MangasPage { return mangadex.fetchFollows(currentPage) diff --git a/app/src/main/java/exh/md/follows/MangaDexFollowsScreenModel.kt b/app/src/main/java/exh/md/follows/MangaDexFollowsScreenModel.kt index 65c9594eb..230ab3bab 100644 --- a/app/src/main/java/exh/md/follows/MangaDexFollowsScreenModel.kt +++ b/app/src/main/java/exh/md/follows/MangaDexFollowsScreenModel.kt @@ -9,11 +9,11 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.update import tachiyomi.domain.manga.model.Manga -import tachiyomi.domain.source.repository.SourcePagingSourceType +import tachiyomi.domain.source.repository.SourcePagingSource class MangaDexFollowsScreenModel(sourceId: Long) : BrowseSourceScreenModel(sourceId, null) { - override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType { + override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSource { return MangaDexFollowsPagingSource(source.getMainSource() as MangaDex) } diff --git a/app/src/main/java/exh/recs/RecommendsScreenModel.kt b/app/src/main/java/exh/recs/RecommendsScreenModel.kt index 6fafd8ddb..5259d1574 100644 --- a/app/src/main/java/exh/recs/RecommendsScreenModel.kt +++ b/app/src/main/java/exh/recs/RecommendsScreenModel.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.produceState import cafe.adriel.voyager.core.model.StateScreenModel -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.presentation.util.ioCoroutineScope import exh.recs.sources.RecommendationPagingSource import exh.recs.sources.SourceCatalogue @@ -22,6 +21,7 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import mihon.domain.manga.model.toDomainManga import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.model.Manga @@ -81,7 +81,7 @@ open class RecommendsScreenModel( val recSourceId = recSource.associatedSourceId if (recSourceId != null) { // If the recommendation is associated with a source, resolve it - networkToLocalManga.await(it.toDomainManga(recSourceId)) + networkToLocalManga(it.toDomainManga(recSourceId)) } else { // Otherwise, skip this step. The user will be prompted to choose a source via SmartSearch it.toDomainManga(RECOMMENDS_SOURCE) diff --git a/app/src/main/java/exh/recs/sources/RecommendationPagingSource.kt b/app/src/main/java/exh/recs/sources/RecommendationPagingSource.kt index 2bbed8000..742022f79 100644 --- a/app/src/main/java/exh/recs/sources/RecommendationPagingSource.kt +++ b/app/src/main/java/exh/recs/sources/RecommendationPagingSource.kt @@ -14,8 +14,8 @@ import exh.source.isMdBasedSource import kotlinx.serialization.json.Json import logcat.LogPriority import tachiyomi.core.common.util.system.logcat +import tachiyomi.data.source.BaseSourcePagingSource import tachiyomi.data.source.NoResultsException -import tachiyomi.data.source.SourcePagingSource import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.track.interactor.GetTracks @@ -29,7 +29,7 @@ import uy.kohesive.injekt.injectLazy abstract class RecommendationPagingSource( source: CatalogueSource?, protected val manga: Manga, -) : SourcePagingSource(source) { +) : BaseSourcePagingSource(source) { // Display name abstract val name: String diff --git a/app/src/main/java/exh/smartsearch/SmartSearchEngine.kt b/app/src/main/java/exh/smartsearch/SmartSearchEngine.kt index f70ad35b2..0bb6844e5 100644 --- a/app/src/main/java/exh/smartsearch/SmartSearchEngine.kt +++ b/app/src/main/java/exh/smartsearch/SmartSearchEngine.kt @@ -1,6 +1,5 @@ package exh.smartsearch -import eu.kanade.domain.manga.model.toDomainManga import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.SManga @@ -8,6 +7,7 @@ import info.debatty.java.stringsimilarity.NormalizedLevenshtein import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.supervisorScope +import mihon.domain.manga.model.toDomainManga import tachiyomi.domain.manga.model.Manga import java.util.Locale diff --git a/app/src/main/java/exh/ui/smartsearch/SmartSearchScreenModel.kt b/app/src/main/java/exh/ui/smartsearch/SmartSearchScreenModel.kt index 0672fefe2..90044195e 100644 --- a/app/src/main/java/exh/ui/smartsearch/SmartSearchScreenModel.kt +++ b/app/src/main/java/exh/ui/smartsearch/SmartSearchScreenModel.kt @@ -28,7 +28,7 @@ class SmartSearchScreenModel( val result = try { val resultManga = smartSearchEngine.smartSearch(source, config.origTitle) if (resultManga != null) { - val localManga = networkToLocalManga.await(resultManga) + val localManga = networkToLocalManga(resultManga) SearchResults.Found(localManga) } else { SearchResults.NotFound diff --git a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt index 86ff8b1f5..dd523d726 100644 --- a/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt @@ -97,40 +97,6 @@ class MangaRepositoryImpl( } } - override suspend fun insert(manga: Manga): Long? { - return handler.awaitOneOrNullExecutable(inTransaction = true) { - // SY --> - if (mangasQueries.getIdByUrlAndSource(manga.url, manga.source).executeAsOneOrNull() != null) { - return@awaitOneOrNullExecutable mangasQueries.getIdByUrlAndSource(manga.url, manga.source) - } - // SY <-- - mangasQueries.insert( - source = manga.source, - url = manga.url, - artist = manga.artist, - author = manga.author, - description = manga.description, - genre = manga.genre, - title = manga.title, - status = manga.status, - thumbnailUrl = manga.thumbnailUrl, - favorite = manga.favorite, - lastUpdate = manga.lastUpdate, - nextUpdate = manga.nextUpdate, - calculateInterval = manga.fetchInterval.toLong(), - initialized = manga.initialized, - viewerFlags = manga.viewerFlags, - chapterFlags = manga.chapterFlags, - coverLastModified = manga.coverLastModified, - dateAdded = manga.dateAdded, - updateStrategy = manga.updateStrategy, - version = manga.version, - notes = manga.notes, - ) - mangasQueries.selectLastInsertedRowId() - } - } - override suspend fun update(update: MangaUpdate): Boolean { return try { partialUpdate(update) @@ -151,6 +117,37 @@ class MangaRepositoryImpl( } } + override suspend fun insertNetworkManga(manga: List): List { + return handler.await(inTransaction = true) { + manga.map { + mangasQueries.insertNetworkManga( + source = it.source, + url = it.url, + artist = it.artist, + author = it.author, + description = it.description, + genre = it.genre, + title = it.title, + status = it.status, + thumbnailUrl = it.thumbnailUrl, + favorite = it.favorite, + lastUpdate = it.lastUpdate, + nextUpdate = it.nextUpdate, + calculateInterval = it.fetchInterval.toLong(), + initialized = it.initialized, + viewerFlags = it.viewerFlags, + chapterFlags = it.chapterFlags, + coverLastModified = it.coverLastModified, + dateAdded = it.dateAdded, + updateStrategy = it.updateStrategy, + version = it.version, + mapper = MangaMapper::mapManga, + ) + .executeAsOne() + } + } + } + private suspend fun partialUpdate(vararg mangaUpdates: MangaUpdate) { handler.await(inTransaction = true) { mangaUpdates.forEach { value -> diff --git a/data/src/main/java/tachiyomi/data/source/EHentaiPagingSource.kt b/data/src/main/java/tachiyomi/data/source/EHentaiPagingSource.kt index 3a781fafc..af2be6ace 100644 --- a/data/src/main/java/tachiyomi/data/source/EHentaiPagingSource.kt +++ b/data/src/main/java/tachiyomi/data/source/EHentaiPagingSource.kt @@ -4,21 +4,27 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MetadataMangasPage -import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.RaisedSearchMetadata +import mihon.domain.manga.model.toDomainManga +import tachiyomi.domain.manga.model.Manga -abstract class EHentaiPagingSource(override val source: CatalogueSource) : SourcePagingSource(source) { +abstract class EHentaiPagingSource(override val source: CatalogueSource) : BaseSourcePagingSource(source) { - override fun getPageLoadResult( + override suspend fun getPageLoadResult( params: LoadParams, mangasPage: MangasPage, - ): LoadResult.Page> { + ): LoadResult.Page> { mangasPage as MetadataMangasPage val metadata = mangasPage.mangasMetadata + val manga = mangasPage.mangas.map { it.toDomainManga(source.id) } + .let { networkToLocalManga(it) } + // SY --> + .mapIndexed { index, manga -> manga to metadata.getOrNull(index) } + // SY <-- + return LoadResult.Page( - data = mangasPage.mangas - .mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) }, + data = manga, prevKey = null, nextKey = mangasPage.nextKey, ) diff --git a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt index b0f8cfd17..c711b5231 100644 --- a/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt +++ b/data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt @@ -5,13 +5,20 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MetadataMangasPage -import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.RaisedSearchMetadata +import mihon.domain.manga.model.toDomainManga import tachiyomi.core.common.util.lang.withIOContext -import tachiyomi.domain.source.repository.SourcePagingSourceType +import tachiyomi.domain.manga.interactor.NetworkToLocalManga +import tachiyomi.domain.manga.model.Manga +import tachiyomi.domain.source.repository.SourcePagingSource +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get -class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : - SourcePagingSource(source) { +class SourceSearchPagingSource( + source: CatalogueSource, + private val query: String, + private val filters: FilterList, +) : BaseSourcePagingSource(source) { override suspend fun requestNextPage(currentPage: Int): MangasPage { return source?.getSearchManga(currentPage, query, filters) // KMK --> @@ -20,7 +27,7 @@ class SourceSearchPagingSource(source: CatalogueSource, val query: String, val f } } -class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(source) { +class SourcePopularPagingSource(source: CatalogueSource) : BaseSourcePagingSource(source) { override suspend fun requestNextPage(currentPage: Int): MangasPage { return source?.getPopularManga(currentPage) // KMK --> @@ -29,7 +36,7 @@ class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(so } } -class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(source) { +class SourceLatestPagingSource(source: CatalogueSource) : BaseSourcePagingSource(source) { override suspend fun requestNextPage(currentPage: Int): MangasPage { return source?.getLatestUpdates(currentPage) // KMK --> @@ -38,37 +45,38 @@ class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(sou } } -abstract class SourcePagingSource( +abstract class BaseSourcePagingSource( protected open val source: CatalogueSource?, -) : SourcePagingSourceType() { + protected val networkToLocalManga: NetworkToLocalManga = Injekt.get(), +) : SourcePagingSource() { abstract suspend fun requestNextPage(currentPage: Int): MangasPage override suspend fun load( params: LoadParams, - ): LoadResult */ Pair/*SY <-- */> { + ): LoadResult */ Pair/*SY <-- */> { val page = params.key ?: 1 - val mangasPage = try { - withIOContext { + return try { + val mangasPage = withIOContext { requestNextPage(page.toInt()) .takeIf { it.mangas.isNotEmpty() } ?: throw NoResultsException() } - } catch (e: Exception) { - return LoadResult.Error(e) - } - // SY --> - return getPageLoadResult(params, mangasPage) - // SY <-- + // SY --> + getPageLoadResult(params, mangasPage) + // SY <-- + } catch (e: Exception) { + LoadResult.Error(e) + } } // SY --> - open fun getPageLoadResult( + open suspend fun getPageLoadResult( params: LoadParams, mangasPage: MangasPage, - ): LoadResult.Page */ Pair/*SY <-- */> { + ): LoadResult.Page */ Pair/*SY <-- */> { val page = params.key ?: 1 // SY --> @@ -79,11 +87,14 @@ abstract class SourcePagingSource( } // SY <-- + val manga = mangasPage.mangas.map { it.toDomainManga(source!!.id) } + .let { networkToLocalManga(it) } + // SY --> + .mapIndexed { index, manga -> manga to metadata.getOrNull(index) } + // SY <-- + return LoadResult.Page( - data = mangasPage.mangas - // SY --> - .mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) }, - // SY <-- + data = manga, prevKey = null, nextKey = if (mangasPage.hasNextPage) page + 1 else null, ) @@ -91,7 +102,7 @@ abstract class SourcePagingSource( // SY <-- override fun getRefreshKey( - state: PagingState */ Pair/*SY <-- */>, + state: PagingState */ Pair/*SY <-- */>, ): Long? { return state.anchorPosition?.let { anchorPosition -> val anchorPage = state.closestPageToPosition(anchorPosition) diff --git a/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt index 0d3a6cb08..1674c7b15 100644 --- a/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/source/SourceRepositoryImpl.kt @@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.map import tachiyomi.data.DatabaseHandler import tachiyomi.domain.source.model.SourceWithCount import tachiyomi.domain.source.model.StubSource -import tachiyomi.domain.source.repository.SourcePagingSourceType +import tachiyomi.domain.source.repository.SourcePagingSource import tachiyomi.domain.source.repository.SourceRepository import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.model.Source as DomainSource @@ -77,7 +77,7 @@ class SourceRepositoryImpl( sourceId: Long, query: String, filterList: FilterList, - ): SourcePagingSourceType { + ): SourcePagingSource { val source = sourceManager.get(sourceId) as CatalogueSource // SY --> if (source.isEhBasedSource()) { @@ -87,7 +87,7 @@ class SourceRepositoryImpl( return SourceSearchPagingSource(source, query, filterList) } - override fun getPopular(sourceId: Long): SourcePagingSourceType { + override fun getPopular(sourceId: Long): SourcePagingSource { val source = sourceManager.get(sourceId) as CatalogueSource // SY --> if (source.isEhBasedSource()) { @@ -97,7 +97,7 @@ class SourceRepositoryImpl( return SourcePopularPagingSource(source) } - override fun getLatest(sourceId: Long): SourcePagingSourceType { + override fun getLatest(sourceId: Long): SourcePagingSource { val source = sourceManager.get(sourceId) as CatalogueSource // SY --> if (source.isEhBasedSource()) { diff --git a/data/src/main/sqldelight/tachiyomi/data/mangas.sq b/data/src/main/sqldelight/tachiyomi/data/mangas.sq index 6ee571ef9..dd2a4a3c9 100644 --- a/data/src/main/sqldelight/tachiyomi/data/mangas.sq +++ b/data/src/main/sqldelight/tachiyomi/data/mangas.sq @@ -195,6 +195,34 @@ WHERE _id = :mangaId; selectLastInsertedRowId: SELECT last_insert_rowid(); +insertNetworkManga { + -- Insert the manga if it doesn't exist already + INSERT INTO mangas( + source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, + last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, + update_strategy, calculate_interval, last_modified_at, version + ) + SELECT + :source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, + :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :chapterFlags, :coverLastModified, :dateAdded, + :updateStrategy, :calculateInterval, 0, :version + WHERE NOT EXISTS(SELECT 0 FROM mangas WHERE source = :source AND url = :url); + + -- Update the title if it is not favorite + UPDATE mangas + SET title = :title + WHERE source = :source + AND url = :url + AND favorite = 0; + + -- Finally return the manga + SELECT * + FROM mangas + WHERE source = :source + AND url = :url + LIMIT 1; +} + getEhMangaWithMetadata: SELECT mangas.* FROM mangas INNER JOIN search_metadata diff --git a/domain/src/main/java/mihon/domain/manga/model/SManga.kt b/domain/src/main/java/mihon/domain/manga/model/SManga.kt new file mode 100644 index 000000000..c07ff52c3 --- /dev/null +++ b/domain/src/main/java/mihon/domain/manga/model/SManga.kt @@ -0,0 +1,22 @@ +package mihon.domain.manga.model + +import eu.kanade.tachiyomi.source.model.SManga +import tachiyomi.domain.manga.model.Manga + +fun SManga.toDomainManga(sourceId: Long): Manga { + return Manga.create().copy( + url = url, + // SY --> + ogTitle = title, + ogArtist = artist, + ogAuthor = author, + ogDescription = description, + ogGenre = getGenres(), + ogStatus = status.toLong(), + ogThumbnailUrl = thumbnail_url, + // SY <-- + updateStrategy = update_strategy, + initialized = initialized, + source = sourceId, + ) +} diff --git a/domain/src/main/java/tachiyomi/domain/manga/interactor/NetworkToLocalManga.kt b/domain/src/main/java/tachiyomi/domain/manga/interactor/NetworkToLocalManga.kt index 255951568..a3e35d6e3 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/interactor/NetworkToLocalManga.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/interactor/NetworkToLocalManga.kt @@ -7,29 +7,11 @@ class NetworkToLocalManga( private val mangaRepository: MangaRepository, ) { - suspend fun await(manga: Manga): Manga { - val localManga = getManga(manga.url, manga.source) - return when { - localManga == null -> { - val id = insertManga(manga) - manga.copy(id = id!!) - } - !localManga.favorite -> { - // if the manga isn't a favorite, set its display title from source - // if it later becomes a favorite, updated title will go to db - localManga.copy(/* SY --> */ogTitle/* SY <-- */ = manga.title) - } - else -> { - localManga - } - } + suspend operator fun invoke(manga: Manga): Manga { + return mangaRepository.insertNetworkManga(listOf(manga)).single() } - private suspend fun getManga(url: String, sourceId: Long): Manga? { - return mangaRepository.getMangaByUrlAndSourceId(url, sourceId) - } - - private suspend fun insertManga(manga: Manga): Long? { - return mangaRepository.insert(manga) + suspend operator fun invoke(manga: List): List { + return mangaRepository.insertNetworkManga(manga) } } diff --git a/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt b/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt index 0b58a8ece..317c9e156 100644 --- a/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt +++ b/domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt @@ -33,12 +33,12 @@ interface MangaRepository { suspend fun setMangaCategories(mangaId: Long, categoryIds: List) - suspend fun insert(manga: Manga): Long? - suspend fun update(update: MangaUpdate): Boolean suspend fun updateAll(mangaUpdates: List): Boolean + suspend fun insertNetworkManga(manga: List): List + // SY --> suspend fun getMangaBySourceId(sourceId: Long): List diff --git a/domain/src/main/java/tachiyomi/domain/source/interactor/GetRemoteManga.kt b/domain/src/main/java/tachiyomi/domain/source/interactor/GetRemoteManga.kt index 61e5e513e..8ec432bbd 100644 --- a/domain/src/main/java/tachiyomi/domain/source/interactor/GetRemoteManga.kt +++ b/domain/src/main/java/tachiyomi/domain/source/interactor/GetRemoteManga.kt @@ -1,14 +1,14 @@ package tachiyomi.domain.source.interactor import eu.kanade.tachiyomi.source.model.FilterList -import tachiyomi.domain.source.repository.SourcePagingSourceType +import tachiyomi.domain.source.repository.SourcePagingSource import tachiyomi.domain.source.repository.SourceRepository class GetRemoteManga( private val repository: SourceRepository, ) { - fun subscribe(sourceId: Long, query: String, filterList: FilterList): SourcePagingSourceType { + operator fun invoke(sourceId: Long, query: String, filterList: FilterList): SourcePagingSource { return when (query) { QUERY_POPULAR -> repository.getPopular(sourceId) QUERY_LATEST -> repository.getLatest(sourceId) diff --git a/domain/src/main/java/tachiyomi/domain/source/repository/SourceRepository.kt b/domain/src/main/java/tachiyomi/domain/source/repository/SourceRepository.kt index f73e1ea97..869add714 100644 --- a/domain/src/main/java/tachiyomi/domain/source/repository/SourceRepository.kt +++ b/domain/src/main/java/tachiyomi/domain/source/repository/SourceRepository.kt @@ -2,13 +2,13 @@ package tachiyomi.domain.source.repository import androidx.paging.PagingSource import eu.kanade.tachiyomi.source.model.FilterList -import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.RaisedSearchMetadata import kotlinx.coroutines.flow.Flow +import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.model.Source import tachiyomi.domain.source.model.SourceWithCount -typealias SourcePagingSourceType = PagingSource */ Pair/*SY <-- */> +typealias SourcePagingSource = PagingSource */ Pair/*SY <-- */> interface SourceRepository { @@ -20,9 +20,9 @@ interface SourceRepository { fun getSourcesWithNonLibraryManga(): Flow> - fun search(sourceId: Long, query: String, filterList: FilterList): SourcePagingSourceType + fun search(sourceId: Long, query: String, filterList: FilterList): SourcePagingSource - fun getPopular(sourceId: Long): SourcePagingSourceType + fun getPopular(sourceId: Long): SourcePagingSource - fun getLatest(sourceId: Long): SourcePagingSourceType + fun getLatest(sourceId: Long): SourcePagingSource }