[ImHentai] add ContentTypes
add new ContentTypes [iken] add SearchWithFilters, ContentTypes [keyoapp] add SearchWithFilters [likemanga] add POPULARITY_TODAY, POPULARITY_WEEK, POPULARITY_MONTH, SearchWithFilters
This commit is contained in:
@@ -26,6 +26,11 @@ public enum class ContentType {
|
||||
/**
|
||||
* Use this type if no other suits your needs. For example, for an indie manga
|
||||
*/
|
||||
OTHER,
|
||||
|
||||
ONE_SHOT,
|
||||
DOUJINSHI,
|
||||
IMAGE_SET,
|
||||
ARTIST_CG,
|
||||
GAME_CG,
|
||||
OTHER,
|
||||
}
|
||||
|
||||
@@ -33,6 +33,14 @@ internal class ImHentai(context: MangaLoaderContext) :
|
||||
availableLocales = setOf(
|
||||
Locale.ENGLISH, Locale.JAPANESE, Locale("es"), Locale.FRENCH, Locale("kr"), Locale.GERMAN, Locale("ru"),
|
||||
),
|
||||
availableContentTypes = EnumSet.of(
|
||||
ContentType.MANGA,
|
||||
ContentType.DOUJINSHI,
|
||||
ContentType.COMICS,
|
||||
ContentType.IMAGE_SET,
|
||||
ContentType.ARTIST_CG,
|
||||
ContentType.GAME_CG,
|
||||
),
|
||||
)
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
@@ -63,6 +71,24 @@ internal class ImHentai(context: MangaLoaderContext) :
|
||||
append(filter.tags.joinToString(separator = ",") { it.key })
|
||||
}
|
||||
|
||||
var types = "&m=1&d=1&w=1&i=1&a=1&g=1"
|
||||
if (filter.types.isNotEmpty()) {
|
||||
types = "&m=0&d=0&w=0&i=0&a=0&g=0"
|
||||
filter.types.forEach {
|
||||
when (it) {
|
||||
ContentType.MANGA -> types = types.replace("&m=0", "&m=1")
|
||||
ContentType.DOUJINSHI -> types = types.replace("&d=0", "&d=1")
|
||||
ContentType.COMICS -> types = types.replace("&w=0", "&w=1")
|
||||
ContentType.IMAGE_SET -> types = types.replace("&i=0", "&i=1")
|
||||
ContentType.ARTIST_CG -> types = types.replace("&a=0", "&a=1")
|
||||
ContentType.GAME_CG -> types = types.replace("&g=0", "&g=1")
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
append(types)
|
||||
|
||||
|
||||
var lang = "&en=1&jp=1&es=1&fr=1&kr=1&de=1&ru=1"
|
||||
filter.locale?.let {
|
||||
lang = "&en=0&jp=0&es=0&fr=0&kr=0&de=0&ru=0"
|
||||
|
||||
@@ -62,7 +62,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars
|
||||
ContentType.MANHUA,
|
||||
ContentType.NOVEL,
|
||||
ContentType.ONE_SHOT,
|
||||
ContentType.HENTAI,
|
||||
ContentType.DOUJINSHI,
|
||||
ContentType.OTHER,
|
||||
),
|
||||
)
|
||||
@@ -116,7 +116,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars
|
||||
ContentType.MANHUA -> "manhua"
|
||||
ContentType.NOVEL -> "novel"
|
||||
ContentType.ONE_SHOT -> "one_shot"
|
||||
ContentType.HENTAI -> "doujinshi"
|
||||
ContentType.DOUJINSHI -> "doujinshi"
|
||||
ContentType.OTHER -> "oel"
|
||||
else -> ""
|
||||
},
|
||||
|
||||
@@ -38,7 +38,7 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
|
||||
availableContentTypes = EnumSet.of(
|
||||
ContentType.MANGA,
|
||||
ContentType.MANHWA,
|
||||
ContentType.HENTAI,
|
||||
ContentType.DOUJINSHI,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -92,7 +92,7 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
|
||||
when (it) {
|
||||
ContentType.MANGA -> "Manga"
|
||||
ContentType.MANHWA -> "Manhwa"
|
||||
ContentType.HENTAI -> "Doujinshi"
|
||||
ContentType.DOUJINSHI -> "Doujinshi"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
|
||||
@@ -30,8 +30,9 @@ internal abstract class IkenParser(
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
isMultipleTagsSupported = true,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
@@ -42,6 +43,12 @@ internal abstract class IkenParser(
|
||||
MangaState.ABANDONED,
|
||||
MangaState.UPCOMING,
|
||||
),
|
||||
availableContentTypes = EnumSet.of(
|
||||
ContentType.MANGA,
|
||||
ContentType.MANHUA,
|
||||
ContentType.MANHWA,
|
||||
ContentType.OTHER,
|
||||
),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
||||
@@ -51,32 +58,40 @@ internal abstract class IkenParser(
|
||||
append("/api/query?page=")
|
||||
append(page)
|
||||
append("&perPage=18&searchTerm=")
|
||||
when {
|
||||
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
filter.query?.let {
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
append("&genreIds=")
|
||||
filter.tags.joinTo(this, ",") { it.key }
|
||||
}
|
||||
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
append("&genreIds=")
|
||||
filter.tags.joinTo(this, ",") { it.key }
|
||||
}
|
||||
append("&seriesType=")
|
||||
filter.types.oneOrThrowIfMany()?.let {
|
||||
append(
|
||||
when (it) {
|
||||
ContentType.MANGA -> "MANGA"
|
||||
ContentType.MANHWA -> "MANHWA"
|
||||
ContentType.MANHUA -> "MANHUA"
|
||||
ContentType.OTHER -> "RUSSIAN"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
append("&seriesType=&seriesStatus=")
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "ONGOING"
|
||||
MangaState.FINISHED -> "COMPLETED"
|
||||
MangaState.UPCOMING -> "COMING_SOON"
|
||||
MangaState.ABANDONED -> "DROPPED"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
append("&seriesStatus=")
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "ONGOING"
|
||||
MangaState.FINISHED -> "COMPLETED"
|
||||
MangaState.UPCOMING -> "COMING_SOON"
|
||||
MangaState.ABANDONED -> "DROPPED"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
return parseMangaList(webClient.httpGet(url).parseJson())
|
||||
|
||||
@@ -7,4 +7,4 @@ import org.koitharu.kotatsu.parsers.site.iken.IkenParser
|
||||
|
||||
@MangaSourceParser("MANGAGALAXY", "MangaGalaxy", "en")
|
||||
internal class MangaGalaxyParser(context: MangaLoaderContext) :
|
||||
IkenParser(context, MangaParserSource.MANGAGALAXY, "mangagalaxy.org")
|
||||
IkenParser(context, MangaParserSource.MANGAGALAXY, "mangagalaxy.net")
|
||||
|
||||
@@ -7,6 +7,6 @@ import org.koitharu.kotatsu.parsers.site.iken.IkenParser
|
||||
|
||||
@MangaSourceParser("PHILIASCANS", "PhiliaScans", "en")
|
||||
internal class PhiliaScans(context: MangaLoaderContext) :
|
||||
IkenParser(context, MangaParserSource.PHILIASCANS, "vortextoon.com") {
|
||||
IkenParser(context, MangaParserSource.PHILIASCANS, "philiascans.com") {
|
||||
override val selectPages = "main section img"
|
||||
}
|
||||
|
||||
@@ -19,8 +19,20 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
|
||||
MangaParser(context, MangaParserSource.NICOVIDEO_SEIGA),
|
||||
MangaParserAuthProvider {
|
||||
|
||||
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("nicovideo.jp")
|
||||
|
||||
override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP)
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
}
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.POPULARITY,
|
||||
)
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isSearchSupported = true,
|
||||
@@ -30,11 +42,6 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
|
||||
availableTags = fetchAvailableTags(),
|
||||
)
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
}
|
||||
|
||||
override val authUrl: String
|
||||
get() = "https://${getDomain("account")}/login?site=seiga"
|
||||
|
||||
@@ -48,13 +55,6 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
|
||||
return body.selectFirst("#userinfo > div > div > strong")?.text() ?: throw AuthRequiredException(source)
|
||||
}
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.POPULARITY,
|
||||
)
|
||||
|
||||
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("nicovideo.jp")
|
||||
|
||||
override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
||||
val page = (offset / 20f).toIntUp().inc()
|
||||
val domain = getDomain("seiga")
|
||||
@@ -65,7 +65,6 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
|
||||
|
||||
else -> {
|
||||
|
||||
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany().let {
|
||||
"https://$domain/manga/list?category=${it?.key}&page=$page&sort=${getSortKey(order)}"
|
||||
|
||||
@@ -58,6 +58,7 @@ internal abstract class KeyoappParser(
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
@@ -70,28 +71,20 @@ internal abstract class KeyoappParser(
|
||||
|
||||
val url = urlBuilder().apply {
|
||||
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
addPathSegment("series")
|
||||
query = filter.query
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
tag = it.title
|
||||
}
|
||||
}
|
||||
|
||||
when (order) {
|
||||
SortOrder.UPDATED -> addPathSegment("latest")
|
||||
SortOrder.NEWEST -> addPathSegment("series")
|
||||
else -> addPathSegment("latest")
|
||||
}
|
||||
|
||||
}
|
||||
filter.query?.let {
|
||||
query = filter.query
|
||||
}
|
||||
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
tag = it.title
|
||||
}
|
||||
|
||||
when (order) {
|
||||
SortOrder.UPDATED -> addPathSegment("latest")
|
||||
SortOrder.NEWEST -> addPathSegment("series")
|
||||
else -> addPathSegment("series")
|
||||
}
|
||||
|
||||
}.build()
|
||||
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml(), tag, query)
|
||||
|
||||
@@ -30,11 +30,19 @@ internal abstract class LikeMangaParser(
|
||||
}
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> =
|
||||
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST)
|
||||
EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.POPULARITY,
|
||||
SortOrder.NEWEST,
|
||||
SortOrder.POPULARITY_TODAY,
|
||||
SortOrder.POPULARITY_WEEK,
|
||||
SortOrder.POPULARITY_MONTH,
|
||||
)
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
@@ -48,48 +56,47 @@ internal abstract class LikeMangaParser(
|
||||
append(domain)
|
||||
append("/?act=search")
|
||||
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
append("&f")
|
||||
append("[keyword]".urlEncoded())
|
||||
append("=")
|
||||
append(filter.query.urlEncoded())
|
||||
filter.query?.let {
|
||||
append("&f")
|
||||
append("[keyword]".urlEncoded())
|
||||
append("=")
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
|
||||
append("&f")
|
||||
append("[sortby]".urlEncoded())
|
||||
append("=")
|
||||
when (order) {
|
||||
SortOrder.UPDATED -> append("lastest-chap")
|
||||
SortOrder.NEWEST -> append("lastest-manga")
|
||||
SortOrder.POPULARITY -> append("top-manga")
|
||||
SortOrder.POPULARITY_TODAY -> append("top-day")
|
||||
SortOrder.POPULARITY_WEEK -> append("top-week")
|
||||
SortOrder.POPULARITY_MONTH -> append("top-month")
|
||||
else -> append("lastest-chap")
|
||||
}
|
||||
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
append("&f")
|
||||
append("[genres]".urlEncoded())
|
||||
append("=")
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
append(it.key)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
append("&f")
|
||||
append("[sortby]".urlEncoded())
|
||||
append("=")
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> append("hot")
|
||||
SortOrder.UPDATED -> append("lastest-chap")
|
||||
SortOrder.NEWEST -> append("lastest-manga")
|
||||
else -> append("lastest-chap")
|
||||
}
|
||||
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
append("&f")
|
||||
append("[genres]".urlEncoded())
|
||||
append("=")
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
append(it.key)
|
||||
}
|
||||
}
|
||||
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("&f")
|
||||
append("[status]".urlEncoded())
|
||||
append("=")
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "in-process"
|
||||
MangaState.FINISHED -> "complete"
|
||||
MangaState.PAUSED -> "pause"
|
||||
else -> "all"
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("&f")
|
||||
append("[status]".urlEncoded())
|
||||
append("=")
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "in-process"
|
||||
MangaState.FINISHED -> "complete"
|
||||
MangaState.PAUSED -> "pause"
|
||||
else -> "all"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (page > 1) {
|
||||
|
||||
Reference in New Issue
Block a user