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:
@@ -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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user