HeanCms: Fix Search (#14843)
* Fix Search * Fix Search * Fix Search * Apply requested changes * Apply requested changes * Apply requested changes * Apply requested changes * Apply requested changes
This commit is contained in:
parent
9c000859b9
commit
c0a6c67cfd
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.multisrc.heancms
|
|||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
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.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
@ -41,14 +42,14 @@ abstract class HeanCms(
|
|||||||
|
|
||||||
protected open val coverPath: String = "cover/"
|
protected open val coverPath: String = "cover/"
|
||||||
|
|
||||||
private var seriesSlugMap: Map<String, String>? = null
|
private var seriesSlugMap: Map<String, HeanCmsTitle>? = null
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||||
.add("Origin", baseUrl)
|
.add("Origin", baseUrl)
|
||||||
.add("Referer", "$baseUrl/")
|
.add("Referer", "$baseUrl/")
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
val payloadObj = HeanCmsSearchPayloadDto(
|
val payloadObj = HeanCmsQuerySearchPayloadDto(
|
||||||
page = page,
|
page = page,
|
||||||
order = "desc",
|
order = "desc",
|
||||||
orderBy = "total_views",
|
orderBy = "total_views",
|
||||||
@ -70,7 +71,7 @@ abstract class HeanCms(
|
|||||||
val json = response.body?.string().orEmpty()
|
val json = response.body?.string().orEmpty()
|
||||||
|
|
||||||
if (json.startsWith("{")) {
|
if (json.startsWith("{")) {
|
||||||
val result = json.parseAs<HeanCmsSearchDto>()
|
val result = json.parseAs<HeanCmsQuerySearchDto>()
|
||||||
val mangaList = result.data.map { it.toSManga(apiUrl, coverPath) }
|
val mangaList = result.data.map { it.toSManga(apiUrl, coverPath) }
|
||||||
|
|
||||||
fetchAllTitles()
|
fetchAllTitles()
|
||||||
@ -87,7 +88,7 @@ abstract class HeanCms(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
val payloadObj = HeanCmsSearchPayloadDto(
|
val payloadObj = HeanCmsQuerySearchPayloadDto(
|
||||||
page = page,
|
page = page,
|
||||||
order = "desc",
|
order = "desc",
|
||||||
orderBy = "latest",
|
orderBy = "latest",
|
||||||
@ -110,7 +111,7 @@ abstract class HeanCms(
|
|||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
val sortByFilter = filters.firstInstanceOrNull<SortByFilter>()
|
val sortByFilter = filters.firstInstanceOrNull<SortByFilter>()
|
||||||
|
|
||||||
val payloadObj = HeanCmsSearchPayloadDto(
|
val payloadObj = HeanCmsQuerySearchPayloadDto(
|
||||||
page = page,
|
page = page,
|
||||||
order = if (sortByFilter?.state?.ascending == true) "asc" else "desc",
|
order = if (sortByFilter?.state?.ascending == true) "asc" else "desc",
|
||||||
orderBy = sortByFilter?.selected ?: "total_views",
|
orderBy = sortByFilter?.selected ?: "total_views",
|
||||||
@ -122,15 +123,25 @@ abstract class HeanCms(
|
|||||||
.orEmpty()
|
.orEmpty()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val searchPayloadObj = HeanCmsSearchPayloadDto(
|
||||||
|
term = query
|
||||||
|
)
|
||||||
|
|
||||||
val payload = json.encodeToString(payloadObj).toRequestBody(JSON_MEDIA_TYPE)
|
val payload = json.encodeToString(payloadObj).toRequestBody(JSON_MEDIA_TYPE)
|
||||||
|
val searchPayload = json.encodeToString(searchPayloadObj).toRequestBody(JSON_MEDIA_TYPE)
|
||||||
|
|
||||||
val apiHeaders = headersBuilder()
|
val apiHeaders = headersBuilder()
|
||||||
.add("Accept", ACCEPT_JSON)
|
.add("Accept", ACCEPT_JSON)
|
||||||
.add("Content-Type", payload.contentType().toString())
|
.add("Content-Type", payload.contentType().toString())
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
if (query.isNotBlank()) {
|
||||||
|
val apiUrl = "$apiUrl/series/search".toHttpUrl().newBuilder()
|
||||||
|
.toString()
|
||||||
|
return POST(apiUrl, apiHeaders, searchPayload)
|
||||||
|
}
|
||||||
|
|
||||||
val apiUrl = "$apiUrl/series/querysearch".toHttpUrl().newBuilder()
|
val apiUrl = "$apiUrl/series/querysearch".toHttpUrl().newBuilder()
|
||||||
.addQueryParameter("q", query)
|
|
||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
return POST(apiUrl, apiHeaders, payload)
|
return POST(apiUrl, apiHeaders, payload)
|
||||||
@ -138,33 +149,54 @@ abstract class HeanCms(
|
|||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
override fun searchMangaParse(response: Response): MangasPage {
|
||||||
val json = response.body?.string().orEmpty()
|
val json = response.body?.string().orEmpty()
|
||||||
val query = response.request.url.queryParameter("q").orEmpty()
|
|
||||||
|
if (response.request.url.pathSegments.last() == "search") {
|
||||||
|
val result = json.parseAs<List<HeanCmsSearchDto>>()
|
||||||
|
val mangaList = result
|
||||||
|
.filter { it.type == "Comic" }
|
||||||
|
.map {
|
||||||
|
createSearchResult(it.slug.replace(TIMESTAMP_REGEX, ""), it.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchAllTitles()
|
||||||
|
|
||||||
|
return MangasPage(mangaList, false)
|
||||||
|
}
|
||||||
|
|
||||||
if (json.startsWith("{")) {
|
if (json.startsWith("{")) {
|
||||||
val result = json.parseAs<HeanCmsSearchDto>()
|
val result = json.parseAs<HeanCmsQuerySearchDto>()
|
||||||
var mangaList = result.data.map { it.toSManga(apiUrl, coverPath) }
|
val mangaList = result.data.map { it.toSManga(apiUrl, coverPath) }
|
||||||
|
|
||||||
if (query.isNotBlank()) {
|
|
||||||
mangaList = mangaList.filter { it.title.contains(query, ignoreCase = true) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchAllTitles()
|
fetchAllTitles()
|
||||||
|
|
||||||
return MangasPage(mangaList, result.meta?.hasNextPage ?: false)
|
return MangasPage(mangaList, result.meta?.hasNextPage ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
var mangaList = json.parseAs<List<HeanCmsSeriesDto>>()
|
val mangaList = json.parseAs<List<HeanCmsSeriesDto>>()
|
||||||
.map { it.toSManga(apiUrl, coverPath) }
|
.map { it.toSManga(apiUrl, coverPath) }
|
||||||
|
|
||||||
if (query.isNotBlank()) {
|
|
||||||
mangaList = mangaList.filter { it.title.contains(query, ignoreCase = true) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchAllTitles()
|
fetchAllTitles()
|
||||||
|
|
||||||
return MangasPage(mangaList, hasNextPage = false)
|
return MangasPage(mangaList, hasNextPage = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createSearchResult(slug: String, title: String): SManga {
|
||||||
|
val theSeries = seriesSlugMap?.get(slug)
|
||||||
|
|
||||||
|
return SManga.create().apply {
|
||||||
|
url = "/series/$slug"
|
||||||
|
this.title = title
|
||||||
|
thumbnail_url = "$apiUrl/$coverPath${theSeries?.thumbnailUrl}"
|
||||||
|
this.status = when (theSeries?.status) {
|
||||||
|
"Ongoing" -> SManga.ONGOING
|
||||||
|
"Hiatus" -> SManga.ON_HIATUS
|
||||||
|
"Dropped" -> SManga.CANCELLED
|
||||||
|
"Completed", "Finished" -> SManga.COMPLETED
|
||||||
|
else -> SManga.UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Workaround to allow "Open in browser" use the real URL.
|
// Workaround to allow "Open in browser" use the real URL.
|
||||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||||
return client.newCall(seriesDetailsRequest(manga))
|
return client.newCall(seriesDetailsRequest(manga))
|
||||||
@ -179,7 +211,7 @@ abstract class HeanCms(
|
|||||||
.substringAfterLast("/")
|
.substringAfterLast("/")
|
||||||
.replace(TIMESTAMP_REGEX, "")
|
.replace(TIMESTAMP_REGEX, "")
|
||||||
|
|
||||||
val currentSlug = seriesSlugMap?.get(seriesSlug) ?: seriesSlug
|
val currentSlug = seriesSlugMap?.get(seriesSlug)?.slug ?: seriesSlug
|
||||||
|
|
||||||
return GET("$baseUrl/series/$currentSlug", headers)
|
return GET("$baseUrl/series/$currentSlug", headers)
|
||||||
}
|
}
|
||||||
@ -191,7 +223,7 @@ abstract class HeanCms(
|
|||||||
|
|
||||||
fetchAllTitles()
|
fetchAllTitles()
|
||||||
|
|
||||||
val currentSlug = seriesSlugMap?.get(seriesSlug) ?: seriesSlug
|
val currentSlug = seriesSlugMap?.get(seriesSlug)?.slug ?: seriesSlug
|
||||||
|
|
||||||
val apiHeaders = headersBuilder()
|
val apiHeaders = headersBuilder()
|
||||||
.add("Accept", ACCEPT_JSON)
|
.add("Accept", ACCEPT_JSON)
|
||||||
@ -271,14 +303,14 @@ abstract class HeanCms(
|
|||||||
val result = runCatching {
|
val result = runCatching {
|
||||||
var hasNextPage = true
|
var hasNextPage = true
|
||||||
var page = 1
|
var page = 1
|
||||||
val tempMap = mutableMapOf<String, String>()
|
val tempMap = mutableMapOf<String, HeanCmsTitle>()
|
||||||
|
|
||||||
while (hasNextPage) {
|
while (hasNextPage) {
|
||||||
val response = client.newCall(allTitlesRequest(page)).execute()
|
val response = client.newCall(allTitlesRequest(page)).execute()
|
||||||
val json = response.body?.string().orEmpty()
|
val json = response.body?.string().orEmpty()
|
||||||
|
|
||||||
if (json.startsWith("{")) {
|
if (json.startsWith("{")) {
|
||||||
val result = json.parseAs<HeanCmsSearchDto>()
|
val result = json.parseAs<HeanCmsQuerySearchDto>()
|
||||||
tempMap.putAll(parseAllTitles(result.data))
|
tempMap.putAll(parseAllTitles(result.data))
|
||||||
hasNextPage = result.meta?.hasNextPage ?: false
|
hasNextPage = result.meta?.hasNextPage ?: false
|
||||||
page++
|
page++
|
||||||
@ -296,7 +328,7 @@ abstract class HeanCms(
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected open fun allTitlesRequest(page: Int): Request {
|
protected open fun allTitlesRequest(page: Int): Request {
|
||||||
val payloadObj = HeanCmsSearchPayloadDto(
|
val payloadObj = HeanCmsQuerySearchPayloadDto(
|
||||||
page = page,
|
page = page,
|
||||||
order = "desc",
|
order = "desc",
|
||||||
orderBy = "total_views",
|
orderBy = "total_views",
|
||||||
@ -314,12 +346,18 @@ abstract class HeanCms(
|
|||||||
return POST("$apiUrl/series/querysearch", apiHeaders, payload)
|
return POST("$apiUrl/series/querysearch", apiHeaders, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun parseAllTitles(result: List<HeanCmsSeriesDto>): Map<String, String> {
|
protected open fun parseAllTitles(result: List<HeanCmsSeriesDto>): Map<String, HeanCmsTitle> {
|
||||||
return result
|
return result
|
||||||
.filter { it.type == "Comic" }
|
.filter { it.type == "Comic" }
|
||||||
.associateBy(
|
.associateBy(
|
||||||
keySelector = { it.slug.replace(TIMESTAMP_REGEX, "") },
|
keySelector = { it.slug.replace(TIMESTAMP_REGEX, "") },
|
||||||
valueTransform = HeanCmsSeriesDto::slug
|
valueTransform = {
|
||||||
|
HeanCmsTitle(
|
||||||
|
it.slug,
|
||||||
|
it.thumbnail,
|
||||||
|
it.status.orEmpty()
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,6 +365,7 @@ abstract class HeanCms(
|
|||||||
val genres = getGenreList()
|
val genres = getGenreList()
|
||||||
|
|
||||||
val filters = listOfNotNull(
|
val filters = listOfNotNull(
|
||||||
|
Filter.Header(intl.filterWarning),
|
||||||
StatusFilter(intl.statusFilterTitle, getStatusList()),
|
StatusFilter(intl.statusFilterTitle, getStatusList()),
|
||||||
SortByFilter(intl.sortByFilterTitle, getSortProperties()),
|
SortByFilter(intl.sortByFilterTitle, getSortProperties()),
|
||||||
GenreFilter(intl.genreFilterTitle, genres).takeIf { genres.isNotEmpty() }
|
GenreFilter(intl.genreFilterTitle, genres).takeIf { genres.isNotEmpty() }
|
||||||
@ -352,4 +391,10 @@ abstract class HeanCms(
|
|||||||
|
|
||||||
val TIMESTAMP_REGEX = "-\\d+$".toRegex()
|
val TIMESTAMP_REGEX = "-\\d+$".toRegex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class HeanCmsTitle(
|
||||||
|
val slug: String,
|
||||||
|
val thumbnailUrl: String,
|
||||||
|
val status: String
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,13 @@ import java.text.SimpleDateFormat
|
|||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class HeanCmsSearchDto(
|
data class HeanCmsQuerySearchDto(
|
||||||
val data: List<HeanCmsSeriesDto> = emptyList(),
|
val data: List<HeanCmsSeriesDto> = emptyList(),
|
||||||
val meta: HeanCmsSearchMetaDto? = null
|
val meta: HeanCmsQuerySearchMetaDto? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class HeanCmsSearchMetaDto(
|
data class HeanCmsQuerySearchMetaDto(
|
||||||
@SerialName("current_page") val currentPage: Int,
|
@SerialName("current_page") val currentPage: Int,
|
||||||
@SerialName("last_page") val lastPage: Int
|
@SerialName("last_page") val lastPage: Int
|
||||||
) {
|
) {
|
||||||
@ -24,6 +24,14 @@ data class HeanCmsSearchMetaDto(
|
|||||||
get() = currentPage < lastPage
|
get() = currentPage < lastPage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HeanCmsSearchDto(
|
||||||
|
val description: String? = null,
|
||||||
|
@SerialName("series_slug") val slug: String,
|
||||||
|
@SerialName("series_type") val type: String,
|
||||||
|
val title: String
|
||||||
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class HeanCmsSeriesDto(
|
data class HeanCmsSeriesDto(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
@ -100,7 +108,7 @@ data class HeanCmsReaderContentDto(
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class HeanCmsSearchPayloadDto(
|
data class HeanCmsQuerySearchPayloadDto(
|
||||||
val order: String,
|
val order: String,
|
||||||
val page: Int,
|
val page: Int,
|
||||||
@SerialName("order_by") val orderBy: String,
|
@SerialName("order_by") val orderBy: String,
|
||||||
@ -108,3 +116,8 @@ data class HeanCmsSearchPayloadDto(
|
|||||||
@SerialName("series_type") val type: String,
|
@SerialName("series_type") val type: String,
|
||||||
@SerialName("tags_ids") val tagIds: List<Int> = emptyList()
|
@SerialName("tags_ids") val tagIds: List<Int> = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HeanCmsSearchPayloadDto(
|
||||||
|
val term: String,
|
||||||
|
)
|
||||||
|
@ -9,7 +9,7 @@ class HeanCmsGenerator : ThemeSourceGenerator {
|
|||||||
|
|
||||||
override val themeClass = "HeanCms"
|
override val themeClass = "HeanCms"
|
||||||
|
|
||||||
override val baseVersionCode: Int = 6
|
override val baseVersionCode: Int = 7
|
||||||
|
|
||||||
override val sources = listOf(
|
override val sources = listOf(
|
||||||
SingleLang("Reaper Scans", "https://reaperscans.net", "pt-BR", overrideVersionCode = 35),
|
SingleLang("Reaper Scans", "https://reaperscans.net", "pt-BR", overrideVersionCode = 35),
|
||||||
|
@ -64,6 +64,12 @@ class HeanCmsIntl(lang: String) {
|
|||||||
else -> "Recently added"
|
else -> "Recently added"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val filterWarning: String = when (availableLang) {
|
||||||
|
BRAZILIAN_PORTUGUESE -> "Os filtros serão ignorados se a busca não estiver vazia."
|
||||||
|
SPANISH -> "Los filtros serán ignorados si la búsqueda no está vacía."
|
||||||
|
else -> "Filters will be ignored if the search is not empty."
|
||||||
|
}
|
||||||
|
|
||||||
fun urlChangedError(sourceName: String): String = when (availableLang) {
|
fun urlChangedError(sourceName: String): String = when (availableLang) {
|
||||||
BRAZILIAN_PORTUGUESE ->
|
BRAZILIAN_PORTUGUESE ->
|
||||||
"A URL da série mudou. Migre de $sourceName " +
|
"A URL da série mudou. Migre de $sourceName " +
|
||||||
|
Loading…
x
Reference in New Issue
Block a user