Add exception for source don't support multi tags

and other fix
Add birdToon
pull/232/head
devi 3 years ago
parent da344233f4
commit 896139a8ed

@ -44,6 +44,7 @@ internal abstract class AnimeBootstrapParser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -59,9 +60,7 @@ internal abstract class AnimeBootstrapParser(
if (!tags.isNullOrEmpty()) {
append("&categorie=")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
}
append("&sort=")

@ -6,27 +6,9 @@ import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.animebootstrap.AnimeBootstrapParser
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrl
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.host
import org.koitharu.kotatsu.parsers.util.mapChapters
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.removeSuffix
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.toTitleCase
import org.koitharu.kotatsu.parsers.util.tryParse
import org.koitharu.kotatsu.parsers.util.urlEncoded
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.EnumSet
import java.util.Locale
@ -56,6 +38,9 @@ internal class PapScan(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -70,9 +55,7 @@ internal class PapScan(context: MangaLoaderContext) :
if (!tags.isNullOrEmpty()) {
append("&cat=")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
}
append("&sortBy=")
when (sortOrder) {

@ -54,6 +54,7 @@ internal abstract class FmreaderParser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -69,9 +70,7 @@ internal abstract class FmreaderParser(
!tags.isNullOrEmpty() -> {
append("&genre=")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
}
}
@ -92,8 +91,9 @@ internal abstract class FmreaderParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirstOrThrow("div.img-in-ratio").attr("style").substringAfter("('")
.substringBeforeLast("')"),
coverUrl = div.selectFirstOrThrow("div.img-in-ratio").attr("data-bg")
?: div.selectFirstOrThrow("div.img-in-ratio").attr("style").substringAfter("('")
.substringBeforeLast("')"),
title = div.selectFirstOrThrow("div.series-title").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
@ -106,10 +106,11 @@ internal abstract class FmreaderParser(
}
}
protected open val selectBodyTag = "ul.filter-type li a"
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listeurl").parseHtml()
return doc.select("ul.filter-type li").mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfter("manga-list-genre-").substringBeforeLast(".html")
MangaTag(
key = href,

@ -6,22 +6,9 @@ import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.fmreader.FmreaderParser
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrl
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.mapChapters
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.toTitleCase
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
@MangaSourceParser("MANHWA18COM", "Manhwa18 Com", "en", ContentType.HENTAI)
@ -35,6 +22,87 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
override val selectTag = "div.info-item:contains(Genre) span.info-value a"
override val datePattern = "dd/MM/yyyy"
override val selectPage = "div#chapter-content img"
override val selectBodyTag = "div.genres-menu a"
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
if (!tags.isNullOrEmpty()) {
append("/genre/")
append(tag?.key.orEmpty())
append("?page=")
append(page.toString())
append("&sort=")
when (sortOrder) {
SortOrder.POPULARITY -> append("views")
SortOrder.UPDATED -> append("last_update")
SortOrder.ALPHABETICAL -> append("name")
else -> append("last_update")
}
} else {
append(listeurl)
append("?page=")
append(page.toString())
when {
!query.isNullOrEmpty() -> {
append("&q=")
append(query.urlEncoded())
}
}
append("&sort=")
when (sortOrder) {
SortOrder.POPULARITY -> append("views")
SortOrder.UPDATED -> append("last_update")
SortOrder.ALPHABETICAL -> append("name")
else -> append("last_update")
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.thumb-item-flow").map { div ->
val href = div.selectFirstOrThrow("div.series-title a").attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirstOrThrow("div.img-in-ratio").attr("data-bg")
?: div.selectFirstOrThrow("div.img-in-ratio").attr("style").substringAfter("('")
.substringBeforeLast("')"),
title = div.selectFirstOrThrow("div.series-title").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = isNsfwSource,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listeurl").parseHtml()
return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("/")
MangaTag(
key = href,
title = a.text(),
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)

@ -27,6 +27,7 @@ internal class Klz9(context: MangaLoaderContext) :
override val selectChapter = "tr"
override val selectDate = "td i"
override val selectPage = "img"
override val selectBodyTag = "div.panel-body a"
override suspend fun getListPage(
page: Int,
@ -34,6 +35,7 @@ internal class Klz9(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -49,9 +51,7 @@ internal class Klz9(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("&genre=")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
}
}

@ -137,13 +137,12 @@ internal abstract class MadaraParser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val doc = if (withoutAjax) {
val url = buildString {
append("https://")
append(domain)
val pages = page + 1
when {
!query.isNullOrEmpty() -> {
append("/page/")
@ -155,9 +154,7 @@ internal abstract class MadaraParser(
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/page/")
append(pages.toString())
append("?")
@ -182,8 +179,6 @@ internal abstract class MadaraParser(
}
webClient.httpGet(url).parseHtml()
} else {
val tag = tags.oneOrThrowIfMany()
val payload = if (sortOrder == SortOrder.RATING) {
createRequestTemplate(ratingRequest)
} else {
@ -553,10 +548,13 @@ internal abstract class MadaraParser(
}
}
private val ratingRequest = "action=madara_load_more&page=1&template=madara-core%2Fcontent%2Fcontent-search&vars%5Bs%5D=&vars%5Borderby%5D%5Bquery_avarage_reviews%5D=DESC&vars%5Borderby%5D%5Bquery_total_reviews%5D=DESC&vars%5Bpaged%5D=1&vars%5Btemplate%5D=search&vars%5Bmeta_query%5D%5B0%5D%5Brelation%5D=AND&vars%5Bmeta_query%5D%5B0%5D%5Bquery_avarage_reviews%5D%5Bkey%5D=_manga_avarage_reviews&vars%5Bmeta_query%5D%5B0%5D%5Bquery_total_reviews%5D%5Bkey%5D=_manga_total_votes&vars%5Bmeta_query%5D%5Brelation%5D=AND&vars%5Bpost_type%5D=wp-manga&vars%5Bpost_status%5D=publish&vars%5Bmanga_archives_item_layout%5D=default"
private val defaultRequest = "action=madara_load_more&page=1&template=madara-core%2Fcontent%2Fcontent-search&vars%5Bs%5D=&vars%5Borderby%5D=meta_value_num&vars%5Bpaged%5D=1&vars%5Btemplate%5D=search&vars%5Bmeta_query%5D%5B0%5D%5Brelation%5D=AND&vars%5Bmeta_query%5D%5Brelation%5D=OR&vars%5Bpost_type%5D=wp-manga&vars%5Bpost_status%5D=publish&vars%5Bmeta_key%5D=_latest_update&vars%5Border%5D=desc&vars%5Bmanga_archives_item_layout%5D=default"
private val ratingRequest =
"action=madara_load_more&page=1&template=madara-core%2Fcontent%2Fcontent-search&vars%5Bs%5D=&vars%5Borderby%5D%5Bquery_avarage_reviews%5D=DESC&vars%5Borderby%5D%5Bquery_total_reviews%5D=DESC&vars%5Bpaged%5D=1&vars%5Btemplate%5D=search&vars%5Bmeta_query%5D%5B0%5D%5Brelation%5D=AND&vars%5Bmeta_query%5D%5B0%5D%5Bquery_avarage_reviews%5D%5Bkey%5D=_manga_avarage_reviews&vars%5Bmeta_query%5D%5B0%5D%5Bquery_total_reviews%5D%5Bkey%5D=_manga_total_votes&vars%5Bmeta_query%5D%5Brelation%5D=AND&vars%5Bpost_type%5D=wp-manga&vars%5Bpost_status%5D=publish&vars%5Bmanga_archives_item_layout%5D=default"
private val defaultRequest =
"action=madara_load_more&page=1&template=madara-core%2Fcontent%2Fcontent-search&vars%5Bs%5D=&vars%5Borderby%5D=meta_value_num&vars%5Bpaged%5D=1&vars%5Btemplate%5D=search&vars%5Bmeta_query%5D%5B0%5D%5Brelation%5D=AND&vars%5Bmeta_query%5D%5Brelation%5D=OR&vars%5Bpost_type%5D=wp-manga&vars%5Bpost_status%5D=publish&vars%5Bmeta_key%5D=_latest_update&vars%5Border%5D=desc&vars%5Bmanga_archives_item_layout%5D=default"
private companion object {
private fun createRequestTemplate(query : String) =
private fun createRequestTemplate(query: String) =
(query).split(
'&',
).map {

@ -31,7 +31,7 @@ internal class BestManhuaCom(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -47,9 +47,7 @@ internal class BestManhuaCom(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/")
append(pages.toString())
append("?")
@ -67,7 +65,7 @@ internal class BestManhuaCom(context: MangaLoaderContext) :
SortOrder.UPDATED -> append("latest-updated")
SortOrder.NEWEST -> append("release-date")
SortOrder.ALPHABETICAL -> append("name-az")
else -> append("latest")
SortOrder.RATING -> append("rating")
}
}
val doc = webClient.httpGet(url).parseHtml()

@ -28,6 +28,9 @@ internal class Hentai4Free(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -43,9 +46,7 @@ internal class Hentai4Free(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/")
if (pages > 1) {
append("page/")
@ -65,7 +66,7 @@ internal class Hentai4Free(context: MangaLoaderContext) :
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
SortOrder.RATING -> append("rating")
}
}
}

@ -28,6 +28,7 @@ internal class IsekaiScan(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -45,10 +46,7 @@ internal class IsekaiScan(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/mangas/")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("?orderby=2&page=")
append(pages.toString())

@ -20,6 +20,7 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -36,9 +37,7 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/page/")
append(pages.toString())
append("?")
@ -58,7 +57,7 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) :
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
SortOrder.RATING -> append("rating")
}
}
val doc = webClient.httpGet(url).parseHtml()

@ -25,7 +25,7 @@ internal class MangaDass(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -42,9 +42,7 @@ internal class MangaDass(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/")
append(pages.toString())
append("?")
@ -64,7 +62,7 @@ internal class MangaDass(context: MangaLoaderContext) :
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
SortOrder.RATING -> append("rating")
}
}
val doc = webClient.httpGet(url).parseHtml()

@ -25,7 +25,7 @@ internal class MangaDna(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -42,9 +42,7 @@ internal class MangaDna(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/page/")
append(pages.toString())
append("?")
@ -64,7 +62,7 @@ internal class MangaDna(context: MangaLoaderContext) :
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
SortOrder.RATING -> append("rating")
}
}
val doc = webClient.httpGet(url).parseHtml()

@ -21,7 +21,7 @@ internal class Manhwaz(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -38,9 +38,7 @@ internal class Manhwaz(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("?page=")
append(pages.toString())
append("&")
@ -60,7 +58,7 @@ internal class Manhwaz(context: MangaLoaderContext) :
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
SortOrder.RATING -> append("rating")
}
}
val doc = webClient.httpGet(url).parseHtml()

@ -14,9 +14,7 @@ import java.util.*
internal class DragonTranslationParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.DRAGONTRANSLATION, "dragontranslation.net", 30) {
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
)
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val selectPage = "div#chapter_imgs img"
@ -27,6 +25,8 @@ internal class DragonTranslationParser(context: MangaLoaderContext) :
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -42,9 +42,7 @@ internal class DragonTranslationParser(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/mangas?tag=")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("&page=")
append(pages.toString())
}

@ -19,7 +19,7 @@ internal class MonarcaManga(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -36,9 +36,7 @@ internal class MonarcaManga(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/page/")
append(pages.toString())
append("?")
@ -58,7 +56,7 @@ internal class MonarcaManga(context: MangaLoaderContext) :
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
SortOrder.RATING -> append("rating")
}
}
val doc = webClient.httpGet(url).parseHtml()

@ -6,11 +6,11 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("TEMPLESCANESP", "TempleScanEsp", "es" , ContentType.HENTAI)
@MangaSourceParser("TEMPLESCANESP", "TempleScanEsp", "es", ContentType.HENTAI)
internal class TempleScanEsp(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.TEMPLESCANESP, "templescanesp.com") {
override val listUrl = "series/"
override val listUrl = "series/"
override val tagPrefix = "genero/"
override val datePattern = "dd.MM.yyyy"
}

@ -6,6 +6,6 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("TENKAISCAN", "Tenkai Scan", "es" , ContentType.HENTAI)
@MangaSourceParser("TENKAISCAN", "Tenkai Scan", "es", ContentType.HENTAI)
internal class TenkaiScan(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.TENKAISCAN, "tenkaiscan.net")

@ -0,0 +1,16 @@
package org.koitharu.kotatsu.parsers.site.madara.id
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.Locale
@MangaSourceParser("BIRDTOON", "BirdToon", "id", ContentType.HENTAI)
internal class BirdToon(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.BIRDTOON, "birdtoon.net", 10) {
override val sourceLocale: Locale = Locale.ENGLISH
override val tagPrefix = "komik-genre/"
override val listUrl = "komik/"
}

@ -24,7 +24,7 @@ internal class ManhwaPlus(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -41,9 +41,7 @@ internal class ManhwaPlus(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/page/")
append(pages.toString())
append("?")

@ -35,6 +35,7 @@ internal class HachiManga(context: MangaLoaderContext) : MadaraParser(context, M
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -51,9 +52,7 @@ internal class HachiManga(context: MangaLoaderContext) : MadaraParser(context, M
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/")
append(pages.toString())
append("/")

@ -24,8 +24,7 @@ internal class Saytruyenhay(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -42,15 +41,12 @@ internal class Saytruyenhay(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("?page=")
append(pages.toString())
}
else -> {
append("/$listUrl")
append("?page=")
append(pages.toString())
@ -62,7 +58,7 @@ internal class Saytruyenhay(context: MangaLoaderContext) :
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
SortOrder.RATING -> append("rating")
}
}
val doc = webClient.httpGet(url).parseHtml()

@ -3,7 +3,6 @@ package org.koitharu.kotatsu.parsers.site.manga18
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
@ -54,6 +53,7 @@ internal abstract class Manga18Parser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -68,9 +68,7 @@ internal abstract class Manga18Parser(
!tags.isNullOrEmpty() -> {
append("/$tagUrl")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/")
append(page.toString())
append("?")

@ -18,6 +18,7 @@ internal class Hentai3zCc(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -33,9 +34,7 @@ internal class Hentai3zCc(context: MangaLoaderContext) :
!tags.isNullOrEmpty() -> {
append("/$tagUrl")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/")
append(pages.toString())
append("?")

@ -50,6 +50,7 @@ internal abstract class MangaboxParser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -62,9 +63,7 @@ internal abstract class MangaboxParser(
} else if (!tags.isNullOrEmpty()) {
append("/")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
append("/")
append(page.toString())
} else {

@ -45,6 +45,7 @@ internal class Mangairo(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -70,9 +71,7 @@ internal class Mangairo(context: MangaLoaderContext) :
if (!tags.isNullOrEmpty()) {
append("/ctg-")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
} else {
append("/ctg-all")
}

@ -9,5 +9,5 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("BIRDMANGA", "Bird Manga", "en")
internal class BirdManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.BIRDMANGA, "birdmanga.com", pageSize = 20, searchPageSize = 10) {
override val encodedSrc = true
override val encodedSrc = true
}

@ -61,7 +61,7 @@ internal abstract class MmrcmsParser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = if (sortOrder == SortOrder.UPDATED) {
//the Updated page doesn't really exist, we just use the home page to weight the latest chapters, so it doesn't include tag and page management.
buildString {
@ -75,23 +75,19 @@ internal abstract class MmrcmsParser(
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()) {
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
}
append("&sortBy=")

@ -146,12 +146,12 @@ class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context, MangaSo
val url = "/forum/search-plus.php".toAbsoluteUrl(domain)
val docs = webClient.httpGet(url).parseHtml()
return docs.selectFirstOrThrow("ul.ul-search").select("li").mapNotNull { el ->
MangaTag(
title = el.text(),
key = el.selectFirst("input")?.attr("value") ?: return@mapNotNull null,
source = source,
)
}.associateBy { it.title }
MangaTag(
title = el.text(),
key = el.selectFirst("input")?.attr("value") ?: return@mapNotNull null,
source = source,
)
}.associateBy { it.title }
}
private fun getSortCookies(sortOrder: SortOrder): Array<String> {
@ -225,19 +225,19 @@ class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context, MangaSo
val chaptersEl = webClient.httpGet(chaptersAjax).parseHtml()
val chapterDateFormat = SimpleDateFormat("dd/MM/yyyy")
return chaptersEl.select("tbody > tr").mapChapters(reversed = true) { index, element ->
val titleEl = element.selectFirst("td > a") ?: return@mapChapters null
val dateStr = element.selectLast("td")?.text()
MangaChapter(
id = generateUid(titleEl.attrAsRelativeUrl("href")),
name = titleEl.text(),
number = index + 1,
url = titleEl.attrAsRelativeUrl("href"),
scanlator = null,
uploadDate = chapterDateFormat.tryParse(dateStr),
branch = null,
source = source,
)
}
val titleEl = element.selectFirst("td > a") ?: return@mapChapters null
val dateStr = element.selectLast("td")?.text()
MangaChapter(
id = generateUid(titleEl.attrAsRelativeUrl("href")),
name = titleEl.text(),
number = index + 1,
url = titleEl.attrAsRelativeUrl("href"),
scanlator = null,
uploadDate = chapterDateFormat.tryParse(dateStr),
branch = null,
source = source,
)
}
}
private fun Element.infoText(title: String) =

@ -16,7 +16,6 @@ internal abstract class VmpParser(
) : PagedMangaParser(context, source, pageSize) {
override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
protected open val listUrl = "xxx/"
@ -33,20 +32,15 @@ internal abstract class VmpParser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://$domain/")
if(!tags.isNullOrEmpty())
{
append(geneUrl)
for (tag in tags) {
append(tag.key)
}
append("/page/")
append(page.toString())
}else
{
if (!tags.isNullOrEmpty()) {
append(geneUrl)
append(tag?.key.orEmpty())
append("/page/")
append(page.toString())
} else {
append(listUrl)
append("/page/")
append(page.toString())
@ -92,10 +86,10 @@ internal abstract class VmpParser(
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc= webClient.httpGet(fullUrl).parseHtml()
val doc = webClient.httpGet(fullUrl).parseHtml()
manga.copy(
tags = doc.select("div.tax_box div.links ul:not(.post-categories) li a").mapNotNullToSet { a ->
tags = doc.select("div.tax_box div.links ul:not(.post-categories) li a").mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast(geneUrl, ""),
title = a.text().toTitleCase(),

@ -55,6 +55,7 @@ internal abstract class WpComicsParser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -62,9 +63,7 @@ internal abstract class WpComicsParser(
if (!tags.isNullOrEmpty()) {
append("/")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
}
append("?page=")

@ -8,7 +8,7 @@ import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser
import org.koitharu.kotatsu.parsers.util.*
import java.util.EnumSet
@MangaSourceParser("XOXOCOMICS", "Xoxo Comics", "vi", ContentType.COMICS)
@MangaSourceParser("XOXOCOMICS", "Xoxo Comics", "en", ContentType.COMICS)
internal class XoxoComics(context: MangaLoaderContext) :
WpComicsParser(context, MangaSource.XOXOCOMICS, "xoxocomics.net", 50) {
@ -28,6 +28,7 @@ internal class XoxoComics(context: MangaLoaderContext) :
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
@ -41,9 +42,7 @@ internal class XoxoComics(context: MangaLoaderContext) :
append(listUrl)
if (!tags.isNullOrEmpty()) {
append("/")
for (tag in tags) {
append(tag.key)
}
append(tag?.key.orEmpty())
}
append("/")

@ -7,6 +7,6 @@ import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.zmanga.ZMangaParser
@MangaSourceParser("NEU_MANGA", "Neu Manga", "id")
@MangaSourceParser("NEU_MANGA", "Neu Manga Net", "id")
internal class NeuManga(context: MangaLoaderContext) :
ZMangaParser(context, MangaSource.NEU_MANGA, "neumanga.net")

Loading…
Cancel
Save