From 003545ac44f157f7b19deb2f21f5169445ba2006 Mon Sep 17 00:00:00 2001 From: SilverBeamx <44263986+SilverBeamx@users.noreply.github.com> Date: Sun, 22 Dec 2024 06:02:45 +0100 Subject: [PATCH] GalleryAdults & Fox additions (#6686) * Expand tag search to 5 pages as 3 are not enough for HentaiFox * Make launchIO protected instead of private * Add Top Rated, Most Faved, Most Fapped, Most Downloaded search * Update versioning * Address comments * Move sidebar categories to a map * Fetch csrf token from tags page * Move launchIO back to private as it is no longer needed * Clean position of csrf functions * Use map with key lookup for popular categories --- lib-multisrc/galleryadults/build.gradle.kts | 2 +- .../multisrc/galleryadults/GalleryAdults.kt | 4 +- .../extension/all/hentaifox/HentaiFox.kt | 111 ++++++++++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/lib-multisrc/galleryadults/build.gradle.kts b/lib-multisrc/galleryadults/build.gradle.kts index e2f11e9c1..6e70fd158 100644 --- a/lib-multisrc/galleryadults/build.gradle.kts +++ b/lib-multisrc/galleryadults/build.gradle.kts @@ -2,4 +2,4 @@ plugins { id("lib-multisrc") } -baseVersionCode = 3 +baseVersionCode = 4 diff --git a/lib-multisrc/galleryadults/src/eu/kanade/tachiyomi/multisrc/galleryadults/GalleryAdults.kt b/lib-multisrc/galleryadults/src/eu/kanade/tachiyomi/multisrc/galleryadults/GalleryAdults.kt index 0f2261719..6a23b9922 100644 --- a/lib-multisrc/galleryadults/src/eu/kanade/tachiyomi/multisrc/galleryadults/GalleryAdults.kt +++ b/lib-multisrc/galleryadults/src/eu/kanade/tachiyomi/multisrc/galleryadults/GalleryAdults.kt @@ -814,8 +814,8 @@ abstract class GalleryAdults( val tags = mutableListOf() runBlocking { val jobsPool = mutableListOf() - // Get first 3 pages - (1..3).forEach { page -> + // Get first 5 pages + (1..5).forEach { page -> jobsPool.add( launchIO { runCatching { diff --git a/src/all/hentaifox/src/eu/kanade/tachiyomi/extension/all/hentaifox/HentaiFox.kt b/src/all/hentaifox/src/eu/kanade/tachiyomi/extension/all/hentaifox/HentaiFox.kt index 900a6b845..33887515e 100644 --- a/src/all/hentaifox/src/eu/kanade/tachiyomi/extension/all/hentaifox/HentaiFox.kt +++ b/src/all/hentaifox/src/eu/kanade/tachiyomi/extension/all/hentaifox/HentaiFox.kt @@ -1,10 +1,22 @@ package eu.kanade.tachiyomi.extension.all.hentaifox import eu.kanade.tachiyomi.multisrc.galleryadults.GalleryAdults +import eu.kanade.tachiyomi.multisrc.galleryadults.Genre +import eu.kanade.tachiyomi.multisrc.galleryadults.SortOrderFilter +import eu.kanade.tachiyomi.multisrc.galleryadults.imgAttr import eu.kanade.tachiyomi.multisrc.galleryadults.toDate +import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.MangasPage +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.util.asJsoup +import okhttp3.FormBody +import okhttp3.Headers import okhttp3.HttpUrl +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Document import org.jsoup.nodes.Element class HentaiFox( @@ -100,4 +112,103 @@ class HentaiFox( Filter.Header("HINT: Use double quote (\") for exact match"), ) + super.getFilterList().list, ) + + private val sidebarPath = "includes/sidebar.php" + + private fun sidebarMangaSelector() = "div.item" + + private fun Element.sidebarMangaTitle() = + selectFirst("img")?.attr("alt") + + private fun Element.sidebarMangaUrl() = + selectFirst("a")?.attr("abs:href") + + private fun Element.sidebarMangaThumbnail() = + selectFirst("img")?.imgAttr() + + private var csrfToken: String? = null + + override fun tagsParser(document: Document): List { + csrfToken = csrfParser(document) + return super.tagsParser(document) + } + + private fun csrfParser(document: Document): String { + return document.select("[name=csrf-token]").attr("content") + } + + private fun setSidebarHeaders(csrfToken: String?): Headers { + if (csrfToken == null) { + return xhrHeaders + } + return xhrHeaders.newBuilder() + .add("X-Csrf-Token", csrfToken) + .build() + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + // Sidebar mangas should always override any other search, so they should appear first + // and only propagate to super when a "normal" search is issued + val sortOrderFilter = filters.filterIsInstance().firstOrNull() + + sortOrderFilter?.let { + val selectedCategory = sortOrderFilter.values.get(sortOrderFilter.state) + if (sidebarCategoriesFilterStateMap.containsKey(selectedCategory)) { + return sidebarRequest( + sidebarCategoriesFilterStateMap.getValue(selectedCategory), + ) + } + } + return super.searchMangaRequest(page, query, filters) + } + + private fun sidebarRequest(category: String): Request { + val url = "$baseUrl/$sidebarPath" + return POST( + url, + setSidebarHeaders(csrfToken), + FormBody.Builder() + .add("type", category) + .build(), + ) + } + + override fun searchMangaParse(response: Response): MangasPage { + if (response.request.url.encodedPath.endsWith(sidebarPath)) { + val document = response.asJsoup() + val mangas = document.select(sidebarMangaSelector()) + .map { + SMangaDto( + title = it.sidebarMangaTitle()!!, + url = it.sidebarMangaUrl()!!, + thumbnail = it.sidebarMangaThumbnail(), + lang = LANGUAGE_MULTI, + ) + } + .map { + SManga.create().apply { + title = it.title + setUrlWithoutDomain(it.url) + thumbnail_url = it.thumbnail + } + } + + return MangasPage(mangas, false) + } else { + return super.searchMangaParse(response) + } + } + + override fun getSortOrderURIs(): List> { + return super.getSortOrderURIs() + sidebarCategoriesFilterStateMap.toList() + } + + companion object { + private val sidebarCategoriesFilterStateMap = mapOf( + "Top Rated" to "top_rated", + "Most Faved" to "top_faved", + "Most Fapped" to "top_fapped", + "Most Downloaded" to "top_downloaded", + ).withDefault { "top_rated" } + } }