[SoManga] close #1091

[AsuraComic] fix close #1088
[HeanCms] add SearchWithFilters
[fuzzydoodle] add ContentTypes, SearchWithFilters
[DoujinDesu.tv] add SearchWithFilters, ContentTypes
master
devi 2 years ago
parent 1c0df02c56
commit 52329e658f

@ -158,16 +158,16 @@ internal class AsuraScansParser(context: MangaLoaderContext) :
return manga.copy( return manga.copy(
description = doc.selectFirst("span.font-medium.text-sm")?.text().orEmpty(), description = doc.selectFirst("span.font-medium.text-sm")?.text().orEmpty(),
tags = tags, tags = tags,
author = doc.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Author)) > h3:eq(1)")?.text(), author = doc.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Author)) > h3:eq(1)")?.text().orEmpty(),
chapters = doc.select("div.scrollbar-thumb-themecolor > div.group").mapChapters(reversed = true) { i, div -> chapters = doc.select("div.scrollbar-thumb-themecolor > div.group").mapChapters(reversed = true) { i, div ->
val a = div.selectLastOrThrow("a") val a = div.selectLastOrThrow("a")
val urlRelative = "/series/" + a.attrAsRelativeUrl("href") val urlRelative = "/series/" + a.attrAsRelativeUrl("href")
val url = urlRelative.toAbsoluteUrl(domain) val url = urlRelative.toAbsoluteUrl(domain)
val date = div.selectFirst("h3:eq(1)")!!.ownText() val date = div.selectLast("h3")?.text().orEmpty()
val cleanDate = date.replace(regexDate, "$1") val cleanDate = date.replace(regexDate, "$1")
MangaChapter( MangaChapter(
id = generateUid(url), id = generateUid(url),
name = div.selectFirstOrThrow("h3:eq(0)").text(), name = div.selectFirst("h3")?.text() ?: "Chapter : ${i + 1f}",
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = url, url = url,

@ -31,6 +31,24 @@ internal abstract class FuzzyDoodleParser(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST)
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true,
isSearchSupported = true,
isSearchWithFiltersSupported = true,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
availableContentTypes = EnumSet.of(
ContentType.MANGA,
ContentType.MANHWA,
ContentType.MANHUA,
ContentType.COMICS,
),
)
@JvmField @JvmField
protected val ongoing = scatterSetOf( protected val ongoing = scatterSetOf(
"en cours", "en cours",
@ -67,54 +85,53 @@ internal abstract class FuzzyDoodleParser(
protected open val pausedValue = "haitus" protected open val pausedValue = "haitus"
protected open val abandonedValue = "dropped" protected open val abandonedValue = "dropped"
override val filterCapabilities: MangaListFilterCapabilities protected open val mangaValue = "manga"
get() = MangaListFilterCapabilities( protected open val manhwaValue = "manhwa"
isMultipleTagsSupported = true, protected open val manhuaValue = "manhua"
isSearchSupported = true, protected open val comicsValue = "bande-dessinee"
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
append("/manga?page=") append("/manga?page=")
append(page) append(page.toString())
when { append("&type=")
filter.types.oneOrThrowIfMany().let {
!filter.query.isNullOrEmpty() -> { append(
append("&title=") when (it) {
append(filter.query.urlEncoded()) ContentType.MANGA -> mangaValue
} ContentType.MANHWA -> manhwaValue
ContentType.MANHUA -> manhuaValue
ContentType.COMICS -> comicsValue
else -> ""
},
)
}
else -> { filter.query?.let {
append("&type=") append("&title=")
append(filter.query.urlEncoded())
append("&status=") }
filter.states.oneOrThrowIfMany()?.let { append("&status=")
append( filter.states.oneOrThrowIfMany()?.let {
when (it) { append(
MangaState.ONGOING -> ongoingValue when (it) {
MangaState.FINISHED -> finishedValue MangaState.ONGOING -> ongoingValue
MangaState.PAUSED -> pausedValue MangaState.FINISHED -> finishedValue
MangaState.ABANDONED -> abandonedValue MangaState.PAUSED -> pausedValue
else -> "" MangaState.ABANDONED -> abandonedValue
}, else -> ""
) },
} )
}
filter.tags.forEach { filter.tags.forEach {
append("&") append("&")
append("genre[]".urlEncoded()) append("genre[]".urlEncoded())
append("=") append("=")
append(it.key) append(it.key)
}
}
} }
} }
@ -270,17 +287,14 @@ internal abstract class FuzzyDoodleParser(
private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long { private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
d.endsWith(" ago") ||
d.endsWith("مضت") || d.startsWith("منذ") ||
d.startsWith("il y a") -> parseRelativeDate(date)
date.contains(Regex("""\d(st|nd|rd|th)""")) -> date.split(" ").map { WordSet(" ago", "مضت").endsWith(d) -> {
if (it.contains(Regex("""\d\D\D"""))) { parseRelativeDate(d)
it.replace(Regex("""\D"""), "") }
} else {
it WordSet("il y a", "منذ").startsWith(d) -> {
} parseRelativeDate(d)
}.let { dateFormat.tryParse(it.joinToString(" ")) } }
else -> dateFormat.tryParse(date) else -> dateFormat.tryParse(date)
} }

@ -16,7 +16,16 @@ internal class HentaiSlayer(context: MangaLoaderContext) :
override val finishedValue = "مكتمل" override val finishedValue = "مكتمل"
override val abandonedValue = "متوقف" override val abandonedValue = "متوقف"
override val mangaValue = "مانجا"
override val manhuaValue = "مانهوا"
override val comicsValue = "كوميكس"
override suspend fun getFilterOptions() = super.getFilterOptions().copy( override suspend fun getFilterOptions() = super.getFilterOptions().copy(
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED), availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED),
availableContentTypes = EnumSet.of(
ContentType.MANGA,
ContentType.MANHUA,
ContentType.COMICS,
),
) )
} }

@ -2,9 +2,21 @@ package org.koitharu.kotatsu.parsers.site.fuzzydoodle.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaListFilterOptions
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.fuzzydoodle.FuzzyDoodleParser import org.koitharu.kotatsu.parsers.site.fuzzydoodle.FuzzyDoodleParser
import java.util.EnumSet
@MangaSourceParser("SCYLLACOMICS", "ScyllaComics", "en") @MangaSourceParser("SCYLLACOMICS", "ScyllaComics", "en")
internal class ScyllaComics(context: MangaLoaderContext) : internal class ScyllaComics(context: MangaLoaderContext) :
FuzzyDoodleParser(context, MangaParserSource.SCYLLACOMICS, "scyllacomics.xyz") FuzzyDoodleParser(context, MangaParserSource.SCYLLACOMICS, "scyllacomics.xyz") {
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableContentTypes = EnumSet.of(
ContentType.MANGA,
ContentType.MANHWA,
ContentType.MANHUA,
),
)
}

@ -116,7 +116,7 @@ internal abstract class GalleryAdultsParser(
publicUrl = href.toAbsoluteUrl(domain), publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
isNsfw = isNsfwSource, isNsfw = isNsfwSource,
coverUrl = div.selectFirstOrThrow(selectGalleryImg).src().orEmpty(), coverUrl = div.selectFirst(selectGalleryImg)?.src().orEmpty(),
tags = emptySet(), tags = emptySet(),
state = null, state = null,
author = null, author = null,

@ -19,6 +19,7 @@ internal class AsmHentai(context: MangaLoaderContext) :
override val selectGalleryLink = ".image a" override val selectGalleryLink = ".image a"
override val selectGalleryImg = ".image img" override val selectGalleryImg = ".image img"
override val pathTagUrl = "/tags/?page=" override val pathTagUrl = "/tags/?page="
override val selectTags = ".tags_page ul.tags"
override val selectAuthor = "div.tags:contains(Artists:) .tag_list a span.tag" override val selectAuthor = "div.tags:contains(Artists:) .tag_list a span.tag"
override val idImg = "fimg" override val idImg = "fimg"

@ -1,6 +1,7 @@
package org.koitharu.kotatsu.parsers.site.galleryadults.all package org.koitharu.kotatsu.parsers.site.galleryadults.all
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
@ -8,6 +9,7 @@ import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.util.* import java.util.*
@Broken
@MangaSourceParser("DOUJINDESUUK", "DoujinDesu.uk", type = ContentType.HENTAI) @MangaSourceParser("DOUJINDESUUK", "DoujinDesu.uk", type = ContentType.HENTAI)
internal class DoujinDesuUk(context: MangaLoaderContext) : internal class DoujinDesuUk(context: MangaLoaderContext) :
GalleryAdultsParser(context, MangaParserSource.DOUJINDESUUK, "doujindesu.uk", 25) { GalleryAdultsParser(context, MangaParserSource.DOUJINDESUUK, "doujindesu.uk", 25) {

@ -77,7 +77,7 @@ internal abstract class GattsuParser(
id = generateUid(href), id = generateUid(href),
url = href, url = href,
publicUrl = href, publicUrl = href,
title = li.selectLastOrThrow(".thumb-titulo, .video-titulo").text(), title = li.selectLast(".thumb-titulo, .video-titulo")?.text().orEmpty(),
coverUrl = li.selectFirst("img")?.src().orEmpty(), coverUrl = li.selectFirst("img")?.src().orEmpty(),
altTitle = null, altTitle = null,
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,

@ -14,6 +14,13 @@ internal abstract class GuyaParser(
domain: String, domain: String,
) : SinglePageMangaParser(context, source) { ) : SinglePageMangaParser(context, source) {
override val configKeyDomain = ConfigKey.Domain(domain)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys)
keys.add(userAgentKey)
}
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
@ -23,13 +30,6 @@ internal abstract class GuyaParser(
override suspend fun getFilterOptions() = MangaListFilterOptions() override suspend fun getFilterOptions() = MangaListFilterOptions()
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys)
keys.add(userAgentKey)
}
override val configKeyDomain = ConfigKey.Domain(domain)
override suspend fun getList(order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getList(order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")

@ -39,16 +39,11 @@ internal abstract class HeanCms(
SortOrder.POPULARITY_ASC, SortOrder.POPULARITY_ASC,
) )
protected open val pathManga = "series"
protected open val apiPath
get() = getDomain("api")
protected open val paramsUpdated = "latest"
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
@ -56,52 +51,59 @@ internal abstract class HeanCms(
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED), availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
) )
protected open val pathManga = "series"
protected open val apiPath
get() = getDomain("api")
protected open val paramsUpdated = "latest"
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
append(apiPath) append(apiPath)
append("/query?query_string=&series_type=Comic&perPage=$pageSize") append("/query?query_string=")
when {
!filter.query.isNullOrEmpty() -> { filter.query?.let {
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
} }
else -> { append("&series_type=Comic&perPage=$pageSize")
filter.states.oneOrThrowIfMany()?.let { filter.states.oneOrThrowIfMany()?.let {
append("&status=") append("&status=")
append( append(
when (it) { when (it) {
MangaState.ONGOING -> "Ongoing" MangaState.ONGOING -> "Ongoing"
MangaState.FINISHED -> "Completed" MangaState.FINISHED -> "Completed"
MangaState.ABANDONED -> "Dropped" MangaState.ABANDONED -> "Dropped"
MangaState.PAUSED -> "Hiatus" MangaState.PAUSED -> "Hiatus"
else -> "" else -> ""
}, },
) )
}
append("&orderBy=")
when (order) {
SortOrder.POPULARITY -> append("total_views&order=desc")
SortOrder.POPULARITY_ASC -> append("total_views&order=asc")
SortOrder.UPDATED -> append("$paramsUpdated&order=desc")
SortOrder.UPDATED_ASC -> append("$paramsUpdated&order=asc")
SortOrder.NEWEST -> append("created_at&order=desc")
SortOrder.NEWEST_ASC -> append("created_at&order=asc")
SortOrder.ALPHABETICAL -> append("title&order=asc")
SortOrder.ALPHABETICAL_DESC -> append("title&order=desc")
else -> append("latest&order=desc")
}
append("&tags_ids=")
append("[".urlEncoded())
append(filter.tags.joinToString(",") { it.key })
append("]".urlEncoded())
}
} }
append("&orderBy=")
when (order) {
SortOrder.POPULARITY -> append("total_views&order=desc")
SortOrder.POPULARITY_ASC -> append("total_views&order=asc")
SortOrder.UPDATED -> append("$paramsUpdated&order=desc")
SortOrder.UPDATED_ASC -> append("$paramsUpdated&order=asc")
SortOrder.NEWEST -> append("created_at&order=desc")
SortOrder.NEWEST_ASC -> append("created_at&order=asc")
SortOrder.ALPHABETICAL -> append("title&order=asc")
SortOrder.ALPHABETICAL_DESC -> append("title&order=desc")
else -> append("latest&order=desc")
}
append("&tags_ids=")
append("[".urlEncoded())
append(filter.tags.joinToString(",") { it.key })
append("]".urlEncoded())
append("&page=") append("&page=")
append(page.toString()) append(page.toString())
} }
return parseMangaList(webClient.httpGet(url).parseJson()) return parseMangaList(webClient.httpGet(url).parseJson())
} }

@ -65,8 +65,8 @@ internal abstract class HeanCmsAlt(
id = generateUid(href), id = generateUid(href),
url = href, url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain), publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirstOrThrow("img").src().orEmpty(), coverUrl = div.selectFirst("img")?.src().orEmpty(),
title = div.selectFirstOrThrow(selectMangaTitle).text().orEmpty(), title = div.selectFirst(selectMangaTitle)?.text().orEmpty(),
altTitle = null, altTitle = null,
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
tags = emptySet(), tags = emptySet(),
@ -90,14 +90,14 @@ internal abstract class HeanCmsAlt(
val dateFormat = SimpleDateFormat(datePattern, sourceLocale) val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return manga.copy( return manga.copy(
altTitle = doc.selectFirst(selectAlt)?.text().orEmpty(), altTitle = doc.selectFirst(selectAlt)?.text().orEmpty(),
description = doc.selectFirstOrThrow(selectDesc).html(), description = doc.selectFirst(selectDesc)?.html(),
chapters = doc.select(selectChapter) chapters = doc.select(selectChapter)
.mapChapters(reversed = true) { i, a -> .mapChapters(reversed = true) { i, a ->
val dateText = a.selectFirstOrThrow(selectChapterDate).text() val dateText = a.selectFirst(selectChapterDate)?.text()
val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain) val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain)
MangaChapter( MangaChapter(
id = generateUid(url), id = generateUid(url),
name = a.selectFirstOrThrow(selectChapterTitle).text(), name = a.selectFirst(selectChapterTitle)?.text() ?: "Chapter : ${i + 1f}",
number = i + 1f, number = i + 1f,
volume = 0, volume = 0,
url = url, url = url,
@ -137,8 +137,6 @@ internal abstract class HeanCmsAlt(
} }
} }
// Parses dates in this form:
// 21 hours ago
private fun parseRelativeDate(date: String): Long { private fun parseRelativeDate(date: String): Long {
val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0 val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0
val cal = Calendar.getInstance() val cal = Calendar.getInstance()

@ -24,6 +24,10 @@ internal abstract class HotComicsParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override fun getRequestHeaders(): Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP)
.build()
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
@ -31,10 +35,6 @@ internal abstract class HotComicsParser(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST)
protected open val mangasUrl = "/genres"
protected open val onePage = false
protected open val isSearchSupported: Boolean = true protected open val isSearchSupported: Boolean = true
final override val filterCapabilities: MangaListFilterCapabilities final override val filterCapabilities: MangaListFilterCapabilities
@ -46,9 +46,9 @@ internal abstract class HotComicsParser(
availableTags = fetchAvailableTags(), availableTags = fetchAvailableTags(),
) )
override fun getRequestHeaders(): Headers = Headers.Builder() protected open val mangasUrl = "/genres"
.add("User-Agent", UserAgents.CHROME_DESKTOP)
.build() protected open val onePage = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
if (onePage && page > 1) { if (onePage && page > 1) {
@ -161,7 +161,6 @@ internal abstract class HotComicsParser(
) )
} }
protected open val selectPages = "#viewer-img img" protected open val selectPages = "#viewer-img img"
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {

@ -29,11 +29,17 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(), availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED), availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED),
availableContentTypes = EnumSet.of(
ContentType.MANGA,
ContentType.MANHWA,
ContentType.HENTAI,
),
) )
override fun getRequestHeaders(): Headers = Headers.Builder() override fun getRequestHeaders(): Headers = Headers.Builder()
@ -47,40 +53,58 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
addPathSegment("page") addPathSegment("page")
addPathSegment("$page/") addPathSegment("$page/")
when { addQueryParameter(
!filter.query.isNullOrEmpty() -> { "title",
addQueryParameter("title", filter.query) filter.query?.let {
} filter.query
},
else -> { )
addQueryParameter("title", "")
addQueryParameter( addQueryParameter(
"order", "order",
when (order) { when (order) {
SortOrder.UPDATED -> "update" SortOrder.UPDATED -> "update"
SortOrder.POPULARITY -> "popular" SortOrder.POPULARITY -> "popular"
SortOrder.ALPHABETICAL -> "title" SortOrder.ALPHABETICAL -> "title"
SortOrder.NEWEST -> "latest" SortOrder.NEWEST -> "latest"
else -> "latest" else -> "latest"
}, },
) )
filter.tags.forEach { filter.tags.forEach {
addEncodedQueryParameter("genre[]".urlEncoded(), it.key.urlEncoded()) addEncodedQueryParameter("genre[]".urlEncoded(), it.key.urlEncoded())
} }
filter.states.oneOrThrowIfMany()?.let { filter.states.oneOrThrowIfMany()?.let {
addEncodedQueryParameter( addEncodedQueryParameter(
"statusx", "statusx",
when (it) { when (it) {
MangaState.ONGOING -> "Publishing" MangaState.ONGOING -> "Publishing"
MangaState.FINISHED -> "Finished" MangaState.FINISHED -> "Finished"
else -> "" else -> ""
}, },
) )
}
}
} }
filter.types.oneOrThrowIfMany()?.let {
addQueryParameter(
"typex",
when (it) {
ContentType.MANGA -> "Manga"
ContentType.MANHWA -> "Manhwa"
ContentType.HENTAI -> "Doujinshi"
else -> ""
},
)
}
// Author
// addQueryParameter("author",
// filter.author?.let {
// filter.author
// }
// )
}.build() }.build()
return webClient.httpGet(url).parseHtml() return webClient.httpGet(url).parseHtml()

@ -12,10 +12,16 @@ import java.util.*
internal class HentaiCrot(context: MangaLoaderContext) : internal class HentaiCrot(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.HENTAICROT, 8) { PagedMangaParser(context, MangaParserSource.HENTAICROT, 8) {
override val configKeyDomain = ConfigKey.Domain("hentaicrot.com")
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys)
keys.add(userAgentKey)
}
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
) )
override val configKeyDomain = ConfigKey.Domain("hentaicrot.com")
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
@ -26,11 +32,6 @@ internal class HentaiCrot(context: MangaLoaderContext) :
availableTags = fetchAvailableTags(), availableTags = fetchAvailableTags(),
) )
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys)
keys.add(userAgentKey)
}
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")

@ -12,10 +12,16 @@ import java.util.*
internal class PixHentai(context: MangaLoaderContext) : internal class PixHentai(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.PIXHENTAI, 8) { PagedMangaParser(context, MangaParserSource.PIXHENTAI, 8) {
override val configKeyDomain = ConfigKey.Domain("pixhentai.com")
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys)
keys.add(userAgentKey)
}
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
) )
override val configKeyDomain = ConfigKey.Domain("pixhentai.com")
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
@ -26,11 +32,6 @@ internal class PixHentai(context: MangaLoaderContext) :
availableTags = fetchAvailableTags(), availableTags = fetchAvailableTags(),
) )
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys)
keys.add(userAgentKey)
}
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")

@ -0,0 +1,12 @@
package org.koitharu.kotatsu.parsers.site.mangareader.id
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("SOMANGA", "SoManga", "id")
internal class SoManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.SOMANGA, "so-manga.com", pageSize = 5, searchPageSize = 25) {
override val datePattern = "MMM d, yyyy"
}
Loading…
Cancel
Save