[GalleryAdults] Language filter support #357
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package org.koitharu.kotatsu.parsers
|
||||
|
||||
object ErrorMessages {
|
||||
|
||||
const val FILTER_MULTIPLE_STATES_NOT_SUPPORTED = "Multiple states are not supported by this source"
|
||||
const val FILTER_MULTIPLE_GENRES_NOT_SUPPORTED = "Multiple genres are not supported by this source"
|
||||
const val FILTER_BOTH_LOCALE_GENRES_NOT_SUPPORTED =
|
||||
"Filtering by both genres and locale is not supported by this source"
|
||||
const val FILTER_BOTH_STATES_GENRES_NOT_SUPPORTED =
|
||||
"Filtering by both genres and states is not supported by this source"
|
||||
const val SEARCH_NOT_SUPPORTED = "Search is not supported by this source"
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.parsers.site.en
|
||||
|
||||
import okhttp3.Headers
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
@@ -8,7 +9,6 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.network.UserAgents
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@@ -60,7 +60,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex
|
||||
}
|
||||
|
||||
} else if (filter.tags.isNotEmpty() && filter.states.isNotEmpty()) {
|
||||
throw IllegalArgumentException("Source does not support tag + states filters")
|
||||
throw IllegalArgumentException(ErrorMessages.FILTER_BOTH_STATES_GENRES_NOT_SUPPORTED)
|
||||
} else {
|
||||
when (filter.sortOrder) {
|
||||
SortOrder.POPULARITY -> append("popular-comic")
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.parsers.site.es
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import okhttp3.Headers
|
||||
import org.jsoup.nodes.Document
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
@@ -10,7 +11,6 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.network.UserAgents
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("TEMPLESCANESP", "TempleScanEsp", "es", ContentType.HENTAI)
|
||||
@@ -31,7 +31,7 @@ internal class TempleScanEsp(context: MangaLoaderContext) :
|
||||
append(domain)
|
||||
when (filter) {
|
||||
is MangaListFilter.Search -> {
|
||||
throw IllegalArgumentException("Search is not supported by this source")
|
||||
throw IllegalArgumentException(ErrorMessages.SEARCH_NOT_SUPPORTED)
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.parsers.site.fr
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import okhttp3.Headers
|
||||
import org.jsoup.nodes.Document
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
@@ -10,7 +11,6 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.network.UserAgents
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
@@ -46,7 +46,7 @@ internal class FuryoSociety(context: MangaLoaderContext) :
|
||||
append(domain)
|
||||
when (filter) {
|
||||
is MangaListFilter.Search -> {
|
||||
throw IllegalArgumentException("Search is not supported by this source")
|
||||
throw IllegalArgumentException(ErrorMessages.SEARCH_NOT_SUPPORTED)
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.fr
|
||||
|
||||
import okhttp3.Headers
|
||||
import org.json.JSONArray
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
@@ -10,7 +11,6 @@ import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.network.UserAgents
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSON
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@@ -49,7 +49,7 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
|
||||
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
|
||||
when (filter) {
|
||||
is MangaListFilter.Search -> {
|
||||
throw IllegalArgumentException("Search is not supported by this source")
|
||||
throw IllegalArgumentException(ErrorMessages.SEARCH_NOT_SUPPORTED)
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
|
||||
@@ -6,6 +6,7 @@ import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
@@ -25,7 +26,6 @@ internal abstract class GalleryAdultsParser(
|
||||
override val isMultipleTagsSupported = false
|
||||
|
||||
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
|
||||
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
@@ -37,18 +37,19 @@ internal abstract class GalleryAdultsParser(
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
if (it.key == "languageKey") {
|
||||
append("/language")
|
||||
append(it.title)
|
||||
append("/?")
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
append("/?")
|
||||
}
|
||||
}
|
||||
val tag = filter.tags.oneOrThrowIfMany()
|
||||
val lang = filter.locale
|
||||
if (tag != null && lang != null) {
|
||||
throw IllegalArgumentException(ErrorMessages.FILTER_BOTH_LOCALE_GENRES_NOT_SUPPORTED)
|
||||
}
|
||||
if (tag != null) {
|
||||
append("/tag/")
|
||||
append(tag.key)
|
||||
append("/?")
|
||||
} else if (filter.locale != null) {
|
||||
append("/language/")
|
||||
append(filter.locale.toLanguagePath())
|
||||
append("/?")
|
||||
} else {
|
||||
append("/?")
|
||||
}
|
||||
@@ -102,39 +103,30 @@ internal abstract class GalleryAdultsParser(
|
||||
}.awaitAll().flattenTo(ArraySet(360))
|
||||
}
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
Locale("id"),
|
||||
Locale.ITALIAN,
|
||||
Locale("pt"),
|
||||
Locale("tr"),
|
||||
Locale("th"),
|
||||
Locale("vi"),
|
||||
)
|
||||
|
||||
protected open val pathTagUrl = "/tags/popular/?page="
|
||||
protected open val selectTags = ".tags_page ul.tags li"
|
||||
protected open val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/french",
|
||||
"/japanese",
|
||||
"/chinese",
|
||||
"/spanish",
|
||||
"/russian",
|
||||
"/korean",
|
||||
"/german",
|
||||
"/indonesian",
|
||||
"/italian",
|
||||
"/portuguese",
|
||||
"/turkish",
|
||||
"/thai",
|
||||
"/vietnamese",
|
||||
) // The "/" is used to move them up in the tag list and therefore also in the url.
|
||||
|
||||
private suspend fun getTags(page: Int): Set<MangaTag> {
|
||||
val url = "https://$domain$pathTagUrl$page"
|
||||
val root = webClient.httpGet(url).parseHtml().selectFirstOrThrow(selectTags)
|
||||
val tagLanguage = ArrayList<MangaTag>(listLanguage.size)
|
||||
for (language in listLanguage) {
|
||||
tagLanguage.add(
|
||||
MangaTag(
|
||||
key = "languageKey",
|
||||
title = language,
|
||||
source = source,
|
||||
),
|
||||
)
|
||||
}
|
||||
return root.parseTags() + tagLanguage
|
||||
return root.parseTags()
|
||||
}
|
||||
|
||||
protected open fun Element.parseTags() = select("a").mapToSet {
|
||||
@@ -142,7 +134,7 @@ internal abstract class GalleryAdultsParser(
|
||||
val name = it.html().substringBefore("<")
|
||||
MangaTag(
|
||||
key = key,
|
||||
title = name,
|
||||
title = name.toTitleCase(),
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
@@ -204,4 +196,8 @@ internal abstract class GalleryAdultsParser(
|
||||
val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
return doc.requireElementById(idImg).src() ?: doc.parseFailed("Image src not found")
|
||||
}
|
||||
|
||||
protected open fun Locale.toLanguagePath() = when (language) {
|
||||
else -> getDisplayLanguage(Locale.ENGLISH).lowercase()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import org.koitharu.kotatsu.parsers.util.removeSuffix
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("ASMHENTAI", "AsmHentai", type = ContentType.HENTAI)
|
||||
internal class AsmHentai(context: MangaLoaderContext) :
|
||||
@@ -17,11 +20,12 @@ internal class AsmHentai(context: MangaLoaderContext) :
|
||||
override val pathTagUrl = "/tags/?page="
|
||||
override val selectAuthor = "div.tags:contains(Artists:) .tag_list a span.tag"
|
||||
override val idImg = "fimg"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/japanese",
|
||||
"/chinese",
|
||||
"/turkish",
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("tr"),
|
||||
)
|
||||
|
||||
override fun Element.parseTags() = select("a").mapToSet {
|
||||
|
||||
@@ -6,10 +6,11 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("DOUJINDESUUK", "DoujinDesu.uk", type = ContentType.HENTAI)
|
||||
internal class DoujinDesuUk(context: MangaLoaderContext) :
|
||||
GalleryAdultsParser(context, MangaSource.DOUJINDESUUK, "doujindesu.uk", 50) {
|
||||
GalleryAdultsParser(context, MangaSource.DOUJINDESUUK, "doujindesu.uk", 25) {
|
||||
override val selectGallery = ".gallery"
|
||||
override val selectGalleryLink = "a"
|
||||
override val selectGalleryTitle = ".caption"
|
||||
@@ -19,10 +20,11 @@ internal class DoujinDesuUk(context: MangaLoaderContext) :
|
||||
override val selectAuthor = "div.tag-container:contains(Artists) a"
|
||||
override val selectLanguageChapter = "div.tag-container:contains(Languages) a"
|
||||
override val idImg = "image-container"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/japanese",
|
||||
"/chinese",
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
)
|
||||
|
||||
override fun parseMangaList(doc: Document): List<Manga> {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
|
||||
import org.jsoup.internal.StringUtil
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("HENTAI3", "3Hentai", type = ContentType.HENTAI)
|
||||
internal class Hentai3(context: MangaLoaderContext) :
|
||||
GalleryAdultsParser(context, MangaSource.HENTAI3, "3hentai.net") {
|
||||
GalleryAdultsParser(context, MangaSource.HENTAI3, "3hentai.net", pageSize = 30) {
|
||||
|
||||
override val selectGallery = ".doujin "
|
||||
override val selectGalleryLink = "a"
|
||||
@@ -21,20 +22,21 @@ internal class Hentai3(context: MangaLoaderContext) :
|
||||
override val selectLanguageChapter = "div.tag-container:contains(Languages) a"
|
||||
override val selectUrlChapter = "#main-cover a"
|
||||
override val idImg = ".js-main-img"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/spanish",
|
||||
"/french",
|
||||
"/italian",
|
||||
"/portuguese",
|
||||
"/russian",
|
||||
"/japanese",
|
||||
)
|
||||
|
||||
override val isMultipleTagsSupported = true
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale.ITALIAN,
|
||||
Locale("pt"),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
@@ -49,24 +51,26 @@ internal class Hentai3(context: MangaLoaderContext) :
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
|
||||
if (filter.tags.isNotEmpty() && filter.tags.size > 1) {
|
||||
if (filter.tags.size > 1 || (filter.tags.isNotEmpty() && filter.locale != null)) {
|
||||
append("/search?q=")
|
||||
append(buildQuery(filter.tags))
|
||||
append(buildQuery(filter.tags, filter.locale))
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("&sort=popular")
|
||||
}
|
||||
append("&page=")
|
||||
append(page.toString())
|
||||
} else if (filter.locale != null) {
|
||||
append("/language/")
|
||||
append(filter.locale.toLanguagePath())
|
||||
append("/")
|
||||
append(page.toString())
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("?sort=popular")
|
||||
}
|
||||
} else if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
if (it.key == "languageKey") {
|
||||
append("/language")
|
||||
append(it.title)
|
||||
} else {
|
||||
append("/tags/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/tags/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/")
|
||||
append(page.toString())
|
||||
@@ -93,12 +97,18 @@ internal class Hentai3(context: MangaLoaderContext) :
|
||||
return doc.selectFirstOrThrow(idImg).src() ?: doc.parseFailed("Image src not found")
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>) =
|
||||
tags.joinToString(separator = " ") { tag ->
|
||||
if (tag.key == "languageKey") {
|
||||
"language:\"${tag.title.removePrefix("/")}\""
|
||||
} else {
|
||||
"tag:\"${tag.title}\""
|
||||
}
|
||||
private fun buildQuery(tags: Collection<MangaTag>, language: Locale?): String {
|
||||
val joiner = StringUtil.StringJoiner(" ")
|
||||
tags.forEach { tag ->
|
||||
joiner.add("tag:\"")
|
||||
joiner.append(tag.key)
|
||||
joiner.append("\"")
|
||||
}
|
||||
language?.let { lc ->
|
||||
joiner.add("language:\"")
|
||||
joiner.append(lc.toLanguagePath())
|
||||
joiner.append("\"")
|
||||
}
|
||||
return joiner.complete()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
@@ -8,11 +9,11 @@ import org.koitharu.kotatsu.parsers.util.domain
|
||||
import org.koitharu.kotatsu.parsers.util.oneOrThrowIfMany
|
||||
import org.koitharu.kotatsu.parsers.util.parseHtml
|
||||
import org.koitharu.kotatsu.parsers.util.urlEncoded
|
||||
import java.util.EnumSet
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("HENTAIENVY", "HentaiEnvy", type = ContentType.HENTAI)
|
||||
internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
GalleryAdultsParser(context, MangaSource.HENTAIENVY, "hentaienvy.com") {
|
||||
GalleryAdultsParser(context, MangaSource.HENTAIENVY, "hentaienvy.com", pageSize = 24) {
|
||||
override val selectGalleryLink = "a"
|
||||
override val selectGalleryTitle = "div.title"
|
||||
override val selectTags = ".tags_items"
|
||||
@@ -20,17 +21,6 @@ internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
override val selectAuthor = ".gt_right_tags ul:contains(Artists:) a"
|
||||
override val selectLanguageChapter = ".gt_right_tags ul:contains(Languages:) a"
|
||||
override val idImg = "fimg"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/french",
|
||||
"/japanese",
|
||||
"/chinese",
|
||||
"/spanish",
|
||||
"/russian",
|
||||
"/korean",
|
||||
"/german",
|
||||
"/portuguese",
|
||||
)
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
@@ -47,20 +37,21 @@ internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
if (it.key == "languageKey") {
|
||||
append("/language")
|
||||
append(it.title)
|
||||
append("/?")
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("/popular")
|
||||
}
|
||||
append("/?")
|
||||
}
|
||||
if (filter.locale != null) {
|
||||
throw IllegalArgumentException(ErrorMessages.FILTER_BOTH_LOCALE_GENRES_NOT_SUPPORTED)
|
||||
}
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("/popular")
|
||||
}
|
||||
append("/?")
|
||||
}
|
||||
} else if (filter.locale != null) {
|
||||
append("/language/")
|
||||
append(filter.locale.toLanguagePath())
|
||||
append("/?")
|
||||
} else {
|
||||
append("/?")
|
||||
}
|
||||
@@ -74,4 +65,16 @@ internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
}
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
}
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
Locale("pt"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("HENTAIERA", "HentaiEra", type = ContentType.HENTAI)
|
||||
internal class HentaiEra(context: MangaLoaderContext) :
|
||||
@@ -15,20 +15,22 @@ internal class HentaiEra(context: MangaLoaderContext) :
|
||||
override val selectTag = ".galleries_info li:contains(Tags) div.info_tags"
|
||||
override val selectAuthor = ".galleries_info li:contains(Artists) span.item_name"
|
||||
override val selectLanguageChapter = ".galleries_info li:contains(Languages) div.info_tags .item_name"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/japanese",
|
||||
"/spanish",
|
||||
"/french",
|
||||
"/korean",
|
||||
"/german",
|
||||
"/russian",
|
||||
)
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override val isMultipleTagsSupported = true
|
||||
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
)
|
||||
|
||||
override fun Element.parseTags() = select("a.tag, .gallery_title a").mapToSet {
|
||||
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
|
||||
val name = it.selectFirst(".item_name")?.text() ?: it.text()
|
||||
@@ -52,26 +54,33 @@ internal class HentaiEra(context: MangaLoaderContext) :
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
if (filter.tags.isNotEmpty() && filter.tags.size > 1) {
|
||||
if (filter.tags.size > 1 || (filter.tags.isNotEmpty() && filter.locale != null)) {
|
||||
append("/search/?key=")
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append(buildQuery(filter.tags).replace("<=1&dl=0&pp=0&tr=0", "<=0&dl=0&pp=1&tr=0"))
|
||||
append(
|
||||
buildQuery(filter.tags, filter.locale)
|
||||
.replace("<=1&dl=0&pp=0&tr=0", "<=0&dl=0&pp=1&tr=0"),
|
||||
)
|
||||
} else {
|
||||
append(buildQuery(filter.tags))
|
||||
append(buildQuery(filter.tags, filter.locale))
|
||||
}
|
||||
append("&")
|
||||
} else if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
if (it.key == "languageKey") {
|
||||
append("/language")
|
||||
append(it.title)
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/")
|
||||
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
append("?")
|
||||
} else if (filter.locale != null) {
|
||||
append("/language/")
|
||||
append(filter.locale.toLanguagePath())
|
||||
append("/")
|
||||
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
@@ -90,40 +99,20 @@ internal class HentaiEra(context: MangaLoaderContext) :
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>): String {
|
||||
private fun buildQuery(tags: Collection<MangaTag>, locale: Locale?): String {
|
||||
val queryDefault =
|
||||
"&search=&mg=1&dj=1&ws=1&is=1&ac=1&gc=1&en=0&jp=0&es=0&fr=0&kr=0&de=0&ru=0<=1&dl=0&pp=0&tr=0"
|
||||
var tag = ""
|
||||
var queryMod = ""
|
||||
tags.map {
|
||||
if (it.key == "languageKey" && it.title == "/english") {
|
||||
queryMod = queryDefault.replace("en=0", "en=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/japanese") {
|
||||
queryMod = queryDefault.replace("jp=0", "jp=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/spanish") {
|
||||
queryMod = queryDefault.replace("es=0", "es=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/french") {
|
||||
queryMod = queryDefault.replace("fr=0", "fr=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/korean") {
|
||||
queryMod = queryDefault.replace("kr=0", "kr=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/russian") {
|
||||
queryMod = queryDefault.replace("ru=0", "ru=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/german") {
|
||||
queryMod = queryDefault.replace("de=0", "de=1")
|
||||
}
|
||||
if (it.key != "languageKey") {
|
||||
tag += it.key + " "
|
||||
}
|
||||
}
|
||||
|
||||
if (queryMod.isEmpty()) {
|
||||
queryMod = "&search=&mg=1&dj=1&ws=1&is=1&ac=1&gc=1&en=1&jp=1&es=1&fr=1&kr=1&de=1&ru=1<=1&dl=0&pp=0&tr=0"
|
||||
val tag = tags.joinToString(" ", postfix = " ") { it.key }
|
||||
val queryMod = when (val lp = locale?.toLanguagePath()) {
|
||||
"english" -> queryDefault.replace("en=0", "en=1")
|
||||
"japanese" -> queryDefault.replace("jp=0", "jp=1")
|
||||
"spanish" -> queryDefault.replace("es=0", "es=1")
|
||||
"french" -> queryDefault.replace("fr=0", "fr=1")
|
||||
"korean" -> queryDefault.replace("kr=0", "kr=1")
|
||||
"russian" -> queryDefault.replace("ru=0", "ru=1")
|
||||
"german" -> queryDefault.replace("de=0", "de=1")
|
||||
null -> "&search=&mg=1&dj=1&ws=1&is=1&ac=1&gc=1&en=1&jp=1&es=1&fr=1&kr=1&de=1&ru=1<=1&dl=0&pp=0&tr=0"
|
||||
else -> throw IllegalArgumentException("Unsupported locale: $lp")
|
||||
}
|
||||
return tag + queryMod
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
|
||||
import org.jsoup.internal.StringUtil
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("HENTAIFORCE", "HentaiForce", type = ContentType.HENTAI)
|
||||
internal class HentaiForce(context: MangaLoaderContext) :
|
||||
GalleryAdultsParser(context, MangaSource.HENTAIFORCE, "hentaiforce.net") {
|
||||
GalleryAdultsParser(context, MangaSource.HENTAIFORCE, "hentaiforce.net", pageSize = 30) {
|
||||
override val selectGallery = ".gallery"
|
||||
override val selectGalleryLink = "a.gallery-thumb"
|
||||
override val pathTagUrl = "/tags/popular/"
|
||||
@@ -19,26 +20,27 @@ internal class HentaiForce(context: MangaLoaderContext) :
|
||||
override val selectAuthor = "div.tag-container:contains(Artists:) a"
|
||||
override val selectLanguageChapter = "div.tag-container:contains(Languages:) a"
|
||||
override val idImg = ".gallery-reader-img-wrapper img"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/french",
|
||||
"/japanese",
|
||||
"/chinese",
|
||||
"/spanish",
|
||||
"/russian",
|
||||
"/korean",
|
||||
"/german",
|
||||
"/indonesian",
|
||||
"/italian",
|
||||
"/portuguese",
|
||||
"/thai",
|
||||
"/vietnamese",
|
||||
)
|
||||
|
||||
override val isMultipleTagsSupported = true
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
Locale("id"),
|
||||
Locale.ITALIAN,
|
||||
Locale("pt"),
|
||||
Locale("th"),
|
||||
Locale("vi"),
|
||||
)
|
||||
|
||||
override suspend fun getPageUrl(page: MangaPage): String {
|
||||
val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
return doc.selectFirstOrThrow(idImg).src() ?: doc.parseFailed("Image src not found")
|
||||
@@ -56,25 +58,29 @@ internal class HentaiForce(context: MangaLoaderContext) :
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
if (filter.tags.isNotEmpty() && filter.tags.size > 1) {
|
||||
if (filter.tags.size > 1 || (filter.tags.isNotEmpty() && filter.locale != null)) {
|
||||
append("/search?q=")
|
||||
append(buildQuery(filter.tags))
|
||||
append(buildQuery(filter.tags, filter.locale))
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("&sort=popular")
|
||||
}
|
||||
append("&page=")
|
||||
} else if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
if (it.key == "languageKey") {
|
||||
append("/language")
|
||||
append(it.title)
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/")
|
||||
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
append("?")
|
||||
} else if (filter.locale != null) {
|
||||
append("/language/")
|
||||
append(filter.locale.toLanguagePath())
|
||||
append("/")
|
||||
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
@@ -92,12 +98,18 @@ internal class HentaiForce(context: MangaLoaderContext) :
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>) =
|
||||
tags.joinToString(separator = " ") { tag ->
|
||||
if (tag.key == "languageKey") {
|
||||
"language:${tag.title.removePrefix("/")}"
|
||||
} else {
|
||||
"tag:${tag.title}"
|
||||
}
|
||||
private fun buildQuery(tags: Collection<MangaTag>, language: Locale?): String {
|
||||
val joiner = StringUtil.StringJoiner(" ")
|
||||
tags.forEach { tag ->
|
||||
joiner.add("tag:\"")
|
||||
joiner.append(tag.key)
|
||||
joiner.append("\"")
|
||||
}
|
||||
language?.let { lc ->
|
||||
joiner.add("language:\"")
|
||||
joiner.append(lc.toLanguagePath())
|
||||
joiner.append("\"")
|
||||
}
|
||||
return joiner.complete()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
|
||||
import org.jsoup.internal.StringUtil
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("HENTAIFOX", "HentaiFox", type = ContentType.HENTAI)
|
||||
internal class HentaiFox(context: MangaLoaderContext) :
|
||||
@@ -16,21 +17,6 @@ internal class HentaiFox(context: MangaLoaderContext) :
|
||||
override val selectTags = ".list_tags"
|
||||
override val selectTag = "ul.tags"
|
||||
override val selectLanguageChapter = "ul.languages a.tag_btn"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/french",
|
||||
"/japanese",
|
||||
"/chinese",
|
||||
"/spanish",
|
||||
"/russian",
|
||||
"/korean",
|
||||
"/indonesian",
|
||||
"/italian",
|
||||
"/portuguese",
|
||||
"/turkish",
|
||||
"/thai",
|
||||
"/vietnamese",
|
||||
)
|
||||
|
||||
override val isMultipleTagsSupported = true
|
||||
|
||||
@@ -51,9 +37,9 @@ internal class HentaiFox(context: MangaLoaderContext) :
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
if (filter.tags.isNotEmpty() && filter.tags.size > 1) {
|
||||
if (filter.tags.size > 1 || (filter.tags.isNotEmpty() && filter.locale != null)) {
|
||||
append("/search/?q=")
|
||||
append(buildQuery(filter.tags))
|
||||
append(buildQuery(filter.tags, filter.locale))
|
||||
if (page > 1) {
|
||||
append("&page=")
|
||||
append(page.toString())
|
||||
@@ -64,19 +50,27 @@ internal class HentaiFox(context: MangaLoaderContext) :
|
||||
}
|
||||
} else if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
if (it.key == "languageKey") {
|
||||
append("/language")
|
||||
append(it.title)
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/")
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
|
||||
if (page > 1) {
|
||||
append("/pag/")
|
||||
append(page.toString())
|
||||
append("/")
|
||||
}
|
||||
} else if (filter.locale != null) {
|
||||
append("/language/")
|
||||
append(filter.locale.toLanguagePath())
|
||||
append("/")
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
|
||||
if (page > 1) {
|
||||
append("/pag/")
|
||||
append(page.toString())
|
||||
@@ -122,12 +116,14 @@ internal class HentaiFox(context: MangaLoaderContext) :
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>) =
|
||||
tags.joinToString(separator = " ") { tag ->
|
||||
if (tag.key == "languageKey") {
|
||||
tag.title.removePrefix("/")
|
||||
} else {
|
||||
tag.key
|
||||
}
|
||||
private fun buildQuery(tags: Collection<MangaTag>, language: Locale?): String {
|
||||
val joiner = StringUtil.StringJoiner(" ")
|
||||
tags.forEach { tag ->
|
||||
joiner.add(tag.key)
|
||||
}
|
||||
language?.let { lc ->
|
||||
joiner.add(lc.toLanguagePath())
|
||||
}
|
||||
return joiner.complete()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import org.koitharu.kotatsu.parsers.util.removeSuffix
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("HENTAIROX", "HentaiRox", type = ContentType.HENTAI)
|
||||
internal class HentaiRox(context: MangaLoaderContext) :
|
||||
@@ -16,14 +19,15 @@ internal class HentaiRox(context: MangaLoaderContext) :
|
||||
override val selectTag = "li:contains(Tags:)"
|
||||
override val selectAuthor = "li:contains(Artists:) span.item_name"
|
||||
override val selectLanguageChapter = "li:contains(Languages:) .item_name"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/french",
|
||||
"/japanese",
|
||||
"/spanish",
|
||||
"/russian",
|
||||
"/korean",
|
||||
"/german",
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
)
|
||||
|
||||
override fun Element.parseTags() = select("a.tag, .gallery_title a").mapToSet {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
|
||||
import org.jsoup.internal.StringUtil
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("NHENTAI", "NHentai.net", type = ContentType.HENTAI)
|
||||
internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
@@ -21,11 +22,6 @@ internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
override val selectLanguageChapter =
|
||||
".tag-container:contains(Languages:) span.tags a:not(.tag-17249) span.name" // tag-17249 = translated
|
||||
override val idImg = "image-container"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/japanese",
|
||||
"/chinese",
|
||||
)
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
@@ -45,28 +41,32 @@ internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
if (filter.tags.isNotEmpty() && filter.tags.size > 1) {
|
||||
if (filter.tags.size > 1 || (filter.tags.isNotEmpty() && filter.locale != null)) {
|
||||
append("/search/?q=")
|
||||
append(buildQuery(filter.tags))
|
||||
append(buildQuery(filter.tags, filter.locale).urlEncoded())
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("&sort=popular")
|
||||
}
|
||||
append("&")
|
||||
} else if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
if (it.key == "languageKey") {
|
||||
append("/language")
|
||||
append(it.title)
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/")
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
|
||||
append("?")
|
||||
} else if (filter.locale != null) {
|
||||
append("/language/")
|
||||
append(filter.locale.toLanguagePath())
|
||||
append("/")
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
|
||||
append("?")
|
||||
} else {
|
||||
if (filter.sortOrder == SortOrder.POPULARITY) {
|
||||
@@ -101,12 +101,24 @@ internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>) =
|
||||
tags.joinToString(separator = " ") { tag ->
|
||||
if (tag.key == "languageKey") {
|
||||
"language:\"${tag.title.removePrefix("/")}\""
|
||||
} else {
|
||||
"tag:\"${tag.key}\""
|
||||
}
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
)
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>, language: Locale?): String {
|
||||
val joiner = StringUtil.StringJoiner(" ")
|
||||
tags.forEach { tag ->
|
||||
joiner.add("tag:\"")
|
||||
joiner.append(tag.key)
|
||||
joiner.append("\"")
|
||||
}
|
||||
language?.let { lc ->
|
||||
joiner.add("language:\"")
|
||||
joiner.append(lc.toLanguagePath())
|
||||
joiner.append("\"")
|
||||
}
|
||||
return joiner.complete()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("NHENTAIUK", "NHentai.uk", type = ContentType.HENTAI)
|
||||
internal class NHentaiUk(context: MangaLoaderContext) :
|
||||
GalleryAdultsParser(context, MangaSource.NHENTAIUK, "nhentai.uk", 50) {
|
||||
GalleryAdultsParser(context, MangaSource.NHENTAIUK, "nhentai.uk", pageSize = 50) {
|
||||
override val selectGallery = ".gallery"
|
||||
override val selectGalleryLink = "a"
|
||||
override val selectGalleryTitle = ".caption"
|
||||
@@ -19,18 +20,19 @@ internal class NHentaiUk(context: MangaLoaderContext) :
|
||||
override val selectAuthor = "div.tag-container:contains(Artists:) a"
|
||||
override val selectLanguageChapter = "div.tag-container:contains(Languages:) a"
|
||||
override val idImg = "image-container"
|
||||
override val listLanguage = arrayOf(
|
||||
"/english",
|
||||
"/french",
|
||||
"/japanese",
|
||||
"/chinese",
|
||||
"/spanish",
|
||||
"/russian",
|
||||
"/korean",
|
||||
"/german",
|
||||
"/italian",
|
||||
"/portuguese",
|
||||
"/turkish",
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
Locale("pt"),
|
||||
Locale.ITALIAN,
|
||||
Locale("tr"),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
|
||||
@@ -41,23 +43,32 @@ internal class NHentaiUk(context: MangaLoaderContext) :
|
||||
when (filter) {
|
||||
|
||||
is MangaListFilter.Search -> {
|
||||
throw IllegalArgumentException("Search is not supported by this source")
|
||||
throw IllegalArgumentException(ErrorMessages.SEARCH_NOT_SUPPORTED)
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
if (it.key == "languageKey") {
|
||||
append("/language")
|
||||
append(it.title)
|
||||
} else {
|
||||
when {
|
||||
filter.locale != null && filter.tags.isNotEmpty() -> {
|
||||
throw IllegalArgumentException(ErrorMessages.FILTER_BOTH_LOCALE_GENRES_NOT_SUPPORTED)
|
||||
}
|
||||
|
||||
filter.locale != null -> {
|
||||
append("/language")
|
||||
append(filter.locale.toLanguagePath())
|
||||
append("/?p=")
|
||||
}
|
||||
|
||||
filter.tags.isNotEmpty() -> {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
append("/tag/")
|
||||
append(it.key)
|
||||
}
|
||||
append("/?p=")
|
||||
}
|
||||
|
||||
else -> {
|
||||
append("/home?p=")
|
||||
}
|
||||
append("/?p=")
|
||||
} else {
|
||||
append("/home?p=")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.koitharu.kotatsu.parsers.site.heancmsalt
|
||||
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
@@ -41,7 +41,7 @@ internal abstract class HeanCmsAlt(
|
||||
append(listUrl)
|
||||
when (filter) {
|
||||
is MangaListFilter.Search -> {
|
||||
throw IllegalArgumentException("Search is not supported by this source")
|
||||
throw IllegalArgumentException(ErrorMessages.SEARCH_NOT_SUPPORTED)
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
package org.koitharu.kotatsu.parsers.site.mangareader.en
|
||||
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
|
||||
import org.koitharu.kotatsu.parsers.util.domain
|
||||
import org.koitharu.kotatsu.parsers.util.oneOrThrowIfMany
|
||||
import org.koitharu.kotatsu.parsers.util.parseHtml
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.util.EnumSet
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("RIZZCOMIC", "RizzComic", "en")
|
||||
internal class RizzComic(context: MangaLoaderContext) :
|
||||
@@ -35,7 +31,7 @@ internal class RizzComic(context: MangaLoaderContext) :
|
||||
when (filter) {
|
||||
|
||||
is MangaListFilter.Search -> {
|
||||
throw IllegalArgumentException("Search is not supported by this source")
|
||||
throw IllegalArgumentException(ErrorMessages.SEARCH_NOT_SUPPORTED)
|
||||
}
|
||||
|
||||
is MangaListFilter.Advanced -> {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.parsers.site.uk
|
||||
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
@@ -23,6 +24,8 @@ class MangaInUaParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
|
||||
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manga.in.ua")
|
||||
|
||||
override val isMultipleTagsSupported: Boolean = false
|
||||
|
||||
private val userHashRegex by lazy {
|
||||
Regex("site_login_hash\\s*=\\s*\'([^\']+)\'", RegexOption.IGNORE_CASE)
|
||||
}
|
||||
@@ -40,7 +43,7 @@ class MangaInUaParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
|
||||
tags.isNullOrEmpty() -> "/mangas/page/$page".toAbsoluteUrl(domain)
|
||||
tags.size == 1 -> "${tags.first().key}/page/$page"
|
||||
tags.size > 1 -> throw IllegalArgumentException("This source supports only 1 genre")
|
||||
tags.size > 1 -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_GENRES_NOT_SUPPORTED)
|
||||
else -> "/mangas/page/$page".toAbsoluteUrl(domain)
|
||||
}
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.util
|
||||
|
||||
import okhttp3.HttpUrl
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.InternalParsersApi
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
@@ -54,7 +55,7 @@ fun Set<MangaTag>?.oneOrThrowIfMany(): MangaTag? {
|
||||
return when {
|
||||
isNullOrEmpty() -> null
|
||||
size == 1 -> first()
|
||||
else -> throw IllegalArgumentException("Multiple genres are not supported by this source")
|
||||
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_GENRES_NOT_SUPPORTED)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +64,7 @@ fun Set<MangaState>?.oneOrThrowIfMany(): MangaState? {
|
||||
return when {
|
||||
isNullOrEmpty() -> null
|
||||
size == 1 -> first()
|
||||
else -> throw IllegalArgumentException("Multiple states are not supported by this source")
|
||||
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user