fix(recommendation): Fix null RecommendationSource & refactoring (#1000)
* Remove redundant condition & refactor class * Batch networkToLocalManga * Fix null source * Simplify by creating RecommendationSource to match with upstream * Add comment
This commit is contained in:
parent
9a31ffcc41
commit
6c530e4fca
10 changed files with 87 additions and 58 deletions
|
|
@ -11,7 +11,7 @@ import exh.md.service.MangaDexService
|
|||
import exh.md.service.SimilarService
|
||||
import exh.md.utils.MdLang
|
||||
import exh.recs.sources.RecommendationPagingSource
|
||||
import exh.recs.sources.SourceCatalogue
|
||||
import exh.recs.sources.RecommendationSource
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import tachiyomi.data.source.NoResultsException
|
||||
|
|
@ -26,12 +26,12 @@ import uy.kohesive.injekt.api.get
|
|||
internal class MangaDexSimilarPagingSource(
|
||||
manga: Manga,
|
||||
// KMK -->
|
||||
private val sourceCatalogue: SourceCatalogue,
|
||||
private val recommendationSource: RecommendationSource,
|
||||
// KMK <--
|
||||
) : RecommendationPagingSource(
|
||||
manga,
|
||||
// KMK -->
|
||||
sourceCatalogue.source,
|
||||
recommendationSource,
|
||||
// KMK <--
|
||||
) {
|
||||
|
||||
|
|
@ -43,12 +43,12 @@ internal class MangaDexSimilarPagingSource(
|
|||
|
||||
override val associatedSourceId: Long
|
||||
// KMK -->
|
||||
get() = sourceCatalogue.sourceId
|
||||
get() = recommendationSource.id
|
||||
|
||||
private val client by lazy { Injekt.get<NetworkHelper>().client }
|
||||
|
||||
private val mdLang by lazy {
|
||||
sourceCatalogue.source?.lang?.let { lang ->
|
||||
recommendationSource.lang.let { lang ->
|
||||
MdLang.fromExt(lang)
|
||||
} ?: MdLang.ENGLISH
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ class BrowseRecommendsScreen(
|
|||
} else {
|
||||
// KMK <--
|
||||
val title = remember {
|
||||
val recSource = screenModel.recommendationSource
|
||||
val recSource = screenModel.recommendationPagingSource
|
||||
"${recSource.name} (${recSource.category.getString(context)})"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import cafe.adriel.voyager.core.model.screenModelScope
|
|||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
|
||||
import exh.metadata.metadata.RaisedSearchMetadata
|
||||
import exh.recs.sources.RECOMMENDS_SOURCE
|
||||
import exh.recs.sources.RecommendationPagingSource
|
||||
import exh.recs.sources.SourceCatalogue
|
||||
import exh.recs.sources.RecommendationSource
|
||||
import exh.recs.sources.StaticResultPagingSource
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -40,20 +41,20 @@ class BrowseRecommendsScreenModel(
|
|||
}
|
||||
}
|
||||
|
||||
val recommendationSource: RecommendationPagingSource
|
||||
val recommendationPagingSource: RecommendationPagingSource
|
||||
get() = when (args) {
|
||||
is BrowseRecommendsScreen.Args.MergedSourceMangas -> StaticResultPagingSource(args.results)
|
||||
is BrowseRecommendsScreen.Args.SingleSourceManga -> RecommendationPagingSource.createSources(
|
||||
manga ?: runBlocking(Dispatchers.IO) { getManga.await(args.mangaId)!! },
|
||||
// KMK -->
|
||||
SourceCatalogue(sourceId),
|
||||
RecommendationSource(sourceId),
|
||||
// KMK <--
|
||||
).first {
|
||||
it::class.qualifiedName == args.recommendationSourceName
|
||||
}
|
||||
}
|
||||
|
||||
override fun createSourcePagingSource(query: String, filters: FilterList) = recommendationSource
|
||||
override fun createSourcePagingSource(query: String, filters: FilterList) = recommendationPagingSource
|
||||
|
||||
override fun Flow<Manga>.combineMetadata(metadata: RaisedSearchMetadata?): Flow<Pair<Manga, RaisedSearchMetadata?>> {
|
||||
// Overridden to prevent our custom metadata from being replaced from a cache
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import exh.recs.RecommendsScreen.Args.MergedSourceMangas
|
|||
import exh.recs.RecommendsScreen.Args.SingleSourceManga
|
||||
import exh.recs.batch.RankedSearchResults
|
||||
import exh.recs.components.RecommendsScreen
|
||||
import exh.recs.sources.RECOMMENDS_SOURCE
|
||||
import exh.recs.sources.StaticResultPagingSource
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.sy.SYMR
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ import androidx.compose.runtime.Immutable
|
|||
import androidx.compose.runtime.produceState
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import eu.kanade.presentation.util.ioCoroutineScope
|
||||
import exh.recs.sources.RECOMMENDS_SOURCE
|
||||
import exh.recs.sources.RecommendationPagingSource
|
||||
import exh.recs.sources.SourceCatalogue
|
||||
import exh.recs.sources.RecommendationSource
|
||||
import exh.recs.sources.StaticResultPagingSource
|
||||
import kotlinx.collections.immutable.PersistentMap
|
||||
import kotlinx.collections.immutable.mutate
|
||||
|
|
@ -55,7 +56,7 @@ open class RecommendsScreenModel(
|
|||
RecommendationPagingSource.createSources(
|
||||
manga,
|
||||
// KMK -->
|
||||
SourceCatalogue(args.sourceId),
|
||||
RecommendationSource(args.sourceId),
|
||||
// KMK <--
|
||||
)
|
||||
}
|
||||
|
|
@ -163,5 +164,3 @@ sealed interface RecommendationItemResult {
|
|||
return !onlyShowHasResults || (this is Success && !this.isEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
const val RECOMMENDS_SOURCE = -1L
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import eu.kanade.domain.manga.model.toSManga
|
|||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.log.xLog
|
||||
import exh.recs.sources.RecommendationPagingSource
|
||||
import exh.recs.sources.SourceCatalogue
|
||||
import exh.recs.sources.RecommendationSource
|
||||
import exh.recs.sources.TrackerRecommendationPagingSource
|
||||
import exh.smartsearch.SmartLibrarySearchEngine
|
||||
import exh.util.ThrottleManager
|
||||
|
|
@ -101,7 +101,7 @@ class RecommendationSearchHelper(val context: Context) {
|
|||
val jobs = RecommendationPagingSource.createSources(
|
||||
sourceManga,
|
||||
// KMK -->
|
||||
SourceCatalogue(sourceManga.source),
|
||||
RecommendationSource(sourceManga.source),
|
||||
// KMK <--
|
||||
).mapNotNull { source ->
|
||||
// Apply source filters
|
||||
|
|
@ -198,13 +198,16 @@ class RecommendationSearchHelper(val context: Context) {
|
|||
return this
|
||||
}
|
||||
|
||||
return filterNot { manga ->
|
||||
// Source recommendations can be directly resolved, if the recommendation is from the same source
|
||||
recSource.associatedSourceId?.let { srcId ->
|
||||
return@filterNot networkToLocalManga(manga.toDomainManga(srcId))
|
||||
.let { local -> libraryManga.any { it.id == local.id } }
|
||||
}
|
||||
// KMK -->
|
||||
// Source recommendations can be directly resolved, if the recommendation is from the same source
|
||||
recSource.associatedSourceId?.let { srcId ->
|
||||
return networkToLocalManga(map { it.toDomainManga(srcId) })
|
||||
.filterNot { local -> libraryManga.any { it.id == local.id } }
|
||||
.map { it.toSManga() }
|
||||
}
|
||||
// KMK <--
|
||||
|
||||
return filterNot { manga ->
|
||||
// Tracker recommendations can be resolved by checking if the tracker is attached to the recommendation
|
||||
if (recSource is TrackerRecommendationPagingSource) {
|
||||
recSource.associatedTrackerId?.let { trackerId ->
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import eu.kanade.tachiyomi.network.GET
|
|||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
|
@ -23,17 +22,15 @@ import uy.kohesive.injekt.Injekt
|
|||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
fun CatalogueSource.isComickSource() = name == "Comick"
|
||||
|
||||
internal class ComickPagingSource(
|
||||
manga: Manga,
|
||||
// KMK -->
|
||||
private val sourceCatalogue: SourceCatalogue,
|
||||
private val recommendationSource: RecommendationSource,
|
||||
// KMK <--
|
||||
) : RecommendationPagingSource(
|
||||
manga,
|
||||
// KMK -->
|
||||
sourceCatalogue.source,
|
||||
recommendationSource,
|
||||
// KMK <--
|
||||
) {
|
||||
|
||||
|
|
@ -45,7 +42,7 @@ internal class ComickPagingSource(
|
|||
|
||||
override val associatedSourceId: Long
|
||||
// KMK -->
|
||||
get() = sourceCatalogue.sourceId
|
||||
get() = recommendationSource.id
|
||||
// KMK <--
|
||||
|
||||
private val client by lazy { Injekt.get<NetworkHelper>().client }
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import dev.icerock.moko.resources.StringResource
|
|||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
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.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.md.similar.MangaDexSimilarPagingSource
|
||||
import exh.pref.DelegateSourcePreferences
|
||||
import exh.source.COMICK_IDS
|
||||
import exh.source.MANGADEX_IDS
|
||||
import exh.source.isMdBasedSource
|
||||
import kotlinx.serialization.json.Json
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.common.util.system.logcat
|
||||
|
|
@ -29,7 +29,9 @@ import uy.kohesive.injekt.injectLazy
|
|||
*/
|
||||
abstract class RecommendationPagingSource(
|
||||
protected val manga: Manga,
|
||||
source: CatalogueSource? = null,
|
||||
// KMK -->
|
||||
source: RecommendationSource = RecommendationSource(),
|
||||
// KMK <--
|
||||
) : BaseSourcePagingSource(source) {
|
||||
// Display name
|
||||
abstract val name: String
|
||||
|
|
@ -49,12 +51,9 @@ abstract class RecommendationPagingSource(
|
|||
internal fun createSources(
|
||||
manga: Manga,
|
||||
// KMK -->
|
||||
sourceCatalogue: SourceCatalogue,
|
||||
recommendationSource: RecommendationSource,
|
||||
// KMK <--
|
||||
): List<RecommendationPagingSource> {
|
||||
// KMK -->
|
||||
val source = sourceCatalogue.source
|
||||
// KMK <--
|
||||
return buildList {
|
||||
add(AniListPagingSource(manga))
|
||||
add(MangaUpdatesCommunityPagingSource(manga))
|
||||
|
|
@ -64,16 +63,14 @@ abstract class RecommendationPagingSource(
|
|||
// Only include MangaDex if the delegate sources are enabled and the source is MD-based
|
||||
if (
|
||||
// KMK -->
|
||||
sourceCatalogue.isMangaDexSource() ||
|
||||
recommendationSource.isMangaDexSource()
|
||||
// KMK <--
|
||||
source?.isMdBasedSource() /* KMK --> */ == true /* KMK <-- */ &&
|
||||
Injekt.get<DelegateSourcePreferences>().delegateSources().get()
|
||||
) {
|
||||
add(
|
||||
MangaDexSimilarPagingSource(
|
||||
manga,
|
||||
// KMK -->
|
||||
sourceCatalogue,
|
||||
recommendationSource,
|
||||
// KMK <--
|
||||
),
|
||||
)
|
||||
|
|
@ -82,15 +79,14 @@ abstract class RecommendationPagingSource(
|
|||
// Only include Comick if the source manga is from there
|
||||
if (
|
||||
// KMK -->
|
||||
sourceCatalogue.isComickSource() ||
|
||||
recommendationSource.isComickSource()
|
||||
// KMK <--
|
||||
source?.isComickSource() /* KMK --> */ == true /* KMK <-- */
|
||||
) {
|
||||
add(
|
||||
ComickPagingSource(
|
||||
manga,
|
||||
// KMK -->
|
||||
sourceCatalogue,
|
||||
recommendationSource,
|
||||
// KMK <--
|
||||
),
|
||||
)
|
||||
|
|
@ -151,15 +147,45 @@ abstract class TrackerRecommendationPagingSource(
|
|||
}
|
||||
|
||||
// KMK -->
|
||||
internal class SourceCatalogue(
|
||||
internal val sourceId: Long,
|
||||
class RecommendationSource(
|
||||
override val id: Long = RECOMMENDS_SOURCE,
|
||||
sourceManager: SourceManager = Injekt.get(),
|
||||
) {
|
||||
val source = sourceManager.get(sourceId)
|
||||
?.let { it as CatalogueSource }
|
||||
) : CatalogueSource {
|
||||
private val delegate by lazy {
|
||||
sourceManager.get(id)
|
||||
?.let { it as CatalogueSource }
|
||||
}
|
||||
|
||||
fun isComickSource(): Boolean = sourceId in COMICK_IDS
|
||||
fun isComickSource(): Boolean = id in COMICK_IDS
|
||||
fun isMangaDexSource(): Boolean = id in MANGADEX_IDS
|
||||
|
||||
fun isMangaDexSource(): Boolean = sourceId in MANGADEX_IDS
|
||||
override val name: String by lazy { delegate?.name ?: "Recommends Source" }
|
||||
override val lang: String by lazy { delegate?.lang ?: "all" }
|
||||
override val supportsLatest by lazy { delegate?.supportsLatest ?: false }
|
||||
|
||||
override suspend fun getMangaDetails(manga: SManga) =
|
||||
delegate?.getMangaDetails(manga)
|
||||
?: throw UnsupportedOperationException()
|
||||
override suspend fun getChapterList(manga: SManga) =
|
||||
delegate?.getChapterList(manga)
|
||||
?: throw UnsupportedOperationException()
|
||||
override suspend fun getPageList(chapter: SChapter) =
|
||||
delegate?.getPageList(chapter)
|
||||
?: throw UnsupportedOperationException()
|
||||
|
||||
override suspend fun getPopularManga(page: Int) =
|
||||
delegate?.getPopularManga(page)
|
||||
?: throw UnsupportedOperationException()
|
||||
override suspend fun getLatestUpdates(page: Int) =
|
||||
delegate?.getLatestUpdates(page)
|
||||
?: throw UnsupportedOperationException()
|
||||
override suspend fun getSearchManga(page: Int, query: String, filters: FilterList) =
|
||||
delegate?.getSearchManga(page, query, filters)
|
||||
?: throw UnsupportedOperationException()
|
||||
override fun getFilterList() =
|
||||
delegate?.getFilterList()
|
||||
?: throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
const val RECOMMENDS_SOURCE = -1L
|
||||
// KMK <--
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ abstract class EHentaiPagingSource(
|
|||
val metadata = mangasPage.mangasMetadata
|
||||
|
||||
val manga = mangasPage.mangas
|
||||
.mapIndexed { index, sManga -> sManga.toDomainManga(source!!.id) to metadata.getOrNull(index) }
|
||||
.mapIndexed { index, sManga -> sManga.toDomainManga(source.id) to metadata.getOrNull(index) }
|
||||
.filter { seenManga.add(it.first.url) }
|
||||
// KMK -->
|
||||
.let { pairs -> networkToLocalManga(pairs.map { it.first }).zip(pairs.map { it.second }) }
|
||||
|
|
@ -41,18 +41,18 @@ class EHentaiSearchPagingSource(
|
|||
val filters: FilterList,
|
||||
) : EHentaiPagingSource(source) {
|
||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||
return source!!.getSearchManga(currentPage, query.sanitize(), filters)
|
||||
return source.getSearchManga(currentPage, query.sanitize(), filters)
|
||||
}
|
||||
}
|
||||
|
||||
class EHentaiPopularPagingSource(source: CatalogueSource) : EHentaiPagingSource(source) {
|
||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||
return source!!.getPopularManga(currentPage)
|
||||
return source.getPopularManga(currentPage)
|
||||
}
|
||||
}
|
||||
|
||||
class EHentaiLatestPagingSource(source: CatalogueSource) : EHentaiPagingSource(source) {
|
||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||
return source!!.getLatestUpdates(currentPage)
|
||||
return source.getLatestUpdates(currentPage)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ 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 exh.log.xLogE
|
||||
import exh.metadata.metadata.RaisedSearchMetadata
|
||||
import mihon.domain.manga.model.toDomainManga
|
||||
import tachiyomi.core.common.util.QuerySanitizer.sanitize
|
||||
|
|
@ -21,24 +22,24 @@ class SourceSearchPagingSource(
|
|||
private val filters: FilterList,
|
||||
) : BaseSourcePagingSource(source) {
|
||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||
return source!!.getSearchManga(currentPage, query.sanitize(), filters)
|
||||
return source.getSearchManga(currentPage, query.sanitize(), filters)
|
||||
}
|
||||
}
|
||||
|
||||
class SourcePopularPagingSource(source: CatalogueSource) : BaseSourcePagingSource(source) {
|
||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||
return source!!.getPopularManga(currentPage)
|
||||
return source.getPopularManga(currentPage)
|
||||
}
|
||||
}
|
||||
|
||||
class SourceLatestPagingSource(source: CatalogueSource) : BaseSourcePagingSource(source) {
|
||||
override suspend fun requestNextPage(currentPage: Int): MangasPage {
|
||||
return source!!.getLatestUpdates(currentPage)
|
||||
return source.getLatestUpdates(currentPage)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BaseSourcePagingSource(
|
||||
protected val source: CatalogueSource?,
|
||||
protected val source: CatalogueSource,
|
||||
protected val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
|
||||
) : SourcePagingSource() {
|
||||
|
||||
|
|
@ -62,6 +63,7 @@ abstract class BaseSourcePagingSource(
|
|||
getPageLoadResult(params, mangasPage)
|
||||
// SY <--
|
||||
} catch (e: Exception) {
|
||||
xLogE("${this::class.simpleName}: Failed to load paging source", e)
|
||||
LoadResult.Error(e)
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +85,7 @@ abstract class BaseSourcePagingSource(
|
|||
|
||||
val manga = mangasPage.mangas
|
||||
// SY -->
|
||||
.mapIndexed { index, sManga -> sManga.toDomainManga(source!!.id) to metadata.getOrNull(index) }
|
||||
.mapIndexed { index, sManga -> sManga.toDomainManga(source.id) to metadata.getOrNull(index) }
|
||||
.filter { seenManga.add(it.first.url) }
|
||||
// KMK -->
|
||||
.let { pairs -> networkToLocalManga(pairs.map { it.first }).zip(pairs.map { it.second }) }
|
||||
|
|
|
|||
Loading…
Reference in a new issue