Significantly improve browsing speed (near instantaneous) (#1946)

(cherry picked from commit c8ffabc84a096207c1997ab69fc86176f3b53f00)

# Conflicts:
#	CHANGELOG.md
#	app/src/main/java/eu/kanade/domain/manga/model/Manga.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt
#	data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt
#	data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt
#	data/src/main/sqldelight/tachiyomi/data/mangas.sq
#	domain/src/main/java/tachiyomi/domain/manga/interactor/NetworkToLocalManga.kt
#	domain/src/main/java/tachiyomi/domain/manga/repository/MangaRepository.kt
#	domain/src/main/java/tachiyomi/domain/source/repository/SourceRepository.kt
This commit is contained in:
AntsyLich 2025-03-31 13:17:22 +06:00 committed by Jobobby04
parent 26674136e6
commit c8039739d5
29 changed files with 180 additions and 172 deletions

View File

@ -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 { fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean {
return coverCache.getCustomCoverFile(id).exists() return coverCache.getCustomCoverFile(id).exists()
} }

View File

@ -510,7 +510,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
private suspend fun updateCovers() { private suspend fun updateCovers() {
val semaphore = Semaphore(5) val semaphore = Semaphore(5)
val progressCount = AtomicInteger(0) val progressCount = AtomicInt(0)
val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>() val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
coroutineScope { coroutineScope {
@ -585,7 +585,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
var dbManga = getManga.await(networkManga.url, mangaDex.id) var dbManga = getManga.await(networkManga.url, mangaDex.id)
if (dbManga == null) { if (dbManga == null) {
dbManga = networkToLocalManga.await( dbManga = networkToLocalManga(
Manga.create().copy( Manga.create().copy(
url = networkManga.url, url = networkManga.url,
ogTitle = networkManga.title, ogTitle = networkManga.title,

View File

@ -170,7 +170,7 @@ class MergedSource : HttpSource() {
var manga = getManga.await(mangaUrl, mangaSourceId) var manga = getManga.await(mangaUrl, mangaSourceId)
val source = sourceManager.getOrStub(manga?.source ?: mangaSourceId) val source = sourceManager.getOrStub(manga?.source ?: mangaSourceId)
if (manga == null) { if (manga == null) {
val newManga = networkToLocalManga.await( val newManga = networkToLocalManga(
Manga.create().copy( Manga.create().copy(
source = mangaSourceId, source = mangaSourceId,
url = mangaUrl, url = mangaUrl,

View File

@ -7,7 +7,6 @@ import androidx.compose.ui.util.fastAny
import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.browse.FeedItemUI import eu.kanade.presentation.browse.FeedItemUI
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
@ -31,6 +30,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import mihon.domain.manga.model.toDomainManga
import tachiyomi.core.common.util.lang.launchIO import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.core.common.util.lang.launchNonCancellable import tachiyomi.core.common.util.lang.launchNonCancellable
import tachiyomi.core.common.util.lang.withIOContext import tachiyomi.core.common.util.lang.withIOContext
@ -251,9 +251,7 @@ open class FeedScreenModel(
val result = withIOContext { val result = withIOContext {
itemUI.copy( itemUI.copy(
results = page.map { results = networkToLocalManga(page.map { it.toDomainManga(itemUI.source!!.id) }),
networkToLocalManga.await(it.toDomainManga(itemUI.source!!.id))
},
) )
} }

View File

@ -226,7 +226,7 @@ class MigrationListScreenModel(
if (searchResult != null && if (searchResult != null &&
!(searchResult.url == mangaObj.url && source.id == mangaObj.source) !(searchResult.url == mangaObj.url && source.id == mangaObj.source)
) { ) {
val localManga = networkToLocalManga.await(searchResult) val localManga = networkToLocalManga(searchResult)
val chapters = if (source is EHentai) { val chapters = if (source is EHentai) {
source.getChapterList(localManga.toSManga(), throttleManager::throttle) source.getChapterList(localManga.toSManga(), throttleManager::throttle)
@ -264,7 +264,7 @@ class MigrationListScreenModel(
} }
if (searchResult != null) { if (searchResult != null) {
val localManga = networkToLocalManga.await(searchResult) val localManga = networkToLocalManga(searchResult)
val chapters = try { val chapters = try {
if (source is EHentai) { if (source is EHentai) {
source.getChapterList(localManga.toSManga(), throttleManager::throttle) source.getChapterList(localManga.toSManga(), throttleManager::throttle)
@ -455,7 +455,7 @@ class MigrationListScreenModel(
screenModelScope.launchIO { screenModelScope.launchIO {
val result = migratingManga.migrationScope.async { val result = migratingManga.migrationScope.async {
val manga = getManga(newMangaId)!! val manga = getManga(newMangaId)!!
val localManga = networkToLocalManga.await(manga) val localManga = networkToLocalManga(manga)
try { try {
val source = sourceManager.get(manga.source)!! val source = sourceManager.get(manga.source)!!
val chapters = source.getChapterList(localManga.toSManga()) val chapters = source.getChapterList(localManga.toSManga())

View File

@ -16,7 +16,6 @@ import cafe.adriel.voyager.core.model.screenModelScope
import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.StringResource
import eu.kanade.core.preference.asState import eu.kanade.core.preference.asState
import eu.kanade.domain.manga.interactor.UpdateManga 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.GetExhSavedSearch
import eu.kanade.domain.source.interactor.GetIncognitoState import eu.kanade.domain.source.interactor.GetIncognitoState
import eu.kanade.domain.source.service.SourcePreferences 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.SharingStarted
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
@ -50,7 +48,6 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonArray
import tachiyomi.core.common.preference.CheckboxState import tachiyomi.core.common.preference.CheckboxState
@ -67,7 +64,6 @@ import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
import tachiyomi.domain.manga.interactor.GetFlatMetadataById import tachiyomi.domain.manga.interactor.GetFlatMetadataById
import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.toMangaUpdate import tachiyomi.domain.manga.model.toMangaUpdate
import tachiyomi.domain.source.interactor.DeleteSavedSearchById import tachiyomi.domain.source.interactor.DeleteSavedSearchById
@ -75,7 +71,7 @@ import tachiyomi.domain.source.interactor.GetRemoteManga
import tachiyomi.domain.source.interactor.InsertSavedSearch import tachiyomi.domain.source.interactor.InsertSavedSearch
import tachiyomi.domain.source.model.EXHSavedSearch import tachiyomi.domain.source.model.EXHSavedSearch
import tachiyomi.domain.source.model.SavedSearch 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.domain.source.service.SourceManager
import tachiyomi.i18n.sy.SYMR import tachiyomi.i18n.sy.SYMR
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -101,7 +97,6 @@ open class BrowseSourceScreenModel(
private val setMangaCategories: SetMangaCategories = Injekt.get(), private val setMangaCategories: SetMangaCategories = Injekt.get(),
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(), private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
private val getManga: GetManga = Injekt.get(), private val getManga: GetManga = Injekt.get(),
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
private val updateManga: UpdateManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(),
private val addTracks: AddTracks = Injekt.get(), private val addTracks: AddTracks = Injekt.get(),
private val getIncognitoState: GetIncognitoState = Injekt.get(), private val getIncognitoState: GetIncognitoState = Injekt.get(),
@ -193,10 +188,9 @@ open class BrowseSourceScreenModel(
createSourcePagingSource(listing.query ?: "", listing.filters) createSourcePagingSource(listing.query ?: "", listing.filters)
// SY <-- // SY <--
}.flow.map { pagingData -> }.flow.map { pagingData ->
pagingData.map { (it, metadata) -> pagingData.map { (manga, metadata) ->
networkToLocalManga.await(it.toDomainManga(sourceId)) getManga.subscribe(manga.url, manga.source)
.let { localManga -> getManga.subscribe(localManga.url, localManga.source) } .map { it ?: manga }
.filterNotNull()
// SY --> // SY -->
.combineMetadata(metadata) .combineMetadata(metadata)
// SY <-- // SY <--
@ -382,8 +376,8 @@ open class BrowseSourceScreenModel(
} }
// SY --> // SY -->
open fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType { open fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSource {
return getRemoteManga.subscribe(sourceId, query, filters) return getRemoteManga(sourceId, query, filters)
} }
// SY <-- // SY <--

View File

@ -10,7 +10,6 @@ import cafe.adriel.voyager.core.model.screenModelScope
import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.StringResource
import eu.kanade.core.preference.asState import eu.kanade.core.preference.asState
import eu.kanade.domain.manga.interactor.UpdateManga 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.GetExhSavedSearch
import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.browse.SourceFeedUI import eu.kanade.presentation.browse.SourceFeedUI
@ -32,8 +31,8 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import mihon.domain.manga.model.toDomainManga
import tachiyomi.core.common.util.lang.launchIO import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.core.common.util.lang.launchNonCancellable import tachiyomi.core.common.util.lang.launchNonCancellable
import tachiyomi.core.common.util.lang.withIOContext import tachiyomi.core.common.util.lang.withIOContext
@ -173,9 +172,7 @@ open class SourceFeedScreenModel(
} }
val titles = withIOContext { val titles = withIOContext {
page.map { networkToLocalManga(page.map { it.toDomainManga(source.id) })
networkToLocalManga.await(it.toDomainManga(source.id))
}
} }
mutableState.update { state -> mutableState.update { state ->

View File

@ -5,7 +5,6 @@ import androidx.compose.runtime.Immutable
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.presentation.util.ioCoroutineScope
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
@ -25,6 +24,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mihon.domain.manga.model.toDomainManga
import tachiyomi.core.common.preference.toggle import tachiyomi.core.common.preference.toggle
import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga
@ -169,9 +169,8 @@ abstract class SearchScreenModel(
source.getSearchManga(1, query, source.getFilterList()) source.getSearchManga(1, query, source.getFilterList())
} }
val titles = page.mangas.map { val titles = page.mangas.map { it.toDomainManga(source.id) }
networkToLocalManga.await(it.toDomainManga(source.id)) .let { networkToLocalManga(it) }
}
if (isActive) { if (isActive) {
updateItem(source, SearchItemResult.Success(titles)) updateItem(source, SearchItemResult.Success(titles))

View File

@ -4,18 +4,16 @@ import androidx.compose.runtime.Immutable
import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.domain.manga.model.toSManga import eu.kanade.domain.manga.model.toSManga
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.model.SChapter 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.ResolvableSource
import eu.kanade.tachiyomi.source.online.UriType import eu.kanade.tachiyomi.source.online.UriType
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import mihon.domain.manga.model.toDomainManga
import tachiyomi.core.common.util.lang.launchIO import tachiyomi.core.common.util.lang.launchIO
import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId
import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.manga.interactor.GetMangaByUrlAndSourceId
import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.service.SourceManager
@ -27,7 +25,6 @@ class DeepLinkScreenModel(
private val sourceManager: SourceManager = Injekt.get(), private val sourceManager: SourceManager = Injekt.get(),
private val networkToLocalManga: NetworkToLocalManga = Injekt.get(), private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
private val getChapterByUrlAndMangaId: GetChapterByUrlAndMangaId = Injekt.get(), private val getChapterByUrlAndMangaId: GetChapterByUrlAndMangaId = Injekt.get(),
private val getMangaByUrlAndSourceId: GetMangaByUrlAndSourceId = Injekt.get(),
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(), private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
) : StateScreenModel<DeepLinkScreenModel.State>(State.Loading) { ) : StateScreenModel<DeepLinkScreenModel.State>(State.Loading) {
@ -38,7 +35,7 @@ class DeepLinkScreenModel(
.firstOrNull { it.getUriType(query) != UriType.Unknown } .firstOrNull { it.getUriType(query) != UriType.Unknown }
val manga = source?.getManga(query)?.let { 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) { 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 { sealed interface State {
@Immutable @Immutable
data object Loading : State data object Loading : State

View File

@ -658,7 +658,7 @@ class MangaScreenModel(
existingManga = getManga.await(mergedManga.url, mergedManga.source) existingManga = getManga.await(mergedManga.url, mergedManga.source)
} }
mergedManga = networkToLocalManga.await(mergedManga) mergedManga = networkToLocalManga(mergedManga)
getCategories.await(originalMangaId) getCategories.await(originalMangaId)
.let { .let {

View File

@ -136,7 +136,7 @@ class GalleryAdder(
// Use manga in DB if possible, otherwise, make a new manga // Use manga in DB if possible, otherwise, make a new manga
var manga = getManga.await(cleanedMangaUrl, source.id) var manga = getManga.await(cleanedMangaUrl, source.id)
?: networkToLocalManga.await( ?: networkToLocalManga(
Manga.create().copy( Manga.create().copy(
source = source.id, source = source.id,
url = cleanedMangaUrl, url = cleanedMangaUrl,

View File

@ -1,6 +1,5 @@
package exh.favorites package exh.favorites
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.source.online.all.EHentai
import exh.metadata.metadata.EHentaiSearchMetadata import exh.metadata.metadata.EHentaiSearchMetadata
import exh.source.EXH_SOURCE_ID import exh.source.EXH_SOURCE_ID
@ -11,6 +10,7 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
import mihon.domain.manga.model.toDomainManga
import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.model.Category import tachiyomi.domain.category.model.Category
import tachiyomi.domain.manga.interactor.DeleteFavoriteEntries import tachiyomi.domain.manga.interactor.DeleteFavoriteEntries

View File

@ -2,12 +2,12 @@ package exh.md.follows
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.online.all.MangaDex import eu.kanade.tachiyomi.source.online.all.MangaDex
import tachiyomi.data.source.SourcePagingSource import tachiyomi.data.source.BaseSourcePagingSource
/** /**
* LatestUpdatesPager inherited from the general Pager. * 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 { override suspend fun requestNextPage(currentPage: Int): MangasPage {
return mangadex.fetchFollows(currentPage) return mangadex.fetchFollows(currentPage)

View File

@ -8,12 +8,12 @@ import exh.source.getMainSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import tachiyomi.data.source.BaseSourcePagingSource
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.repository.SourcePagingSourceType
class MangaDexFollowsScreenModel(sourceId: Long) : BrowseSourceScreenModel(sourceId, null) { class MangaDexFollowsScreenModel(sourceId: Long) : BrowseSourceScreenModel(sourceId, null) {
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType { override fun createSourcePagingSource(query: String, filters: FilterList): BaseSourcePagingSource {
return MangaDexFollowsPagingSource(source.getMainSource() as MangaDex) return MangaDexFollowsPagingSource(source.getMainSource() as MangaDex)
} }

View File

@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.StateScreenModel
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.presentation.util.ioCoroutineScope import eu.kanade.presentation.util.ioCoroutineScope
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
import exh.recs.sources.RecommendationPagingSource import exh.recs.sources.RecommendationPagingSource
@ -23,6 +22,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mihon.domain.manga.model.toDomainManga
import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.manga.interactor.NetworkToLocalManga import tachiyomi.domain.manga.interactor.NetworkToLocalManga
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
@ -85,7 +85,7 @@ open class RecommendsScreenModel(
val recSourceId = recSource.associatedSourceId val recSourceId = recSource.associatedSourceId
if (recSourceId != null) { if (recSourceId != null) {
// If the recommendation is associated with a source, resolve it // If the recommendation is associated with a source, resolve it
networkToLocalManga.await(it.toDomainManga(recSourceId)) networkToLocalManga(it.toDomainManga(recSourceId))
} else { } else {
// Otherwise, skip this step. The user will be prompted to choose a source via SmartSearch // Otherwise, skip this step. The user will be prompted to choose a source via SmartSearch
it.toDomainManga(-1) it.toDomainManga(-1)

View File

@ -5,7 +5,6 @@ import android.net.wifi.WifiManager
import android.os.PowerManager import android.os.PowerManager
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.net.toUri import androidx.core.net.toUri
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.domain.manga.model.toSManga import eu.kanade.domain.manga.model.toSManga
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
@ -26,6 +25,7 @@ import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mihon.domain.manga.model.toDomainManga
import tachiyomi.data.source.NoResultsException import tachiyomi.data.source.NoResultsException
import tachiyomi.domain.UnsortedPreferences import tachiyomi.domain.UnsortedPreferences
import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.library.model.LibraryManga
@ -201,8 +201,7 @@ class RecommendationSearchHelper(val context: Context) {
return filterNot { manga -> return filterNot { manga ->
// Source recommendations can be directly resolved, if the recommendation is from the same source // Source recommendations can be directly resolved, if the recommendation is from the same source
recSource.associatedSourceId?.let { srcId -> recSource.associatedSourceId?.let { srcId ->
return@filterNot networkToLocalManga return@filterNot networkToLocalManga(manga.toDomainManga(srcId))
.await(manga.toDomainManga(srcId))
.let { local -> libraryManga.any { it.id == local.id } } .let { local -> libraryManga.any { it.id == local.id } }
} }

View File

@ -14,8 +14,8 @@ import exh.source.isMdBasedSource
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.common.util.system.logcat import tachiyomi.core.common.util.system.logcat
import tachiyomi.data.source.BaseSourcePagingSource
import tachiyomi.data.source.NoResultsException import tachiyomi.data.source.NoResultsException
import tachiyomi.data.source.SourcePagingSource
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.i18n.sy.SYMR import tachiyomi.i18n.sy.SYMR
@ -29,7 +29,7 @@ import uy.kohesive.injekt.injectLazy
abstract class RecommendationPagingSource( abstract class RecommendationPagingSource(
protected val manga: Manga, protected val manga: Manga,
source: CatalogueSource? = null, source: CatalogueSource? = null,
) : SourcePagingSource(source) { ) : BaseSourcePagingSource(source) {
// Display name // Display name
abstract val name: String abstract val name: String

View File

@ -1,9 +1,9 @@
package exh.smartsearch package exh.smartsearch
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import mihon.domain.manga.model.toDomainManga
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
class SmartSourceSearchEngine( class SmartSourceSearchEngine(

View File

@ -28,7 +28,7 @@ class SmartSearchScreenModel(
val result = try { val result = try {
val resultManga = smartSearchEngine.smartSearch(source, config.origTitle) val resultManga = smartSearchEngine.smartSearch(source, config.origTitle)
if (resultManga != null) { if (resultManga != null) {
val localManga = networkToLocalManga.await(resultManga) val localManga = networkToLocalManga(resultManga)
SearchResults.Found(localManga) SearchResults.Found(localManga)
} else { } else {
SearchResults.NotFound SearchResults.NotFound

View File

@ -105,40 +105,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 { override suspend fun update(update: MangaUpdate): Boolean {
return try { return try {
partialUpdate(update) partialUpdate(update)
@ -159,6 +125,39 @@ class MangaRepositoryImpl(
} }
} }
override suspend fun insertNetworkManga(manga: List<Manga>): List<Manga> {
return handler.await(inTransaction = true) {
manga.map {
mangasQueries.insertNetworkManga(
source = it.source,
url = it.url,
// SY -->
artist = it.ogArtist,
author = it.ogAuthor,
description = it.ogDescription,
genre = it.ogGenre,
title = it.ogTitle,
status = it.ogStatus,
thumbnailUrl = it.ogThumbnailUrl,
// SY <--
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) { private suspend fun partialUpdate(vararg mangaUpdates: MangaUpdate) {
handler.await(inTransaction = true) { handler.await(inTransaction = true) {
mangaUpdates.forEach { value -> mangaUpdates.forEach { value ->

View File

@ -4,20 +4,26 @@ import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.MetadataMangasPage import eu.kanade.tachiyomi.source.model.MetadataMangasPage
import eu.kanade.tachiyomi.source.model.SManga
import exh.metadata.metadata.RaisedSearchMetadata 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<Long>, params: LoadParams<Long>,
mangasPage: MangasPage, mangasPage: MangasPage,
): LoadResult.Page<Long, Pair<SManga, RaisedSearchMetadata?>> { ): LoadResult.Page<Long, Pair<Manga, RaisedSearchMetadata?>> {
mangasPage as MetadataMangasPage mangasPage as MetadataMangasPage
val metadata = mangasPage.mangasMetadata val metadata = mangasPage.mangasMetadata
val manga = mangasPage.mangas.map { it.toDomainManga(source.id) }
.let { networkToLocalManga(it) }
return LoadResult.Page( return LoadResult.Page(
data = mangasPage.mangas data = manga
.mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) }, .mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) },
prevKey = null, prevKey = null,
nextKey = mangasPage.nextKey, nextKey = mangasPage.nextKey,

View File

@ -5,63 +5,74 @@ import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.MetadataMangasPage import eu.kanade.tachiyomi.source.model.MetadataMangasPage
import eu.kanade.tachiyomi.source.model.SManga
import exh.metadata.metadata.RaisedSearchMetadata import exh.metadata.metadata.RaisedSearchMetadata
import mihon.domain.manga.model.toDomainManga
import tachiyomi.core.common.util.lang.withIOContext 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) : class SourceSearchPagingSource(
SourcePagingSource(source) { source: CatalogueSource,
private val query: String,
private val filters: FilterList,
) : BaseSourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage { override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source!!.getSearchManga(currentPage, query, filters) return source!!.getSearchManga(currentPage, query, filters)
} }
} }
class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(source) { class SourcePopularPagingSource(source: CatalogueSource) : BaseSourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage { override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source!!.getPopularManga(currentPage) return source!!.getPopularManga(currentPage)
} }
} }
class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(source) { class SourceLatestPagingSource(source: CatalogueSource) : BaseSourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage { override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source!!.getLatestUpdates(currentPage) return source!!.getLatestUpdates(currentPage)
} }
} }
abstract class SourcePagingSource( abstract class BaseSourcePagingSource(
protected open val source: CatalogueSource?, protected open val source: CatalogueSource?,
) : SourcePagingSourceType() { protected val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
) : SourcePagingSource() {
abstract suspend fun requestNextPage(currentPage: Int): MangasPage abstract suspend fun requestNextPage(currentPage: Int): MangasPage
override suspend fun load( override suspend fun load(
params: LoadParams<Long>, params: LoadParams<Long>,
): LoadResult<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */> { ): LoadResult<Long, /*SY --> */ Pair<Manga, RaisedSearchMetadata?>/*SY <-- */> {
val page = params.key ?: 1 val page = params.key ?: 1
val mangasPage = try { return try {
withIOContext { val mangasPage = withIOContext {
requestNextPage(page.toInt()) requestNextPage(page.toInt())
.takeIf { it.mangas.isNotEmpty() } .takeIf { it.mangas.isNotEmpty() }
?: throw NoResultsException() ?: throw NoResultsException()
} }
} catch (e: Exception) {
return LoadResult.Error(e)
}
// SY --> // SY -->
return getPageLoadResult(params, mangasPage) getPageLoadResult(params, mangasPage)
// SY <-- // SY <--
} catch (e: Exception) {
LoadResult.Error(e)
}
} }
// SY --> // SY -->
open fun getPageLoadResult( open suspend fun getPageLoadResult(
params: LoadParams<Long>, params: LoadParams<Long>,
mangasPage: MangasPage, mangasPage: MangasPage,
): LoadResult.Page<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */> { ): LoadResult.Page<Long, /*SY --> */ Pair<Manga, RaisedSearchMetadata?>/*SY <-- */> {
val page = params.key ?: 1 val page = params.key ?: 1
val manga = mangasPage.mangas.map { it.toDomainManga(source!!.id) }
.let { networkToLocalManga(it) }
// SY --> // SY -->
val metadata = if (mangasPage is MetadataMangasPage) { val metadata = if (mangasPage is MetadataMangasPage) {
mangasPage.mangasMetadata mangasPage.mangasMetadata
@ -71,10 +82,9 @@ abstract class SourcePagingSource(
// SY <-- // SY <--
return LoadResult.Page( return LoadResult.Page(
data = mangasPage.mangas data = manga// SY -->
// SY -->
.mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) }, .mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) },
// SY <-- // SY <--,
prevKey = null, prevKey = null,
nextKey = if (mangasPage.hasNextPage) page + 1 else null, nextKey = if (mangasPage.hasNextPage) page + 1 else null,
) )
@ -82,7 +92,7 @@ abstract class SourcePagingSource(
// SY <-- // SY <--
override fun getRefreshKey( override fun getRefreshKey(
state: PagingState<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */>, state: PagingState<Long, /*SY --> */ Pair<Manga, RaisedSearchMetadata?>/*SY <-- */>,
): Long? { ): Long? {
return state.anchorPosition?.let { anchorPosition -> return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition) val anchorPage = state.closestPageToPosition(anchorPosition)

View File

@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.map
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.domain.source.model.SourceWithCount import tachiyomi.domain.source.model.SourceWithCount
import tachiyomi.domain.source.model.StubSource 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.repository.SourceRepository
import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.service.SourceManager
import tachiyomi.domain.source.model.Source as DomainSource import tachiyomi.domain.source.model.Source as DomainSource
@ -77,7 +77,7 @@ class SourceRepositoryImpl(
sourceId: Long, sourceId: Long,
query: String, query: String,
filterList: FilterList, filterList: FilterList,
): SourcePagingSourceType { ): SourcePagingSource {
val source = sourceManager.get(sourceId) as CatalogueSource val source = sourceManager.get(sourceId) as CatalogueSource
// SY --> // SY -->
if (source.isEhBasedSource()) { if (source.isEhBasedSource()) {
@ -87,7 +87,7 @@ class SourceRepositoryImpl(
return SourceSearchPagingSource(source, query, filterList) return SourceSearchPagingSource(source, query, filterList)
} }
override fun getPopular(sourceId: Long): SourcePagingSourceType { override fun getPopular(sourceId: Long): SourcePagingSource {
val source = sourceManager.get(sourceId) as CatalogueSource val source = sourceManager.get(sourceId) as CatalogueSource
// SY --> // SY -->
if (source.isEhBasedSource()) { if (source.isEhBasedSource()) {
@ -97,7 +97,7 @@ class SourceRepositoryImpl(
return SourcePopularPagingSource(source) return SourcePopularPagingSource(source)
} }
override fun getLatest(sourceId: Long): SourcePagingSourceType { override fun getLatest(sourceId: Long): SourcePagingSource {
val source = sourceManager.get(sourceId) as CatalogueSource val source = sourceManager.get(sourceId) as CatalogueSource
// SY --> // SY -->
if (source.isEhBasedSource()) { if (source.isEhBasedSource()) {

View File

@ -195,6 +195,34 @@ WHERE _id = :mangaId;
selectLastInsertedRowId: selectLastInsertedRowId:
SELECT last_insert_rowid(); 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: getEhMangaWithMetadata:
SELECT mangas.* FROM mangas SELECT mangas.* FROM mangas
INNER JOIN search_metadata INNER JOIN search_metadata

View File

@ -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,
)
}

View File

@ -7,29 +7,11 @@ class NetworkToLocalManga(
private val mangaRepository: MangaRepository, private val mangaRepository: MangaRepository,
) { ) {
suspend fun await(manga: Manga): Manga { suspend operator fun invoke(manga: Manga): Manga {
val localManga = getManga(manga.url, manga.source) return mangaRepository.insertNetworkManga(listOf(manga)).single()
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
}
}
} }
private suspend fun getManga(url: String, sourceId: Long): Manga? { suspend operator fun invoke(manga: List<Manga>): List<Manga> {
return mangaRepository.getMangaByUrlAndSourceId(url, sourceId) return mangaRepository.insertNetworkManga(manga)
}
private suspend fun insertManga(manga: Manga): Long? {
return mangaRepository.insert(manga)
} }
} }

View File

@ -33,12 +33,12 @@ interface MangaRepository {
suspend fun setMangaCategories(mangaId: Long, categoryIds: List<Long>) suspend fun setMangaCategories(mangaId: Long, categoryIds: List<Long>)
suspend fun insert(manga: Manga): Long?
suspend fun update(update: MangaUpdate): Boolean suspend fun update(update: MangaUpdate): Boolean
suspend fun updateAll(mangaUpdates: List<MangaUpdate>): Boolean suspend fun updateAll(mangaUpdates: List<MangaUpdate>): Boolean
suspend fun insertNetworkManga(manga: List<Manga>): List<Manga>
// SY --> // SY -->
suspend fun getMangaBySourceId(sourceId: Long): List<Manga> suspend fun getMangaBySourceId(sourceId: Long): List<Manga>

View File

@ -1,14 +1,14 @@
package tachiyomi.domain.source.interactor package tachiyomi.domain.source.interactor
import eu.kanade.tachiyomi.source.model.FilterList 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 import tachiyomi.domain.source.repository.SourceRepository
class GetRemoteManga( class GetRemoteManga(
private val repository: SourceRepository, 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) { return when (query) {
QUERY_POPULAR -> repository.getPopular(sourceId) QUERY_POPULAR -> repository.getPopular(sourceId)
QUERY_LATEST -> repository.getLatest(sourceId) QUERY_LATEST -> repository.getLatest(sourceId)

View File

@ -2,13 +2,13 @@ package tachiyomi.domain.source.repository
import androidx.paging.PagingSource import androidx.paging.PagingSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.SManga
import exh.metadata.metadata.RaisedSearchMetadata import exh.metadata.metadata.RaisedSearchMetadata
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.model.Source import tachiyomi.domain.source.model.Source
import tachiyomi.domain.source.model.SourceWithCount import tachiyomi.domain.source.model.SourceWithCount
typealias SourcePagingSourceType = PagingSource<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */> typealias SourcePagingSource = PagingSource<Long, /*SY --> */ Pair<Manga, RaisedSearchMetadata?>/*SY <-- */>
interface SourceRepository { interface SourceRepository {
@ -20,9 +20,9 @@ interface SourceRepository {
fun getSourcesWithNonLibraryManga(): Flow<List<SourceWithCount>> fun getSourcesWithNonLibraryManga(): Flow<List<SourceWithCount>>
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
} }