fix getlist some source mangaeader, MmrcmsParser

add filter on NepnepParser
devi 2 years ago
parent 743a92a3e8
commit 019b8cc087

@ -17,52 +17,58 @@ internal class SwaTeam(context: MangaLoaderContext) :
override val selectMangaListImg = "img" override val selectMangaListImg = "img"
override val isNetShieldProtected = true override val isNetShieldProtected = true
override suspend fun getListPage( override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (!query.isNullOrEmpty()) {
if (page > lastSearchPage) {
return emptyList()
}
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
when (filter) {
is MangaListFilter.Search -> {
append("/?s=") append("/?s=")
append(query.urlEncoded()) append(filter.query.urlEncoded())
append("&page=")
append(page)
} }
val docs = webClient.httpGet(url).parseHtml() is MangaListFilter.Advanced -> {
lastSearchPage = docs.selectFirst(".pagination .next") append(listUrl)
?.previousElementSibling()
?.text()?.toIntOrNull() ?: 1
return parseMangaList(docs)
}
val sortQuery = when (sortOrder) { append("/?order=")
append(
when (filter.sortOrder) {
SortOrder.ALPHABETICAL -> "a-z" SortOrder.ALPHABETICAL -> "a-z"
SortOrder.NEWEST -> "added" SortOrder.NEWEST -> "added"
SortOrder.POPULARITY -> "popular" SortOrder.POPULARITY -> "popular"
SortOrder.UPDATED -> "update" SortOrder.UPDATED -> "update"
else -> "" else -> ""
} },
)
val tagKey = "genre[]".urlEncoded() val tagKey = "genre[]".urlEncoded()
val tagQuery = val tagQuery =
if (tags.isNullOrEmpty()) "" else tags.joinToString(separator = "&", prefix = "&") { "$tagKey=${it.key}" } if (filter.tags.isEmpty()) ""
val url = buildString { else filter.tags.joinToString(separator = "&", prefix = "&") { "$tagKey=${it.key}" }
append("https://")
append(domain)
append(listUrl)
append("/?order=")
append(sortQuery)
append(tagQuery) append(tagQuery)
if (filter.states.isNotEmpty()) {
filter.states.oneOrThrowIfMany()?.let {
append("&status=")
when (it) {
MangaState.ONGOING -> append("ongoing")
MangaState.FINISHED -> append("completed")
MangaState.PAUSED -> append("hiatus")
else -> append("")
}
}
}
}
null -> {
append(listUrl)
append("/?order=update")
}
}
append("&page=") append("&page=")
append(page) append(page.toString())
} }
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())

@ -17,60 +17,54 @@ internal class ManhwaFreak(context: MangaLoaderContext) :
override val selectMangaList = ".listupd .lastest-serie" override val selectMangaList = ".listupd .lastest-serie"
override val selectMangaListImg = "img" override val selectMangaListImg = "img"
override val availableStates: Set<MangaState> = emptySet()
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (!query.isNullOrEmpty()) {
if (page > lastSearchPage) {
return emptyList()
}
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
when (filter) {
is MangaListFilter.Search -> {
append("/page/") append("/page/")
append(page) append(page.toString())
append("/?s=") append("/?s=")
append(query.urlEncoded()) append(filter.query.urlEncoded())
} }
val docs = webClient.httpGet(url).parseHtml()
lastSearchPage = docs.selectFirst(".pagination .next") is MangaListFilter.Advanced -> {
?.previousElementSibling()
?.text()?.toIntOrNull() ?: 1
return parseMangaList(docs)
}
if (!tags.isNullOrEmpty()) {
if (page > 1) { if (page > 1) {
return emptyList() return emptyList()
} }
val tag = tags.oneOrThrowIfMany()
val url = buildString { if (filter.tags.isNotEmpty()) {
append("https://")
append(domain)
append("/genres/?genre=") append("/genres/?genre=")
append(tag?.key.orEmpty()) append(
} filter.tags.oneOrThrowIfMany()?.let {
return parseMangaList(webClient.httpGet(url).parseHtml()) it.key
} },
if (page > 1) { )
return emptyList() } else {
} append(listUrl)
val sortQuery = when (sortOrder) { append("/?order=")
append(
when (filter.sortOrder) {
SortOrder.ALPHABETICAL -> "az" SortOrder.ALPHABETICAL -> "az"
SortOrder.NEWEST -> "new" SortOrder.NEWEST -> "new"
SortOrder.POPULARITY -> "views" SortOrder.POPULARITY -> "views"
SortOrder.UPDATED -> "" SortOrder.UPDATED -> ""
else -> "" else -> ""
},
)
} }
val url = buildString { }
append("https://")
append(domain) null -> {
append(listUrl) append(listUrl)
append("/?order=") }
append(sortQuery) }
} }
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }

@ -3,8 +3,9 @@ package org.koitharu.kotatsu.parsers.site.mangareader.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.Manga 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.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.domain import org.koitharu.kotatsu.parsers.util.domain
@ -19,31 +20,40 @@ internal class RizzComic(context: MangaLoaderContext) :
override val datePattern = "dd MMM yyyy" override val datePattern = "dd MMM yyyy"
override val listUrl = "/series" override val listUrl = "/series"
override val availableSortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
get() = EnumSet.of(SortOrder.ALPHABETICAL) override val availableStates: Set<MangaState> = emptySet()
override val isMultipleTagsSupported = false
override suspend fun getListPage( // TODO Query created in json
page: Int, override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
if (page > 1) { if (page > 1) {
return emptyList() return emptyList()
} }
if (!query.isNullOrEmpty()) { val url = buildString {
throw IllegalArgumentException("Search is not supported by this source")
}
val url = if (!tags.isNullOrEmpty()) {
buildString {
append("https://") append("https://")
append(domain) append(domain)
when (filter) {
is MangaListFilter.Search -> {
throw IllegalArgumentException("Search is not supported by this source")
}
is MangaListFilter.Advanced -> {
if (filter.tags.isNotEmpty()) {
append("/genre/") append("/genre/")
append(tag?.key.orEmpty()) filter.tags.oneOrThrowIfMany()?.let {
append(it.key)
} }
} else { } else {
"https://$domain$listUrl" append(listUrl)
}
}
null -> {
append(listUrl)
}
}
} }
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }

@ -3,11 +3,13 @@ package org.koitharu.kotatsu.parsers.site.mangareader.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.Manga 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.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.domain 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.parseHtml
import org.koitharu.kotatsu.parsers.util.urlEncoded import org.koitharu.kotatsu.parsers.util.urlEncoded
import java.util.* import java.util.*
@ -19,53 +21,34 @@ internal class Zahard(context: MangaLoaderContext) :
override val listUrl = "/library" override val listUrl = "/library"
override val selectChapter = "#chapterlist > ul > a" override val selectChapter = "#chapterlist > ul > a"
override val selectPage = "div#chapter_imgs img" override val selectPage = "div#chapter_imgs img"
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST)
override val availableStates: Set<MangaState> = emptySet()
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.NEWEST)
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (!query.isNullOrEmpty()) {
if (page > lastSearchPage) {
return emptyList()
}
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
append(listUrl) append(listUrl)
append("?search=") append("?page=")
append(query.urlEncoded()) append(page.toString())
append("&page=") when (filter) {
append(page)
}
val docs = webClient.httpGet(url).parseHtml() is MangaListFilter.Search -> {
lastSearchPage = docs.selectFirst("a[rel=next]") append("&search=")
?.previousElementSibling() append(filter.query.urlEncoded())
?.text()?.toIntOrNull() ?: 1
return parseMangaList(docs)
} }
val tagKey = "tag".urlEncoded() is MangaListFilter.Advanced -> {
val tagQuery = filter.tags.oneOrThrowIfMany()?.let {
if (tags.isNullOrEmpty()) "" else tags.joinToString(separator = "&", prefix = "&") { "$tagKey=${it.key}" } append("tag=")
val url = buildString { append(it.key)
append("https://") }
append(domain)
append(listUrl)
append("?page=")
append(page)
append(tagQuery)
} }
null -> {}
}
}
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }
} }

@ -12,41 +12,41 @@ import java.util.ArrayList
import java.util.Calendar import java.util.Calendar
import java.util.EnumSet import java.util.EnumSet
@MangaSourceParser("TU_MANHWAS", "TuManhwas", "es") @MangaSourceParser("TU_MANHWAS", "TuManhwas.com", "es")
internal class TuManhwas(context: MangaLoaderContext) : internal class TuManhwas(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.TU_MANHWAS, "tumanhwas.com", 20, 20) { MangaReaderParser(context, MangaSource.TU_MANHWAS, "tumanhwas.com", 20, 20) {
override val listUrl = "/biblioteca" override val listUrl = "/biblioteca"
override val selectPage = "div#readerarea img" override val selectPage = "div#readerarea img"
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST)
override val availableStates: Set<MangaState> = emptySet()
override val availableSortOrders: Set<SortOrder> override val isMultipleTagsSupported = false
get() = EnumSet.of(SortOrder.NEWEST)
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
override suspend fun getListPage(
page: Int, override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
append(listUrl) append(listUrl)
append("?page=") append("?page=")
append(page) append(page.toString())
if (!tags.isNullOrEmpty()) { when (filter) {
append("&genero=")
append(tag?.key.orEmpty()) is MangaListFilter.Search -> {
}
if (!query.isNullOrEmpty()) {
append("&search=") append("&search=")
append(query.urlEncoded()) append(filter.query.urlEncoded())
} }
is MangaListFilter.Advanced -> {
filter.tags.oneOrThrowIfMany()?.let {
append("&genero=")
append(it.key)
}
} }
null -> {}
}
}
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }

@ -18,61 +18,54 @@ internal class ManhwaFreakFr(context: MangaLoaderContext) :
override val selectMangaList = ".listupd .lastest-serie" override val selectMangaList = ".listupd .lastest-serie"
override val selectMangaListImg = "img" override val selectMangaListImg = "img"
override val sourceLocale: Locale = Locale.ENGLISH override val sourceLocale: Locale = Locale.ENGLISH
override val availableStates: Set<MangaState> = emptySet()
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (!query.isNullOrEmpty()) {
if (page > lastSearchPage) {
return emptyList()
}
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
when (filter) {
is MangaListFilter.Search -> {
append("/page/") append("/page/")
append(page) append(page.toString())
append("/?s=") append("/?s=")
append(query.urlEncoded()) append(filter.query.urlEncoded())
} }
val docs = webClient.httpGet(url).parseHtml()
lastSearchPage = docs.selectFirst(".pagination .next")
?.previousElementSibling()
?.text()?.toIntOrNull() ?: 1
return parseMangaList(docs)
}
if (!tags.isNullOrEmpty()) {
is MangaListFilter.Advanced -> {
if (page > 1) { if (page > 1) {
return emptyList() return emptyList()
} }
val tag = tags.oneOrThrowIfMany()
val url = buildString { if (filter.tags.isNotEmpty()) {
append("https://")
append(domain)
append("/genres/?genre=") append("/genres/?genre=")
append(tag?.key.orEmpty()) append(
} filter.tags.oneOrThrowIfMany()?.let {
return parseMangaList(webClient.httpGet(url).parseHtml()) it.key
} },
if (page > 1) { )
return emptyList() } else {
} append(listUrl)
val sortQuery = when (sortOrder) { append("/?order=")
append(
when (filter.sortOrder) {
SortOrder.ALPHABETICAL -> "az" SortOrder.ALPHABETICAL -> "az"
SortOrder.NEWEST -> "new" SortOrder.NEWEST -> "new"
SortOrder.POPULARITY -> "views" SortOrder.POPULARITY -> "views"
SortOrder.UPDATED -> "" SortOrder.UPDATED -> ""
else -> "" else -> ""
},
)
} }
val url = buildString { }
append("https://")
append(domain) null -> {
append(listUrl) append(listUrl)
append("/?order=") }
append(sortQuery) }
} }
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }

@ -3,13 +3,16 @@ package org.koitharu.kotatsu.parsers.site.mangareader.id
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.Manga 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.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.domain 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.parseHtml
import org.koitharu.kotatsu.parsers.util.urlEncoded import org.koitharu.kotatsu.parsers.util.urlEncoded
import java.util.EnumSet
import java.util.Locale import java.util.Locale
@MangaSourceParser("COSMIC_SCANS", "CosmicScans.id", "id") @MangaSourceParser("COSMIC_SCANS", "CosmicScans.id", "id")
@ -17,54 +20,50 @@ internal class CosmicScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.COSMIC_SCANS, "cosmicscans.id", pageSize = 30, searchPageSize = 30) { MangaReaderParser(context, MangaSource.COSMIC_SCANS, "cosmicscans.id", pageSize = 30, searchPageSize = 30) {
override val sourceLocale: Locale = Locale.ENGLISH override val sourceLocale: Locale = Locale.ENGLISH
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val availableStates: Set<MangaState> = emptySet()
override val isMultipleTagsSupported = false
override val listUrl = "/semua-komik" override val listUrl = "/semua-komik"
override suspend fun getListPage( override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (!query.isNullOrEmpty()) {
if (page > lastSearchPage) {
return emptyList()
}
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
when (filter) {
is MangaListFilter.Search -> {
append("/page/") append("/page/")
append(page) append(page.toString())
append("/?s=") append("/?s=")
append(query.urlEncoded()) append(filter.query.urlEncoded())
} }
val docs = webClient.httpGet(url).parseHtml()
lastSearchPage = docs.selectFirst(".pagination .next") is MangaListFilter.Advanced -> {
?.previousElementSibling() if (filter.tags.isNotEmpty()) {
?.text()?.toIntOrNull() ?: 1 filter.tags.oneOrThrowIfMany()?.let {
return parseMangaList(docs) append("/genres/")
append(it.key)
append("/page/")
append(page.toString())
append('/')
} }
} else {
if (page > 1) { if (page > 1) {
return emptyList() return emptyList()
} }
val sortQuery = when (sortOrder) { append(listUrl)
SortOrder.ALPHABETICAL -> "title" }
SortOrder.NEWEST -> "latest"
SortOrder.POPULARITY -> "popular" }
SortOrder.UPDATED -> "update"
else -> "" null -> {
if (page > 1) {
return emptyList()
} }
val tagKey = "genre[]".urlEncoded()
val tagQuery =
if (tags.isNullOrEmpty()) "" else tags.joinToString(separator = "&", prefix = "&") { "$tagKey=${it.key}" }
val url = buildString {
append("https://")
append(domain)
append(listUrl) append(listUrl)
append("/?order=") }
append(sortQuery) }
append(tagQuery)
append("&page=")
append(page)
} }
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }

@ -3,11 +3,13 @@ package org.koitharu.kotatsu.parsers.site.mangareader.id
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.Manga 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.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.domain 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.parseHtml
import org.koitharu.kotatsu.parsers.util.urlEncoded import org.koitharu.kotatsu.parsers.util.urlEncoded
@ -19,50 +21,61 @@ internal class KomikSan(context: MangaLoaderContext) :
override val listUrl = "/list" override val listUrl = "/list"
override val datePattern = "MMM d, yyyy" override val datePattern = "MMM d, yyyy"
override suspend fun getListPage( override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (!query.isNullOrEmpty()) {
if (page > lastSearchPage) {
return emptyList()
}
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
when (filter) {
is MangaListFilter.Search -> {
append("/search?search=") append("/search?search=")
append(query.urlEncoded()) append(filter.query.urlEncoded())
append("&page=") append("&page=")
append(page) append(page.toString())
}
val docs = webClient.httpGet(url).parseHtml()
lastSearchPage = docs.selectFirst(".pagination .next")
?.previousElementSibling()
?.text()?.toIntOrNull() ?: 1
return parseMangaList(docs)
} }
val sortQuery = when (sortOrder) {
is MangaListFilter.Advanced -> {
append(listUrl)
append("/?order=")
append(
when (filter.sortOrder) {
SortOrder.ALPHABETICAL -> "title" SortOrder.ALPHABETICAL -> "title"
SortOrder.NEWEST -> "latest" SortOrder.NEWEST -> "latest"
SortOrder.POPULARITY -> "popular" SortOrder.POPULARITY -> "popular"
SortOrder.UPDATED -> "update" SortOrder.UPDATED -> "update"
else -> "" else -> ""
} },
)
val tagKey = "genre[]".urlEncoded() val tagKey = "genre[]".urlEncoded()
val tagQuery = val tagQuery =
if (tags.isNullOrEmpty()) "" else tags.joinToString(separator = "&", prefix = "&") { "$tagKey=${it.key}" } if (filter.tags.isEmpty()) ""
val url = buildString { else filter.tags.joinToString(separator = "&", prefix = "&") { "$tagKey=${it.key}" }
append("https://")
append(domain)
append(listUrl)
append("/?order=")
append(sortQuery)
append(tagQuery) append(tagQuery)
if (filter.states.isNotEmpty()) {
filter.states.oneOrThrowIfMany()?.let {
append("&status=")
when (it) {
MangaState.ONGOING -> append("ongoing")
MangaState.FINISHED -> append("completed")
MangaState.PAUSED -> append("hiatus")
else -> append("")
}
}
}
append("&page=") append("&page=")
append(page) append(page.toString())
}
null -> {
append(listUrl)
append("/?order=update&page=")
append(page.toString())
}
}
} }
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }

@ -13,55 +13,70 @@ import java.util.*
@MangaSourceParser("KOMIKCAST", "KomikCast", "id") @MangaSourceParser("KOMIKCAST", "KomikCast", "id")
internal class Komikcast(context: MangaLoaderContext) : internal class Komikcast(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.KOMIKCAST, "komikcast.ch", pageSize = 60, searchPageSize = 28) { MangaReaderParser(context, MangaSource.KOMIKCAST, "komikcast.lol", pageSize = 60, searchPageSize = 28) {
override val listUrl = "/daftar-komik" override val listUrl = "/daftar-komik"
override val datePattern = "MMM d, yyyy" override val datePattern = "MMM d, yyyy"
override val sourceLocale: Locale = Locale.ENGLISH override val sourceLocale: Locale = Locale.ENGLISH
override val availableSortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder> =
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL)
override val availableStates: Set<MangaState> = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED)
override suspend fun getListPage(
page: Int, override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (!query.isNullOrEmpty()) {
if (page > lastSearchPage) {
return emptyList()
}
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
when (filter) {
is MangaListFilter.Search -> {
append("/page/") append("/page/")
append(page) append(page.toString())
append("/?s=") append("/?s=")
append(query.urlEncoded()) append(filter.query.urlEncoded())
}
val docs = webClient.httpGet(url).parseHtml()
lastSearchPage = docs.selectFirst(".pagination .next")
?.previousElementSibling()
?.text()?.toIntOrNull() ?: 1
return parseMangaList(docs)
} }
is MangaListFilter.Advanced -> {
append(listUrl)
append("/page/")
append(page.toString())
append("/?orderby=")
append(
when (filter.sortOrder) {
SortOrder.ALPHABETICAL -> append("titleasc")
SortOrder.POPULARITY -> append("popular")
SortOrder.UPDATED -> append("update")
else -> append("update")
},
)
val tagKey = "genre[]".urlEncoded() val tagKey = "genre[]".urlEncoded()
val tagQuery = val tagQuery =
if (tags.isNullOrEmpty()) "" else tags.joinToString(separator = "&", prefix = "&") { "$tagKey=${it.key}" } if (filter.tags.isEmpty()) ""
val url = buildString { else filter.tags.joinToString(separator = "&", prefix = "&") { "$tagKey=${it.key}" }
append("https://") append(tagQuery)
append(domain)
if (filter.states.isNotEmpty()) {
filter.states.oneOrThrowIfMany()?.let {
append("&status=")
when (it) {
MangaState.ONGOING -> append("Ongoing")
MangaState.FINISHED -> append("Completed")
else -> append("")
}
}
}
}
null -> {
append(listUrl) append(listUrl)
append("/page/") append("/?orderby=update&page=")
append(page) append(page.toString())
when (sortOrder) { }
SortOrder.ALPHABETICAL -> append("/?orderby=titleasc")
SortOrder.POPULARITY -> append("/?orderby=popular")
SortOrder.UPDATED -> append("/?sortby=update")
else -> append("/?sortby=update")
} }
append(tagQuery)
} }
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }

@ -55,49 +55,76 @@ internal abstract class MmrcmsParser(
"مكتملة", "مكتملة",
) )
override val isMultipleTagsSupported = false
protected open val imgUpdated = "/cover/cover_250x350.jpg" protected open val imgUpdated = "/cover/cover_250x350.jpg"
override suspend fun getListPage( override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
page: Int,
query: String?, when (filter) {
tags: Set<MangaTag>?,
sortOrder: SortOrder, is MangaListFilter.Search -> {
): List<Manga> { val url = buildString {
val tag = tags.oneOrThrowIfMany()
val url = if (!query.isNullOrEmpty() || !tags.isNullOrEmpty() || sortOrder != SortOrder.UPDATED) {
buildString {
append("https://") append("https://")
append(domain) append(domain)
append("/$listUrl/") append('/')
append("?page=") append(listUrl)
append("/?page=")
append(page.toString()) append(page.toString())
append("&asc=true&author=&tag=") append("&asc=true&author=&tag=&alpha=")
append("&alpha=") append(filter.query.urlEncoded())
if (!query.isNullOrEmpty()) { append("&cat=&sortBy=views")
append(query.urlEncoded()) }
return parseMangaList(webClient.httpGet(url).parseHtml())
} }
append("&cat=")
if (!tags.isNullOrEmpty()) { is MangaListFilter.Advanced -> {
append(tag?.key.orEmpty())
if (filter.sortOrder == SortOrder.UPDATED) {
val url = buildString {
append("https://")
append(domain)
append("/latest-release?page=")
append(page.toString())
}
return parseMangaListUpdated(webClient.httpGet(url).parseHtml())
} else {
val url = buildString {
append("https://")
append(domain)
append('/')
append(listUrl)
append("/?page=")
append(page.toString())
append("&asc=true&author=&tag=&alpha=&cat=")
filter.tags.oneOrThrowIfMany()?.let {
append(it.key)
} }
append("&sortBy=") append("&sortBy=")
when (sortOrder) { when (filter.sortOrder) {
SortOrder.POPULARITY -> append("views") SortOrder.POPULARITY -> append("views")
SortOrder.ALPHABETICAL -> append("name") SortOrder.ALPHABETICAL -> append("name")
else -> append("name") else -> append("name")
} }
} }
} else { return parseMangaList(webClient.httpGet(url).parseHtml())
buildString { }
}
null -> {
val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
append("/latest-release") append("/latest-release?page=")
append("?page=")
append(page.toString()) append(page.toString())
} }
return parseMangaList(webClient.httpGet(url).parseHtml())
}
}
} }
val doc = webClient.httpGet(url).parseHtml()
if (!query.isNullOrEmpty() || !tags.isNullOrEmpty() || sortOrder != SortOrder.UPDATED) { protected open fun parseMangaList(doc: Document): List<Manga> {
return doc.select("div.media").map { div -> return doc.select("div.media").map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
Manga( Manga(
@ -115,7 +142,9 @@ internal abstract class MmrcmsParser(
isNsfw = isNsfwSource, isNsfw = isNsfwSource,
) )
} }
} else { }
protected open fun parseMangaListUpdated(doc: Document): List<Manga> {
return doc.select("div.manga-item").map { div -> return doc.select("div.manga-item").map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
val deeplink = href.substringAfterLast("/") val deeplink = href.substringAfterLast("/")
@ -136,8 +165,6 @@ internal abstract class MmrcmsParser(
} }
} }
}
override suspend fun getAvailableTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$tagUrl/").parseHtml() val doc = webClient.httpGet("https://$domain/$tagUrl/").parseHtml()
return doc.select("ul.list-category li").mapNotNullToSet { li -> return doc.select("ul.list-category li").mapNotNullToSet { li ->

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mmrcms.ar
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Document
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.*
@ -19,66 +20,8 @@ internal class Onma(context: MangaLoaderContext) :
override val selectAut = "h3:contains(المؤلف) .text" override val selectAut = "h3:contains(المؤلف) .text"
override val selectTag = "h3:contains(التصنيفات) .text" override val selectTag = "h3:contains(التصنيفات) .text"
override suspend fun getListPage(
page: Int, override fun parseMangaList(doc: Document): List<Manga> {
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = if (sortOrder == SortOrder.UPDATED) {
buildString {
append("https://")
append(domain)
append("/latest-release")
append("?page=")
append(page.toString())
}
} else {
buildString {
append("https://")
append(domain)
append("/$listUrl/")
append("?page=")
append(page.toString())
append("&asc=true&author=&tag=")
append("&alpha=")
if (!query.isNullOrEmpty()) {
append(query.urlEncoded())
}
append("&cat=")
if (!tags.isNullOrEmpty()) {
append(tag?.key.orEmpty())
}
append("&sortBy=")
when (sortOrder) {
SortOrder.POPULARITY -> append("views")
SortOrder.ALPHABETICAL -> append("name")
else -> append("views")
}
}
}
val doc = webClient.httpGet(url).parseHtml()
if (sortOrder == SortOrder.UPDATED) {
return doc.select("div.manga-item").map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
val deeplink = href.substringAfterLast('/')
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = "https://$domain/uploads/manga/$deeplink$imgUpdated",
title = div.selectFirstOrThrow("div.content-left a").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = isNsfwSource,
)
}
} else {
return doc.select("div.chapter-container").map { div -> return doc.select("div.chapter-container").map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
Manga( Manga(
@ -97,7 +40,6 @@ internal class Onma(context: MangaLoaderContext) :
) )
} }
} }
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope { override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain) val fullUrl = manga.url.toAbsoluteUrl(domain)

@ -1,18 +1,14 @@
package org.koitharu.kotatsu.parsers.site.mmrcms.id package org.koitharu.kotatsu.parsers.site.mmrcms.id
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.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mmrcms.MmrcmsParser import org.koitharu.kotatsu.parsers.site.mmrcms.MmrcmsParser
import java.util.Locale import java.util.Locale
@MangaSourceParser("MANGAID", "MangaId", "id") @MangaSourceParser("MANGAID", "MangaId", "id")
internal class Mangaid(context: MangaLoaderContext) : internal class Mangaid(context: MangaLoaderContext) :
MmrcmsParser(context, MangaSource.MANGAID, "mangaid.click") { MmrcmsParser(context, MangaSource.MANGAID, "mangaid.click") {
override val selectState = "dt:contains(Status)" override val selectState = "dt:contains(Status)"
override val selectAlt = "dt:contains(Other names)" override val selectAlt = "dt:contains(Other names)"
override val selectAut = "dt:contains(Author(s))" override val selectAut = "dt:contains(Author(s))"

@ -24,15 +24,20 @@ internal abstract class NepnepParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
override val availableStates: Set<MangaState> = EnumSet.allOf(MangaState::class.java)
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP) .add("User-Agent", UserAgents.CHROME_DESKTOP)
.build() .build()
override suspend fun getList(offset: Int, query: String?, tags: Set<MangaTag>?, sortOrder: SortOrder): List<Manga> { override suspend fun getList(offset: Int, filter: MangaListFilter?): List<Manga> {
if (offset > 0) { if (offset > 0) {
return emptyList() return emptyList()
} }
var foundTag = true
var foundState = true
val doc = webClient.httpGet("https://$domain/search/").parseHtml() val doc = webClient.httpGet("https://$domain/search/").parseHtml()
val json = JSONArray( val json = JSONArray(
doc.selectFirstOrThrow("script:containsData(MainFunction)").data() doc.selectFirstOrThrow("script:containsData(MainFunction)").data()
@ -41,18 +46,18 @@ internal abstract class NepnepParser(
.trim() .trim()
.replace(';', ' '), .replace(';', ' '),
) )
val manga = ArrayList<Manga>(json.length()) val manga = ArrayList<Manga>(json.length())
for (i in 0 until json.length()) { for (i in 0 until json.length()) {
val m = json.getJSONObject(i) val m = json.getJSONObject(i)
val href = "/manga/" + m.getString("i") val href = "/manga/" + m.getString("i")
val imgUrl = "https://temp.compsci88.com/cover/" + m.getString("i") + ".jpg" val imgUrl = "https://temp.compsci88.com/cover/" + m.getString("i") + ".jpg"
when { when (filter) {
!query.isNullOrEmpty() -> {
if (m.getString("s").contains(query, ignoreCase = true) || m.getString("al") is MangaListFilter.Search -> {
.contains(query, ignoreCase = true) if (m.getString("s").contains(filter.query, ignoreCase = true) || m.getString("al")
.contains(filter.query, ignoreCase = true)
) { ) {
manga.add( manga.add(
addManga(href, imgUrl, m), addManga(href, imgUrl, m),
@ -60,29 +65,49 @@ internal abstract class NepnepParser(
} }
} }
!tags.isNullOrEmpty() -> { is MangaListFilter.Advanced -> {
val a = m.getJSONArray("g").toString()
var found = true if (filter.tags.isNotEmpty()) {
tags.forEach { val tagsJon = m.getJSONArray("g").toString()
if (!a.contains(it.key, ignoreCase = true)) { filter.tags.forEach {
found = false foundTag = false
if (tagsJon.contains(it.key, ignoreCase = true)) {
foundTag = true
} }
} }
if (found) { }
manga.add(
addManga(href, imgUrl, m), if (filter.states.isNotEmpty()) {
val stateJson = m.getString("ps")
filter.states.oneOrThrowIfMany().let {
foundState = false
if (stateJson.contains(
when (it) {
MangaState.ONGOING -> "Ongoing"
MangaState.FINISHED -> "Complete"
MangaState.ABANDONED -> "Cancelled"
MangaState.PAUSED -> "Hiatus"
else -> ""
},
ignoreCase = true,
) )
) {
foundState = true
}
} }
} }
else -> { if (foundTag && foundState) {
manga.add(addManga(href, imgUrl, m))
}
}
null -> {
manga.add( manga.add(
addManga(href, imgUrl, m), addManga(href, imgUrl, m),
) )
} }
} }
} }
return manga return manga
} }

Loading…
Cancel
Save