From 2bb71b034dc223a5d92f2c66d547156b92fbefc6 Mon Sep 17 00:00:00 2001 From: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> Date: Tue, 10 Jan 2023 17:19:02 -0300 Subject: [PATCH] Refactor and fix some issues in HeanCms. (#14887) Co-authored-by: Seew <90949336+seew3l@users.noreply.github.com> --- .../tachiyomi/multisrc/heancms/HeanCms.kt | 89 ++++++++----------- .../tachiyomi/multisrc/heancms/HeanCmsDto.kt | 39 +++++--- .../multisrc/heancms/HeanCmsGenerator.kt | 2 +- 3 files changed, 68 insertions(+), 62 deletions(-) diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCms.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCms.kt index c1c3f6e34..245326766 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCms.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCms.kt @@ -14,7 +14,6 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import okhttp3.Headers -import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request @@ -109,6 +108,23 @@ abstract class HeanCms( override fun latestUpdatesParse(response: Response): MangasPage = popularMangaParse(response) override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + /** + * Their query search endpoint doesn't return the thumbnails, so we need to do + * later an special parsing to get the thumbnails as well from the slug map. + */ + if (query.isNotBlank()) { + val searchPayloadObj = HeanCmsSearchPayloadDto(query) + val searchPayload = json.encodeToString(searchPayloadObj) + .toRequestBody(JSON_MEDIA_TYPE) + + val apiHeaders = headersBuilder() + .add("Accept", ACCEPT_JSON) + .add("Content-Type", searchPayload.contentType().toString()) + .build() + + return POST("$apiUrl/series/search", apiHeaders, searchPayload) + } + val sortByFilter = filters.firstInstanceOrNull() val payloadObj = HeanCmsQuerySearchPayloadDto( @@ -123,42 +139,26 @@ abstract class HeanCms( .orEmpty() ) - val searchPayloadObj = HeanCmsSearchPayloadDto( - term = query - ) - val payload = json.encodeToString(payloadObj).toRequestBody(JSON_MEDIA_TYPE) - val searchPayload = json.encodeToString(searchPayloadObj).toRequestBody(JSON_MEDIA_TYPE) val apiHeaders = headersBuilder() .add("Accept", ACCEPT_JSON) .add("Content-Type", payload.contentType().toString()) .build() - if (query.isNotBlank()) { - val apiUrl = "$apiUrl/series/search".toHttpUrl().newBuilder() - .toString() - return POST(apiUrl, apiHeaders, searchPayload) - } - - val apiUrl = "$apiUrl/series/querysearch".toHttpUrl().newBuilder() - .toString() - - return POST(apiUrl, apiHeaders, payload) + return POST("$apiUrl/series/querysearch", apiHeaders, payload) } override fun searchMangaParse(response: Response): MangasPage { val json = response.body?.string().orEmpty() if (response.request.url.pathSegments.last() == "search") { + fetchAllTitles() + val result = json.parseAs>() val mangaList = result .filter { it.type == "Comic" } - .map { - createSearchResult(it.slug.replace(TIMESTAMP_REGEX, ""), it.title) - } - - fetchAllTitles() + .map { it.toSManga(apiUrl, coverPath, seriesSlugMap.orEmpty()) } return MangasPage(mangaList, false) } @@ -180,23 +180,6 @@ abstract class HeanCms( 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. override fun fetchMangaDetails(manga: SManga): Observable { return client.newCall(seriesDetailsRequest(manga)) @@ -223,13 +206,15 @@ abstract class HeanCms( fetchAllTitles() - val currentSlug = seriesSlugMap?.get(seriesSlug)?.slug ?: seriesSlug + val seriesDetails = seriesSlugMap?.get(seriesSlug) + val currentSlug = seriesDetails?.slug ?: seriesSlug + val currentStatus = seriesDetails?.status ?: SManga.UNKNOWN val apiHeaders = headersBuilder() .add("Accept", ACCEPT_JSON) .build() - return GET("$apiUrl/series/$currentSlug#${manga.status}", apiHeaders) + return GET("$apiUrl/series/$currentSlug#$currentStatus", apiHeaders) } override fun mangaDetailsParse(response: Response): SManga { @@ -247,9 +232,11 @@ abstract class HeanCms( override fun chapterListParse(response: Response): List { val result = response.parseAs() val seriesSlug = response.request.url.pathSegments.last() + val currentTimestamp = System.currentTimeMillis() return result.chapters.orEmpty() .map { it.toSChapter(seriesSlug) } + .filter { it.date_upload <= currentTimestamp } .reversed() } @@ -265,7 +252,9 @@ abstract class HeanCms( override fun pageListParse(response: Response): List { return response.parseAs().content?.images.orEmpty() - .mapIndexed { i, url -> Page(i, "", "$apiUrl/$url") } + .mapIndexed { i, url -> + Page(i, imageUrl = if (url.startsWith("http")) url else "$apiUrl/$url") + } } override fun fetchImageUrl(page: Page): Observable = Observable.just(page.imageUrl!!) @@ -353,9 +342,9 @@ abstract class HeanCms( keySelector = { it.slug.replace(TIMESTAMP_REGEX, "") }, valueTransform = { HeanCmsTitle( - it.slug, - it.thumbnail, - it.status.orEmpty() + slug = it.slug, + thumbnailFileName = it.thumbnail, + status = it.status?.toStatus() ?: SManga.UNKNOWN ) } ) @@ -383,6 +372,12 @@ abstract class HeanCms( private inline fun List<*>.firstInstanceOrNull(): R? = filterIsInstance().firstOrNull() + /** + * Used to store the current slugs for sources that change it periodically and for the + * search that doesn't return the thumbnail URLs. + */ + data class HeanCmsTitle(val slug: String, val thumbnailFileName: String, val status: Int) + companion object { private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8" private const val ACCEPT_JSON = "application/json, text/plain, */*" @@ -391,10 +386,4 @@ abstract class HeanCms( val TIMESTAMP_REGEX = "-\\d+$".toRegex() } - - data class HeanCmsTitle( - val slug: String, - val thumbnailUrl: String, - val status: String - ) } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsDto.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsDto.kt index b5e788766..f87f9f22c 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsDto.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsDto.kt @@ -30,7 +30,24 @@ data class HeanCmsSearchDto( @SerialName("series_slug") val slug: String, @SerialName("series_type") val type: String, val title: String -) +) { + + fun toSManga( + apiUrl: String, + coverPath: String, + slugMap: Map + ): SManga = SManga.create().apply { + val slugOnly = slug.replace(HeanCms.TIMESTAMP_REGEX, "") + val thumbnailFileName = slugMap[slugOnly]?.thumbnailFileName.orEmpty() + + title = this@HeanCmsSearchDto.title + thumbnail_url = when { + thumbnailFileName.isNotEmpty() -> "$apiUrl/$coverPath$thumbnailFileName" + else -> "" + } + url = "/series/$slugOnly" + } +} @Serializable data class HeanCmsSeriesDto( @@ -60,13 +77,7 @@ data class HeanCmsSeriesDto( .sortedBy(HeanCmsTagDto::name) .joinToString { it.name } thumbnail_url = "$apiUrl/$coverPath$thumbnail" - status = when (this@HeanCmsSeriesDto.status) { - "Ongoing" -> SManga.ONGOING - "Hiatus" -> SManga.ON_HIATUS - "Dropped" -> SManga.CANCELLED - "Completed", "Finished" -> SManga.COMPLETED - else -> SManga.UNKNOWN - } + status = this@HeanCmsSeriesDto.status?.toStatus() ?: SManga.UNKNOWN url = "/series/${slug.replace(HeanCms.TIMESTAMP_REGEX, "")}" } } @@ -118,6 +129,12 @@ data class HeanCmsQuerySearchPayloadDto( ) @Serializable -data class HeanCmsSearchPayloadDto( - val term: String, -) +data class HeanCmsSearchPayloadDto(val term: String) + +fun String.toStatus(): Int = when (this) { + "Ongoing" -> SManga.ONGOING + "Hiatus" -> SManga.ON_HIATUS + "Dropped" -> SManga.CANCELLED + "Completed", "Finished" -> SManga.COMPLETED + else -> SManga.UNKNOWN +} diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsGenerator.kt index 5e8a38359..15f9c6a9e 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsGenerator.kt @@ -9,7 +9,7 @@ class HeanCmsGenerator : ThemeSourceGenerator { override val themeClass = "HeanCms" - override val baseVersionCode: Int = 7 + override val baseVersionCode: Int = 8 override val sources = listOf( SingleLang("Reaper Scans", "https://reaperscans.net", "pt-BR", overrideVersionCode = 35),