using search to enable all extensions’ related mangas
This commit is contained in:
parent
89f8723d7e
commit
0cf256ccce
4 changed files with 74 additions and 19 deletions
|
|
@ -1109,7 +1109,7 @@ class MangaScreenModel(
|
|||
try {
|
||||
withIOContext {
|
||||
if (state.source !is MergedSource) {
|
||||
val relatedMangas = if (state.source.supportsRelatedMangas)
|
||||
val relatedMangas = if (true)//state.source.supportsRelatedMangas)
|
||||
withIOContext {
|
||||
state.source.getRelatedMangaList(state.manga.toSManga())
|
||||
.map {
|
||||
|
|
|
|||
|
|
@ -49,13 +49,6 @@ interface Source {
|
|||
}
|
||||
|
||||
// KMK -->
|
||||
/**
|
||||
* Whether the source has support for related mangas.
|
||||
*
|
||||
* @since extensions-lib 1.6
|
||||
*/
|
||||
val supportsRelatedMangas: Boolean get() = false
|
||||
|
||||
/**
|
||||
* Get all the available related mangas for a manga.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||
import exh.log.maybeInjectEHLogger
|
||||
import exh.pref.DelegateSourcePreferences
|
||||
import exh.source.DelegatedHttpSource
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
|
@ -27,6 +31,7 @@ import uy.kohesive.injekt.api.get
|
|||
import java.net.URI
|
||||
import java.net.URISyntaxException
|
||||
import java.security.MessageDigest
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* A simple implementation for sources from a website.
|
||||
|
|
@ -275,6 +280,14 @@ abstract class HttpSource : CatalogueSource {
|
|||
protected abstract fun mangaDetailsParse(response: Response): SManga
|
||||
|
||||
// KMK -->
|
||||
/**
|
||||
* Whether parsing related mangas in manga page or extension provide custom related mangas request (true)
|
||||
* or using search keyword to search for related mangas (false - default)
|
||||
* @default false
|
||||
* @since extensions-lib 1.6
|
||||
*/
|
||||
protected open val supportsRelatedMangas: Boolean get() = false
|
||||
|
||||
/**
|
||||
* Get all the available related mangas for a manga.
|
||||
* Normally it's not needed to override this method.
|
||||
|
|
@ -285,9 +298,60 @@ abstract class HttpSource : CatalogueSource {
|
|||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
override suspend fun getRelatedMangaList(manga: SManga): List<SManga> {
|
||||
return fetchRelatedMangaList(manga).awaitSingle()
|
||||
return if (supportsRelatedMangas)
|
||||
fetchRelatedMangaList(manga).awaitSingle()
|
||||
else
|
||||
return fetchRelatedMangaListBySearch(manga)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch related mangas by searching for each keywords from manga's title
|
||||
*/
|
||||
protected open suspend fun fetchRelatedMangaListBySearch(manga: SManga): List<SManga> {
|
||||
fun String.stripKeyword(): List<String> {
|
||||
val regexWhitespace = Regex("\\s+")
|
||||
// remove special character
|
||||
return replace(Regex("[\\[(!~@#$%^&*|,?:\"<>)\\]]"), " ")
|
||||
.split(regexWhitespace)
|
||||
.map {
|
||||
// remove number only
|
||||
it.replace(Regex("^\\d+$"), "")
|
||||
.lowercase(Locale.getDefault())
|
||||
}
|
||||
// exclude single character
|
||||
.filter { it.length > 1 }
|
||||
}
|
||||
val scope = CoroutineScope(Dispatchers.IO)
|
||||
val words = HashSet<String>()
|
||||
words += manga.title.stripKeyword()
|
||||
manga.originalTitle.let { title ->
|
||||
words += title.stripKeyword()
|
||||
}
|
||||
if (words.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
val results = words.map { keyword ->
|
||||
scope.async {
|
||||
client.newCall(searchMangaRequest(0, keyword, FilterList()))
|
||||
.execute()
|
||||
.let { response ->
|
||||
searchMangaParse(response).mangas
|
||||
.filter {
|
||||
it.url != manga.url &&
|
||||
it.title.lowercase().contains(keyword)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.awaitAll()
|
||||
.minBy { if (it.isEmpty()) Int.MAX_VALUE else it.size }
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch related mangas found in manga's page which is provided by sites.
|
||||
* If using this, must also: 'override val supportsRelatedMangas = true'
|
||||
*/
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getRelatedMangaList"))
|
||||
override fun fetchRelatedMangaList(manga: SManga): Observable<List<SManga>> {
|
||||
return client.newCall(relatedMangaListRequest(manga))
|
||||
|
|
@ -300,6 +364,7 @@ abstract class HttpSource : CatalogueSource {
|
|||
/**
|
||||
* Returns the request for get related manga list. Override only if it's needed to override
|
||||
* the url, send different headers or request method like POST.
|
||||
* If using this, must also: 'override val supportsRelatedMangas = true'
|
||||
*
|
||||
* @param manga the manga to look for related mangas.
|
||||
*/
|
||||
|
|
@ -309,17 +374,11 @@ abstract class HttpSource : CatalogueSource {
|
|||
|
||||
/**
|
||||
* Parses the response from the site and returns a list of related mangas.
|
||||
* If using this, must also: 'override val supportsRelatedMangas = true'
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
protected open fun relatedMangaListParse(response: Response): List<SManga> = throw UnsupportedOperationException()
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a SManga Object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
protected open fun relatedMangaPageParse(response: Response): SManga = throw UnsupportedOperationException()
|
||||
protected open fun relatedMangaListParse(response: Response): List<SManga> = popularMangaParse(response).mangas
|
||||
// KMK <--
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -148,21 +148,24 @@ abstract class ParsedHttpSource : HttpSource() {
|
|||
// KMK -->
|
||||
/**
|
||||
* Parses the response from the site and returns a list of related mangas.
|
||||
* If using this, must also: 'override val supportsRelatedMangas = true'
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun relatedMangaListParse(response: Response): List<SManga> {
|
||||
val document = response.asJsoup()
|
||||
return document.select(relatedMangaListSelector()).map { relatedMangaFromElement(it) }
|
||||
return response.asJsoup()
|
||||
.select(relatedMangaListSelector()).map { relatedMangaFromElement(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each related mangas.
|
||||
* If using this, must also: 'override val supportsRelatedMangas = true'
|
||||
*/
|
||||
protected open fun relatedMangaListSelector(): String = popularMangaSelector()
|
||||
|
||||
/**
|
||||
* Returns a manga from the given element.
|
||||
* If using this, must also: 'override val supportsRelatedMangas = true'
|
||||
*
|
||||
* @param element an element obtained from [relatedMangaListSelector].
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue