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
@@ -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 {
return try {
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) {
handler.await(inTransaction = true) {
mangaUpdates.forEach { value ->
@@ -4,20 +4,26 @@ 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<Long>,
mangasPage: MangasPage,
): LoadResult.Page<Long, Pair<SManga, RaisedSearchMetadata?>> {
): LoadResult.Page<Long, Pair<Manga, RaisedSearchMetadata?>> {
mangasPage as MetadataMangasPage
val metadata = mangasPage.mangasMetadata
val manga = mangasPage.mangas.map { it.toDomainManga(source.id) }
.let { networkToLocalManga(it) }
return LoadResult.Page(
data = mangasPage.mangas
data = manga
.mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) },
prevKey = null,
nextKey = mangasPage.nextKey,
@@ -5,63 +5,74 @@ 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)
}
}
class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(source) {
class SourcePopularPagingSource(source: CatalogueSource) : BaseSourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source!!.getPopularManga(currentPage)
}
}
class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(source) {
class SourceLatestPagingSource(source: CatalogueSource) : BaseSourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source!!.getLatestUpdates(currentPage)
}
}
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<Long>,
): LoadResult<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */> {
): LoadResult<Long, /*SY --> */ Pair<Manga, RaisedSearchMetadata?>/*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<Long>,
mangasPage: MangasPage,
): LoadResult.Page<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */> {
): LoadResult.Page<Long, /*SY --> */ Pair<Manga, RaisedSearchMetadata?>/*SY <-- */> {
val page = params.key ?: 1
val manga = mangasPage.mangas.map { it.toDomainManga(source!!.id) }
.let { networkToLocalManga(it) }
// SY -->
val metadata = if (mangasPage is MetadataMangasPage) {
mangasPage.mangasMetadata
@@ -71,10 +82,9 @@ abstract class SourcePagingSource(
// SY <--
return LoadResult.Page(
data = mangasPage.mangas
// SY -->
data = manga// SY -->
.mapIndexed { index, sManga -> sManga to metadata.getOrNull(index) },
// SY <--
// SY <--,
prevKey = null,
nextKey = if (mangasPage.hasNextPage) page + 1 else null,
)
@@ -82,7 +92,7 @@ abstract class SourcePagingSource(
// SY <--
override fun getRefreshKey(
state: PagingState<Long, /*SY --> */ Pair<SManga, RaisedSearchMetadata?>/*SY <-- */>,
state: PagingState<Long, /*SY --> */ Pair<Manga, RaisedSearchMetadata?>/*SY <-- */>,
): Long? {
return state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
@@ -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()) {