[ImHentai] add ContentTypes

add new ContentTypes
[iken] add SearchWithFilters, ContentTypes
[keyoapp] add SearchWithFilters
[likemanga] add POPULARITY_TODAY, POPULARITY_WEEK, POPULARITY_MONTH, SearchWithFilters
devi 2 years ago
parent 091c5247d5
commit d32d1f5044

@ -26,6 +26,11 @@ public enum class ContentType {
/** /**
* Use this type if no other suits your needs. For example, for an indie manga * Use this type if no other suits your needs. For example, for an indie manga
*/ */
OTHER,
ONE_SHOT, ONE_SHOT,
DOUJINSHI,
IMAGE_SET,
ARTIST_CG,
GAME_CG,
OTHER,
} }

@ -33,6 +33,14 @@ internal class ImHentai(context: MangaLoaderContext) :
availableLocales = setOf( availableLocales = setOf(
Locale.ENGLISH, Locale.JAPANESE, Locale("es"), Locale.FRENCH, Locale("kr"), Locale.GERMAN, Locale("ru"), 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<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
@ -63,6 +71,24 @@ internal class ImHentai(context: MangaLoaderContext) :
append(filter.tags.joinToString(separator = ",") { it.key }) 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" var lang = "&en=1&jp=1&es=1&fr=1&kr=1&de=1&ru=1"
filter.locale?.let { filter.locale?.let {
lang = "&en=0&jp=0&es=0&fr=0&kr=0&de=0&ru=0" 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.MANHUA,
ContentType.NOVEL, ContentType.NOVEL,
ContentType.ONE_SHOT, ContentType.ONE_SHOT,
ContentType.HENTAI, ContentType.DOUJINSHI,
ContentType.OTHER, ContentType.OTHER,
), ),
) )
@ -116,7 +116,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars
ContentType.MANHUA -> "manhua" ContentType.MANHUA -> "manhua"
ContentType.NOVEL -> "novel" ContentType.NOVEL -> "novel"
ContentType.ONE_SHOT -> "one_shot" ContentType.ONE_SHOT -> "one_shot"
ContentType.HENTAI -> "doujinshi" ContentType.DOUJINSHI -> "doujinshi"
ContentType.OTHER -> "oel" ContentType.OTHER -> "oel"
else -> "" else -> ""
}, },

@ -38,7 +38,7 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
availableContentTypes = EnumSet.of( availableContentTypes = EnumSet.of(
ContentType.MANGA, ContentType.MANGA,
ContentType.MANHWA, ContentType.MANHWA,
ContentType.HENTAI, ContentType.DOUJINSHI,
), ),
) )
@ -92,7 +92,7 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
when (it) { when (it) {
ContentType.MANGA -> "Manga" ContentType.MANGA -> "Manga"
ContentType.MANHWA -> "Manhwa" ContentType.MANHWA -> "Manhwa"
ContentType.HENTAI -> "Doujinshi" ContentType.DOUJINSHI -> "Doujinshi"
else -> "" else -> ""
}, },
) )

@ -30,8 +30,9 @@ internal abstract class IkenParser(
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true,
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
isMultipleTagsSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
@ -42,6 +43,12 @@ internal abstract class IkenParser(
MangaState.ABANDONED, MangaState.ABANDONED,
MangaState.UPCOMING, 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> { 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("/api/query?page=")
append(page) append(page)
append("&perPage=18&searchTerm=") append("&perPage=18&searchTerm=")
when {
filter.query?.let {
!filter.query.isNullOrEmpty() -> { append(filter.query.urlEncoded())
append(filter.query.urlEncoded()) }
}
if (filter.tags.isNotEmpty()) {
else -> { 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(
append("&seriesType=&seriesStatus=") when (it) {
filter.states.oneOrThrowIfMany()?.let { ContentType.MANGA -> "MANGA"
append( ContentType.MANHWA -> "MANHWA"
when (it) { ContentType.MANHUA -> "MANHUA"
MangaState.ONGOING -> "ONGOING" ContentType.OTHER -> "RUSSIAN"
MangaState.FINISHED -> "COMPLETED" else -> ""
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()) return parseMangaList(webClient.httpGet(url).parseJson())

@ -7,4 +7,4 @@ import org.koitharu.kotatsu.parsers.site.iken.IkenParser
@MangaSourceParser("MANGAGALAXY", "MangaGalaxy", "en") @MangaSourceParser("MANGAGALAXY", "MangaGalaxy", "en")
internal class MangaGalaxyParser(context: MangaLoaderContext) : 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") @MangaSourceParser("PHILIASCANS", "PhiliaScans", "en")
internal class PhiliaScans(context: MangaLoaderContext) : internal class PhiliaScans(context: MangaLoaderContext) :
IkenParser(context, MangaParserSource.PHILIASCANS, "vortextoon.com") { IkenParser(context, MangaParserSource.PHILIASCANS, "philiascans.com") {
override val selectPages = "main section img" override val selectPages = "main section img"
} }

@ -19,8 +19,20 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
MangaParser(context, MangaParserSource.NICOVIDEO_SEIGA), MangaParser(context, MangaParserSource.NICOVIDEO_SEIGA),
MangaParserAuthProvider { MangaParserAuthProvider {
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("nicovideo.jp")
override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP) 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 override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isSearchSupported = true, isSearchSupported = true,
@ -30,11 +42,6 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
availableTags = fetchAvailableTags(), availableTags = fetchAvailableTags(),
) )
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys)
keys.add(userAgentKey)
}
override val authUrl: String override val authUrl: String
get() = "https://${getDomain("account")}/login?site=seiga" 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) 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> { override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val page = (offset / 20f).toIntUp().inc() val page = (offset / 20f).toIntUp().inc()
val domain = getDomain("seiga") val domain = getDomain("seiga")
@ -65,7 +65,6 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
else -> { else -> {
if (filter.tags.isNotEmpty()) { if (filter.tags.isNotEmpty()) {
filter.tags.oneOrThrowIfMany().let { filter.tags.oneOrThrowIfMany().let {
"https://$domain/manga/list?category=${it?.key}&page=$page&sort=${getSortKey(order)}" "https://$domain/manga/list?category=${it?.key}&page=$page&sort=${getSortKey(order)}"

@ -58,6 +58,7 @@ internal abstract class KeyoappParser(
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
@ -70,28 +71,20 @@ internal abstract class KeyoappParser(
val url = urlBuilder().apply { val url = urlBuilder().apply {
when { filter.query?.let {
!filter.query.isNullOrEmpty() -> { query = filter.query
addPathSegment("series") }
query = filter.query
}
else -> {
if (filter.tags.isNotEmpty()) {
filter.tags.oneOrThrowIfMany()?.let {
tag = it.title
}
}
when (order) { filter.tags.oneOrThrowIfMany()?.let {
SortOrder.UPDATED -> addPathSegment("latest") tag = it.title
SortOrder.NEWEST -> addPathSegment("series") }
else -> addPathSegment("latest")
}
} when (order) {
SortOrder.UPDATED -> addPathSegment("latest")
SortOrder.NEWEST -> addPathSegment("series")
else -> addPathSegment("series")
} }
}.build() }.build()
return parseMangaList(webClient.httpGet(url).parseHtml(), tag, query) return parseMangaList(webClient.httpGet(url).parseHtml(), tag, query)

@ -30,11 +30,19 @@ internal abstract class LikeMangaParser(
} }
override val availableSortOrders: Set<SortOrder> = 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 override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
@ -48,50 +56,49 @@ internal abstract class LikeMangaParser(
append(domain) append(domain)
append("/?act=search") append("/?act=search")
when { filter.query?.let {
!filter.query.isNullOrEmpty() -> { append("&f")
append("&f") append("[keyword]".urlEncoded())
append("[keyword]".urlEncoded()) append("=")
append("=") append(filter.query.urlEncoded())
append(filter.query.urlEncoded()) }
}
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("&f") append("[sortby]".urlEncoded())
append("[genres]".urlEncoded()) append("=")
append("=") when (order) {
filter.tags.oneOrThrowIfMany()?.let { SortOrder.UPDATED -> append("lastest-chap")
append(it.key) 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")
}
filter.states.oneOrThrowIfMany()?.let { if (filter.tags.isNotEmpty()) {
append("&f") append("&f")
append("[status]".urlEncoded()) append("[genres]".urlEncoded())
append("=") append("=")
append( filter.tags.oneOrThrowIfMany()?.let {
when (it) { append(it.key)
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) { if (page > 1) {
append("&pageNum=") append("&pageNum=")
append(page) append(page)

Loading…
Cancel
Save