diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/ContentType.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/ContentType.kt index b8a2e000..2027fe7a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/ContentType.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/ContentType.kt @@ -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, } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ImHentai.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ImHentai.kt index fb5262b7..0d9fb09a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ImHentai.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ImHentai.kt @@ -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>) { @@ -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" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TuMangaOnlineParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TuMangaOnlineParser.kt index 1fd7af85..9ea529fa 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TuMangaOnlineParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TuMangaOnlineParser.kt @@ -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 -> "" }, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt index 3d7ba5ea..c92ae232 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt @@ -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 -> "" }, ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt index 5f3998d7..805384a8 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt @@ -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 { @@ -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()) - } - - else -> { - - if (filter.tags.isNotEmpty()) { - append("&genreIds=") - filter.tags.joinTo(this, ",") { it.key } - } - - append("&seriesType=&seriesStatus=") - filter.states.oneOrThrowIfMany()?.let { - append( - when (it) { - MangaState.ONGOING -> "ONGOING" - MangaState.FINISHED -> "COMPLETED" - MangaState.UPCOMING -> "COMING_SOON" - MangaState.ABANDONED -> "DROPPED" - else -> "" - }, - ) - } - } + + filter.query?.let { + append(filter.query.urlEncoded()) + } + + 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("&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()) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/MangaGalaxyParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/MangaGalaxyParser.kt index 9bb19c95..d76c7bb6 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/MangaGalaxyParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/MangaGalaxyParser.kt @@ -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") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/PhiliaScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/PhiliaScans.kt index b71098f1..dd02a9f3 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/PhiliaScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/PhiliaScans.kt @@ -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" } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ja/NicovideoSeigaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ja/NicovideoSeigaParser.kt index 021d5fd3..9b636c36 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ja/NicovideoSeigaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ja/NicovideoSeigaParser.kt @@ -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>) { + super.onCreateConfig(keys) + keys.add(userAgentKey) + } + + override val availableSortOrders: Set = 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>) { - 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 = 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 { 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)}" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/keyoapp/KeyoappParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/keyoapp/KeyoappParser.kt index dfd5b392..77cb40b3 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/keyoapp/KeyoappParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/keyoapp/KeyoappParser.kt @@ -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 - } - } + filter.query?.let { + query = filter.query + } - when (order) { - SortOrder.UPDATED -> addPathSegment("latest") - SortOrder.NEWEST -> addPathSegment("series") - else -> addPathSegment("latest") - } + 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) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/likemanga/LikeMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/likemanga/LikeMangaParser.kt index 4b9d4e5d..2dca899c 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/likemanga/LikeMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/likemanga/LikeMangaParser.kt @@ -30,11 +30,19 @@ internal abstract class LikeMangaParser( } override val availableSortOrders: Set = - 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,50 +56,49 @@ internal abstract class LikeMangaParser( append(domain) append("/?act=search") - when { - !filter.query.isNullOrEmpty() -> { - append("&f") - append("[keyword]".urlEncoded()) - append("=") - 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") - } + filter.query?.let { + append("&f") + append("[keyword]".urlEncoded()) + append("=") + append(filter.query.urlEncoded()) + } - if (filter.tags.isNotEmpty()) { - append("&f") - append("[genres]".urlEncoded()) - append("=") - filter.tags.oneOrThrowIfMany()?.let { - append(it.key) - } - } + 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") + } - 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 (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" + }, + ) + } + if (page > 1) { append("&pageNum=") append(page)