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
This commit is contained in:
parent
5588f4d762
commit
003545ac44
|
@ -2,4 +2,4 @@ plugins {
|
||||||
id("lib-multisrc")
|
id("lib-multisrc")
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVersionCode = 3
|
baseVersionCode = 4
|
||||||
|
|
|
@ -814,8 +814,8 @@ abstract class GalleryAdults(
|
||||||
val tags = mutableListOf<Genre>()
|
val tags = mutableListOf<Genre>()
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val jobsPool = mutableListOf<Job>()
|
val jobsPool = mutableListOf<Job>()
|
||||||
// Get first 3 pages
|
// Get first 5 pages
|
||||||
(1..3).forEach { page ->
|
(1..5).forEach { page ->
|
||||||
jobsPool.add(
|
jobsPool.add(
|
||||||
launchIO {
|
launchIO {
|
||||||
runCatching {
|
runCatching {
|
||||||
|
|
|
@ -1,10 +1,22 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.hentaifox
|
package eu.kanade.tachiyomi.extension.all.hentaifox
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.galleryadults.GalleryAdults
|
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.multisrc.galleryadults.toDate
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
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.SManga
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.FormBody
|
||||||
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
|
||||||
class HentaiFox(
|
class HentaiFox(
|
||||||
|
@ -100,4 +112,103 @@ class HentaiFox(
|
||||||
Filter.Header("HINT: Use double quote (\") for exact match"),
|
Filter.Header("HINT: Use double quote (\") for exact match"),
|
||||||
) + super.getFilterList().list,
|
) + 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<Genre> {
|
||||||
|
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<SortOrderFilter>().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<Pair<String, String>> {
|
||||||
|
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" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue