Merge pull request #202 from davvarrr/master

rework madara theme and fix many parser
pull/203/head
Koitharu 3 years ago committed by GitHub
commit 240562037d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -112,16 +112,21 @@ internal class JapScanParser(context: MangaLoaderContext) : PagedMangaParser(con
val embeddedData = doc.requireElementById("data").attr("data-data")
val script = webClient.httpGet(scriptUrl).parseRaw()
val sample = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toList()
val keyRegex = Regex("""'([\dA-Z]{62})'""", RegexOption.IGNORE_CASE)
val shortkeyRegex = Regex("""'([\dA-Z]{2})'""", RegexOption.IGNORE_CASE)
val longkeyRegex = Regex("""'([\dA-Z]{20})'""", RegexOption.IGNORE_CASE)
val keyTables = keyRegex.findAll(script)
.mapNotNullTo(ArrayList(2)) { match ->
match.groupValues[1].takeIf {
it.toList().sorted() == sample
}
}
check(keyTables.size == 2)
val longTables = longkeyRegex.findAll(script).map {
it.groupValues[1]
}.toList()
val shortTables = shortkeyRegex.findAll(script).map {
it.groupValues[1]
}.toList()
val keyTables = listOf(
ShortTables[1].reversed() + LongTables[5].reversed() + LongTables[2].reversed() + LongTables[0].reversed(),
ShortTables[2].reversed() + LongTables[3].reversed() + LongTables[4].reversed() + LongTables[1].reversed(),
)
var error: Exception? = null
repeat(2) { i ->

@ -1,51 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
@MangaSourceParser("AIYUMANGASCANLATION", "AiyuMangaScanlation", "es")
internal class AiyuMangaScanlation(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.AIYUMANGASCANLATION, "aiyumangascanlation.com") {
override val tagPrefix = "manga-genre/"
override val datePattern = "MM/dd/yyyy"
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".post-content")
val tags = postContent.getElementsContainingOwnText("Genre(s)")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
description = postContent.getElementsContainingOwnText("Summary")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternative")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
override fun String.asMangaState(): MangaState? = when (this) {
"OnGoing",
"Upcoming",
-> MangaState.ONGOING
"Completed",
"Dropped",
-> MangaState.FINISHED
else -> null
}
}

@ -1,59 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.assertNotNull
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
@MangaSourceParser("ASTRALMANGA", "AstralManga", "fr")
internal class AstralManga(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.ASTRALMANGA, "astral-manga.fr", pageSize = 12) {
override val datePattern = "dd/MM/yyyy"
override fun String.asMangaState(): MangaState? = when (this) {
"En cours",
-> MangaState.ONGOING
"Terminé",
"Complété",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".post-content")
val tags = postContent.getElementsContainingOwnText("Genre(s)")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
rating = postContent.selectFirstOrThrow(".post-rating")
.selectFirstOrThrow(".total_votes").text().toFloat() / 5f,
largeCoverUrl = root.selectFirst(".summary_image")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src")
.assertNotNull("largeCoverUrl"),
description = root.selectFirstOrThrow(".manga-excerpt")
.firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Auteur(s)")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternatif")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Statut")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
}

@ -1,57 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.assertNotNull
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
@MangaSourceParser("ATLANTISSCAN", "Atlantisscan", "pt")
internal class Atlantisscan(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.ATLANTISSCAN, "atlantisscan.com") {
override val datePattern = "dd/MM/yyyy"
override fun String.asMangaState(): MangaState? = when (this) {
"OnGoing",
-> MangaState.ONGOING
"finished",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".summary_content")
val tags = postContent.getElementsContainingOwnText("Genre(s) ")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
largeCoverUrl = root.selectFirst(".summary_image")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src")
.assertNotNull("largeCoverUrl"),
description = root.selectFirstOrThrow(".description-summary")
.firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Author(s)")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternative")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
}

@ -1,60 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.assertNotNull
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import java.util.*
@MangaSourceParser("FRSCAN", "FrScan", "fr")
internal class FrScan(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.FRSCAN, "fr-scan.com") {
override val datePattern = "MMMM d, yyyy"
override val sourceLocale: Locale = Locale.FRENCH
override fun String.asMangaState(): MangaState? = when (this) {
"OnGoing",
-> MangaState.ONGOING
"Complété",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".post-content")
val tags = postContent.getElementsContainingOwnText("Genre(s)")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
rating = postContent.selectFirstOrThrow(".post-rating")
.selectFirstOrThrow(".total_votes").text().toFloat() / 5f,
largeCoverUrl = root.selectFirst(".summary_image")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src")
.assertNotNull("largeCoverUrl"),
description = root.selectFirstOrThrow(".description-summary")
.firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Auteur(s)")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternatif")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Statut")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
}

@ -1,69 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
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.MangaTag
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("HENTAI_4FREE", "Hentai4Free", "en")
internal class Hentai4Free(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAI_4FREE, "hentai4free.net", pageSize = 24) {
override val tagPrefix = "hentai-tag/"
override val isNsfwSource = true
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/").parseHtml()
val body = doc.body()
val root1 = body.selectFirst("header")?.selectFirst("ul.second-menu")
val list = root1?.select("li").orEmpty()
val keySet = HashSet<String>(list.size)
return list.mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
val href = a.attr("href").removeSuffix("/")
.substringAfterLast(tagPrefix, "")
if (href.isEmpty() || !keySet.add(href)) {
return@mapNotNullToSet null
}
MangaTag(
key = href,
title = a.ownText().trim().toTitleCase(),
source = source,
)
}
}
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
val slug = manga.url.removeSuffix('/').substringAfterLast('/')
val doc2 = webClient.httpPost(
"https://$domain/hentai/$slug/ajax/chapters/",
mapOf(),
).parseHtml()
val ul = doc2.body().selectFirstOrThrow("ul")
val dateFormat = SimpleDateFormat(datePattern, Locale.US)
return ul.select("li").mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
MangaChapter(
id = generateUid(href),
name = a.ownText(),
number = i + 1,
url = href,
uploadDate = parseChapterDate(
dateFormat,
li.selectFirst("span.chapter-release-date i")?.text(),
),
source = source,
scanlator = null,
branch = null,
)
}
}
}

@ -1,63 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.assertNotNull
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
@MangaSourceParser("HENTAITECA", "Hentaiteca", "pt")
internal class Hentaiteca(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.HENTAITECA, "hentaiteca.net", pageSize = 10) {
override val datePattern = "MM/dd/yyyy"
override val tagPrefix = "genero/"
override val isNsfwSource = true
override fun String.asMangaState(): MangaState? = when (this) {
"Em Lançamento",
-> MangaState.ONGOING
"Completo",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".summary_content")
val tags = postContent.getElementsContainingOwnText("Gênero(s)")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
rating = postContent.selectFirstOrThrow(".post-rating")
.selectFirstOrThrow(".total_votes").text().toFloat() / 5f,
largeCoverUrl = root.selectFirst(".summary_image")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src")
.assertNotNull("largeCoverUrl"),
description = root.selectFirstOrThrow(".description-summary")
.firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Autor(es)")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternatif")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
}

@ -1,93 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
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.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("HENTAIZONE", "Hentaizone", "fr")
internal class Hentaizone(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.HENTAIZONE, "hentaizone.xyz", pageSize = 10) {
override val datePattern = "MMM d, yyyy"
override val sourceLocale: Locale = Locale.FRENCH
override val isNsfwSource = true
override fun String.asMangaState(): MangaState? = when (this) {
"En Cours",
-> MangaState.ONGOING
"Terminé",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".summary_content")
val tags = postContent.getElementsContainingOwnText("Genre(s)")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
rating = postContent.selectFirstOrThrow(".post-rating")
.selectFirstOrThrow(".total_votes").text().toFloat() / 5f,
description = root.selectFirst("div.description-summary")?.selectFirst("div.summary__content")?.select("p")
?.filterNot { it.ownText().startsWith("A brief description") }?.joinToString { it.html() },
author = postContent.getElementsContainingOwnText("Auteur(s)")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternatif")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Statut")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
chapters = chapters,
)
}
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
val root2 = doc.body().selectFirstOrThrow("div.content-area").selectFirstOrThrow("div.c-page")
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return root2.select("li").mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
// correct parse date missing a "."
val date_org = li.selectFirst("span.chapter-release-date i")?.text() ?: "janv 1, 2000"
val date_corect_parse = date_org
.replace("janv", "janv.")
.replace("févr", "févr.")
.replace("avr", "avr.")
.replace("juil", "juil.")
.replace("sept", "sept.")
.replace("nov", "nov.")
.replace("oct", "oct.")
.replace("déc", "déc.")
MangaChapter(
id = generateUid(href),
name = a.ownText(),
number = i + 1,
url = href,
uploadDate = parseChapterDate(
dateFormat,
date_corect_parse,
),
source = source,
scanlator = null,
branch = null,
)
}
}
}

@ -1,66 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.domain
import org.koitharu.kotatsu.parsers.util.insertCookies
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import java.util.*
@MangaSourceParser("HHENTAIFR", "HhentaiFr", "fr")
internal class HhentaiFr(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.HHENTAIFR, "hhentai.fr") {
override val datePattern = "MMMM d, yyyy"
override val sourceLocale: Locale = Locale.FRENCH
override val isNsfwSource = true
init {
context.cookieJar.insertCookies(
domain,
"age_gate=32;",
)
}
override fun String.asMangaState(): MangaState? = when (this) {
"En Cours",
-> MangaState.ONGOING
"Terminé",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".summary_content")
val tags = postContent.getElementsContainingOwnText("Genre(s)")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
rating = postContent.selectFirstOrThrow(".post-rating")
.selectFirstOrThrow(".total_votes").text().toFloat() / 5f,
description = root.selectFirstOrThrow(".description-summary")
.firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Auteur(s)")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternatif")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Statut")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
}

@ -1,54 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import java.util.*
@MangaSourceParser("HIPERCOOL", "Hipercool", "pt")
internal class Hipercool(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.HIPERCOOL, "hipercool.xyz", pageSize = 20) {
override val datePattern = "MMMM d, yyyy"
override val tagPrefix = "manga-tag/"
override val isNsfwSource = true
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".main-col")
val tags = postContent.getElementsByClass("tags-content")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
largeCoverUrl = root.selectFirst("picture")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src"),
description = root.selectFirst("div.description-summary")?.selectFirst("div.summary__content")?.select("p")
?.filterNot { it.ownText().startsWith("A brief description") }?.joinToString { it.html() },
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
override fun String.asMangaState() = when (trim().lowercase(Locale.ROOT)) {
"em lançamento" -> MangaState.ONGOING
else -> null
}
}

@ -1,81 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
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.MangaTag
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("ISEKAISCAN_EU", "IsekaiScan", "en")
internal class IsekaiScanEuParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ISEKAISCAN_EU, "isekaiscan.to") {
override val datePattern = "MM/dd/yyyy"
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
doc.selectFirst("ul.version-chap")?.let {
return parseChapters(it)
}
val mangaId = doc.body().requireElementById("manga-chapters-holder").attr("data-id")
val ul = webClient.httpPost(
"https://${domain}/wp-admin/admin-ajax.php",
mapOf(
"action" to "manga_get_chapters",
"manga" to mangaId,
),
).parseHtml().body().selectFirstOrThrow("ul")
return parseChapters(ul)
}
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/mangax/").parseHtml()
val body = doc.body()
val root1 = body.selectFirst("header")?.selectFirst("ul.second-menu")
val root2 = body.selectFirst("div.genres_wrap")?.selectFirst("ul.list-unstyled")
if (root1 == null && root2 == null) {
doc.parseFailed("Root not found")
}
val list = root1?.select("li").orEmpty() + root2?.select("li").orEmpty()
val keySet = HashSet<String>(list.size)
return list.mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
val href = a.attr("href").removeSuffix("/")
.substringAfterLast(tagPrefix, "")
if (href.isEmpty() || !keySet.add(href)) {
return@mapNotNullToSet null
}
MangaTag(
key = href,
title = a.ownText().toTitleCase(Locale.ENGLISH),
source = source,
)
}
}
private fun parseChapters(ul: Element): List<MangaChapter> {
val dateFormat = SimpleDateFormat(datePattern, Locale.US)
return ul.select("li").mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
MangaChapter(
id = generateUid(href),
name = a.ownText(),
number = i + 1,
url = href,
uploadDate = parseChapterDate(
dateFormat,
li.selectFirst("span.chapter-release-date i")?.text(),
),
source = source,
scanlator = null,
branch = null,
)
}
}
}

@ -1,183 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import androidx.collection.arraySetOf
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
abstract class Madara5Parser @InternalParsersApi constructor(
context: MangaLoaderContext,
source: MangaSource,
domain: String,
) : PagedMangaParser(context, source, pageSize = 22) {
protected open val datePattern = "MMMM dd, HH:mm"
protected open val tagPrefix = "/mangas/"
protected open val nsfwTags = arraySetOf("yaoi", "yuri", "mature")
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain(domain)
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val domain = domain
val url = buildString {
append("https://")
append(domain)
append("/search?s=")
if (!query.isNullOrEmpty()) {
append(query.urlEncoded())
}
append("&post_type=wp-manga")
if (!tags.isNullOrEmpty()) {
for (tag in tags) {
append("&genre%5B%5D=")
append(tag.key)
}
}
append("&op=1&author=&artist=&page=")
append(page)
}
val root = webClient.httpGet(url).parseHtml().body().selectFirstOrThrow(".search-wrap")
return root.select(".c-tabs-item__content").map { div ->
val a = div.selectFirstOrThrow("a")
val img = div.selectLastOrThrow("img")
val href = a.attrAsRelativeUrl("href")
val postContent = root.selectFirstOrThrow(".post-content")
val tagSet = postContent.getElementsContainingOwnText("Genre")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { it.asMangaTag() }.orEmpty()
Manga(
id = generateUid(href),
title = a.attr("title"),
altTitle = postContent.getElementsContainingOwnText("Alternative")
.firstOrNull()?.tableValue()?.text()?.trim(),
url = href,
publicUrl = a.attrAsAbsoluteUrl("href"),
coverUrl = img.src().orEmpty(),
author = postContent.getElementsContainingOwnText("Author")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
isNsfw = isNsfw(tagSet),
rating = div.selectFirstOrThrow(".score").text()
.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
tags = tagSet,
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga {
val root = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml().body()
.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".post-content")
val tags = postContent.getElementsContainingOwnText("Genre")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
val mangaId = root.getElementById("manga-chapters-holder")?.attr("data-id")?.toLongOrNull()
?: root.parseFailed("Cannot find mangaId")
return manga.copy(
description = (root.selectFirst(".detail-content")
?: root.selectFirstOrThrow(".description-summary")).html(),
author = postContent.getElementsContainingOwnText("Author")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = isNsfw(tags),
chapters = loadChapters(mangaId),
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val arrayData = doc.getElementById("arraydata") ?: doc.parseFailed("#arraydata not found")
return arrayData.html().split(',').map { url ->
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("http://${domain}/").parseHtml().body()
return doc.getElementsByAttributeValueContaining("href", tagPrefix)
.mapToSet { it.asMangaTag() }
}
private suspend fun loadChapters(mangaId: Long): List<MangaChapter> {
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val doc = webClient.httpGet("https://${domain}/ajax-list-chapter?mangaID=$mangaId").parseHtml()
return doc.select("li.wp-manga-chapter").mapChapters(reversed = true) { i, li ->
val a = li.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href")
MangaChapter(
id = generateUid(href),
url = href,
name = a.text(),
number = i + 1,
branch = null,
uploadDate = dateFormat.tryParse(
li.selectFirst(".chapter-release-date")?.text()?.trim(),
),
scanlator = null,
source = source,
)
}
}
protected fun isNsfw(tags: Set<MangaTag>): Boolean {
return tags.any { it.key in nsfwTags }
}
private fun Element.src(): String? {
return absUrl("data-src").ifEmpty {
absUrl("src")
}.takeUnless { it.isEmpty() }
}
private fun Element.tableValue(): Element {
for (p in parents()) {
val children = p.children()
if (children.size == 2) {
return children[1]
}
}
parseFailed("Cannot find tableValue for node ${text()}")
}
private fun String.asMangaState() = when (trim().lowercase(sourceLocale)) {
"ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED
else -> null
}
private fun Element.asMangaTag() = MangaTag(
title = ownText(),
key = attr("href").removeSuffix('/').substringAfterLast('/')
.replace('-', '+'),
source = source,
)
@MangaSourceParser("MANGAOWLS", "BeautyManga", "en")
class BeautyManga(context: MangaLoaderContext) : Madara5Parser(context, MangaSource.MANGAOWLS, "beautymanga.com")
}

@ -1,71 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
internal abstract class Madara6Parser(
context: MangaLoaderContext,
source: MangaSource,
domain: String,
pageSize: Int = 12,
) : MadaraParser(context, source, domain, pageSize) {
override val datePattern: String = "dd MMMM yyyy"
override suspend fun getDetails(manga: Manga): Manga {
return coroutineScope {
val chapters = async { loadChapters(manga.url) }
val body = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml().body()
parseDetails(manga, body, chapters.await())
}
}
protected fun Element.tableValue(): Element {
for (p in parents()) {
val children = p.children()
if (children.size == 2) {
return children[1]
}
}
parseFailed("Cannot find tableValue for node ${text()}")
}
protected abstract fun String.asMangaState(): MangaState?
protected fun Element.asMangaTag() = MangaTag(
title = ownText(),
key = attr("href").removeSuffix('/').substringAfterLast('/')
.replace('-', '+'),
source = source,
)
protected open suspend fun loadChapters(mangaUrl: String): List<MangaChapter> {
val url = mangaUrl.toAbsoluteUrl(domain).removeSuffix('/') + "/ajax/chapters/"
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val doc = webClient.httpPost(url, emptyMap()).parseHtml()
return doc.select("li.wp-manga-chapter").mapChapters(reversed = true) { i, li ->
val a = li.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href") + "?style=list"
MangaChapter(
id = generateUid(href),
url = href,
name = a.text(),
number = i + 1,
branch = null,
uploadDate = parseChapterDate(
dateFormat,
li.selectFirst("span.chapter-release-date i")?.text(),
),
scanlator = null,
source = source,
)
}
}
protected abstract fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga
}

@ -5,7 +5,6 @@ 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.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.ParseException
@ -15,6 +14,7 @@ import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
internal abstract class MadaraParser(
context: MangaLoaderContext,
source: MangaSource,
@ -38,6 +38,28 @@ internal abstract class MadaraParser(
searchPaginator.firstPage = 0
}
protected fun Element.tableValue(): Element {
for (p in parents()) {
val children = p.children()
if (children.size == 2) {
return children[1]
}
}
parseFailed("Cannot find tableValue for node ${text()}")
}
protected val ongoing: Array<String> = arrayOf(
"مستمرة", "En curso", "En Curso","Ongoing", "OnGoing","On going",
"Ativo", "En Cours", "En cours", "Đang tiến hành", "Em lançamento", "em lançamento", "Em Lançamento", "Онгоінг", "Publishing",
"Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating",
"Lançando", "In Arrivo", "Emision", "En emision", "مستمر", "Curso", "En marcha", "Publicandose", "连载中",)
protected val finished: Array<String> = arrayOf(
"Completed", "Completo", "Complété", "Fini", "Terminé", "Tamamlandı", "Đã hoàn thành", "مكتملة", "Завершено",
"Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído", "Concluido", "已完结",)
override suspend fun getListPage(
page: Int,
query: String?,
@ -80,9 +102,16 @@ internal abstract class MadaraParser(
}.orEmpty(),
author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()?.trim()
?.lowercase()) {
"ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED
?.lowercase())
{
"مستمرة", "En curso", "En Curso","Ongoing", "OnGoing","On going",
"Ativo", "En Cours", "En cours", "Đang tiến hành", "Em lançamento", "em lançamento", "Em Lançamento", "Онгоінг", "Publishing",
"Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating",
"Lançando", "In Arrivo", "Emision", "En emision", "مستمر", "Curso", "En marcha", "Publicandose", "连载中",
-> MangaState.ONGOING
"Completed", "Completo", "Complété", "Fini", "Terminé", "Tamamlandı", "Đã hoàn thành", "مكتملة", "Завершено",
"Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído", "Concluido", "已完结",
-> MangaState.FINISHED
else -> null
},
source = source,
@ -120,36 +149,68 @@ internal abstract class MadaraParser(
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chaptersDeferred = async { getChapters(manga, doc) }
val root = doc.body().selectFirst("div.profile-manga")?.selectFirst("div.summary_content")
?.selectFirst("div.post-content") ?: throw ParseException("Root not found", fullUrl)
val root2 = doc.body().selectFirst("div.content-area")?.selectFirst("div.c-page")
?: throw ParseException("Root2 not found", fullUrl)
manga.copy(
tags = root.selectFirst("div.genres-content")?.select("a")?.mapNotNullToSet { a ->
val testchekasync = doc.body().select("div.listing-chapters_wrap")
val chaptersDeferred = if(testchekasync.isNullOrEmpty())
{
async { loadChapters(manga.url) }
}else
{
async { getChapters(manga, doc) }
}
val desc = doc.body().selectFirst("div.description-summary div.summary__content") ?:
doc.body().selectFirst("div.summary_content div.post-content_item > h5 + div") ?:
doc.body().selectFirst("div.summary_content div.manga-excerpt")
val stateselect =
doc.body().select("div.post-content_item:contains(Status) > div.summary-content").last() ?: doc.body().select("div.post-content_item:contains(Statut) > div.summary-content").last()
?: doc.body().select("div.post-content_item:contains(حالة العمل) > div.summary-content").last() ?: doc.body().select("div.post-content_item:contains(Estado) > div.summary-content").last()
?: doc.body().select("div.post-content_item:contains(สถานะ) > div.summary-content").last() ?: doc.body().select("div.post-content_item:contains(Stato) > div.summary-content").last()
?: doc.body().select("div.post-content_item:contains(Durum) > div.summary-content").last() ?: doc.body().select("div.post-content_item:contains(Statüsü) > div.summary-content").last()
?: doc.body().select("div.summary-content").last()
val state =
stateselect?.let {
when (it.text()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
else -> null
}
}
manga.copy(
tags = doc.body().select("div.genres-content a").mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
title = a.text().toTitleCase(),
source = source,
)
} ?: manga.tags,
description = root2.selectFirst("div.description-summary")?.selectFirst("div.summary__content")?.select("p")
?.filterNot { it.ownText().startsWith("A brief description") }?.joinToString { it.html() },
},
description = desc?.select("p")?.filterNot { it.ownText().startsWith("A brief description") }?.joinToString { it.text() },
altTitle =
doc.body().select(".post-content_item:contains(Alt) .summary-content").firstOrNull()?.tableValue()?.text()?.trim() ?:
doc.body().select(".post-content_item:contains(Nomes alternativos: ) .summary-content").firstOrNull()?.tableValue()?.text()?.trim(),
state = state,
chapters = chaptersDeferred.await(),
)
}
protected open suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
val root2 = doc.body().selectFirstOrThrow("div.content-area").selectFirstOrThrow("div.c-page")
val root2 = doc.body().selectFirstOrThrow("div.content-area")
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return root2.select("li").mapChapters(reversed = true) { i, li ->
return root2.select("li.wp-manga-chapter").mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
val link = href + "?style=list"
MangaChapter(
id = generateUid(href),
name = a.ownText(),
number = i + 1,
url = href,
url = link,
uploadDate = parseChapterDate(
dateFormat,
li.selectFirst("span.chapter-release-date i")?.text(),
@ -161,6 +222,30 @@ internal abstract class MadaraParser(
}
}
protected open suspend fun loadChapters(mangaUrl: String): List<MangaChapter> {
val url = mangaUrl.toAbsoluteUrl(domain).removeSuffix('/') + "/ajax/chapters/"
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val doc = webClient.httpPost(url, emptyMap()).parseHtml()
return doc.select("li.wp-manga-chapter").mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
val link = href + "?style=list"
MangaChapter(
id = generateUid(href),
url = link,
name = a.text(),
number = i + 1,
branch = null,
uploadDate = parseChapterDate(
dateFormat,
li.selectFirst("span.chapter-release-date i")?.text(),
),
scanlator = null,
source = source,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
@ -289,193 +374,4 @@ internal abstract class MadaraParser(
it.substring(0, pos) to it.substring(pos + 1)
}.toMutableMap()
@MangaSourceParser("MANGAWEEBS", "MangaWeebs", "en")
class MangaWeebs(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANGAWEEBS, "mangaweebs.in",
pageSize = 20,
) {
override val datePattern = "dd MMMM HH:mm"
}
@MangaSourceParser("HACHIMANGA", "HachiManga", "ja")
class HachiManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.HACHIMANGA, "hachiraw.com") {
override val sourceLocale: Locale = Locale.ENGLISH
}
@MangaSourceParser("PIANMANGA", "PianManga", "en")
class PianManga(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.PIANMANGA, "pianmanga.me",
pageSize = 10,
)
@MangaSourceParser("MANGAROSIE", "MangaRosie", "en")
class MangaRosie(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANGAROSIE, "mangarosie.in",
pageSize = 16,
)
@MangaSourceParser("MANGATX", "MangaTx", "en")
class MangaTx(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGATX, "mangatx.com")
@MangaSourceParser("MANGAEFFECT", "MangaEffect", "en")
class MangaEffect(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGAEFFECT, "mangaeffect.com") {
override val datePattern = "dd.MM.yyyy"
}
@MangaSourceParser("AQUAMANGA", "AquaManga", "en")
class AquaManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.AQUAMANGA, "aquamanga.com")
@MangaSourceParser("MANGALEK", "MangaLek", "ar")
class MangaLek(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANGALEK, "mangalek.com",
pageSize = 10,
)
@MangaSourceParser("HARIMANGA", "HariManga", "en")
class HariManga(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.HARIMANGA, "harimanga.com",
pageSize = 10,
) {
override val datePattern = "MM/dd/yyyy"
}
@MangaSourceParser("KISSMANGA", "KissManga", "en")
class KissManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.KISSMANGA, "kissmanga.in")
@MangaSourceParser("MANGAROCK", "MangaRock", "en")
class MangaRock(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGAROCK, "mangarockteam.com")
@MangaSourceParser("FREEMANGA", "FreeManga", "en")
class FreeManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.FREEMANGA, "freemanga.me")
@MangaSourceParser("MANGA_KOMI", "MangaKomi", "en")
class MangaKomi(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANGA_KOMI, "mangakomi.io",
pageSize = 18,
)
@MangaSourceParser("MANHWACLAN", "ManhwaClan", "en")
class ManhwaClan(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANHWACLAN, "manhwaclan.com",
pageSize = 10,
)
@MangaSourceParser("MANGA_3S", "Manga3s", "en")
class Manga3s(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGA_3S, "manga3s.com") {
override val tagPrefix = "manhwa-genre/"
}
@MangaSourceParser("MANHWAKOOL", "Manhwa Kool", "en")
class ManhwaKool(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANHWAKOOL, "manhwakool.com",
pageSize = 10,
) {
override val datePattern: String = "MM/dd"
}
@MangaSourceParser("TOPMANHUA", "Top Manhua", "en")
class TopManhua(context: MangaLoaderContext) : MadaraParser(context, MangaSource.TOPMANHUA, "www.topmanhua.com") {
override val tagPrefix = "manhua-genre/"
override val datePattern = "MM/dd/yyyy"
}
@MangaSourceParser("S2MANGA", "S2Manga", "en")
class S2Manga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.S2MANGA, "s2manga.com")
@MangaSourceParser("SKY_MANGA", "Sky Manga", "en")
class SkyManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.SKY_MANGA, "skymanga.xyz") {
override val isNsfwSource = true
}
@MangaSourceParser("BAKAMAN", "BakaMan", "th")
class BakaMan(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.BAKAMAN, "bakaman.net",
pageSize = 18,
) {
override val isNsfwSource = false
}
@MangaSourceParser("HENTAI20", "Hentai20", "en")
class Hentai20(context: MangaLoaderContext) : MadaraParser(context, MangaSource.HENTAI20, "hentai20.io") {
override val tagPrefix = "manga-genre/"
override val isNsfwSource = true
}
@MangaSourceParser("ALLPORN_COMIC", "All Porn Comic", "en")
class AllPornComic(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ALLPORN_COMIC, "allporncomic.com", pageSize = 24) {
override val tagPrefix = "porncomic-genre/"
override val isNsfwSource = true
}
@MangaSourceParser("CAT_300", "Cat300", "th")
class Cat300(context: MangaLoaderContext) : MadaraParser(context, MangaSource.CAT_300, "cat300.com") {
override val isNsfwSource = true
}
@MangaSourceParser("BIBIMANGA", "BibiManga", "en")
class BibiManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.BIBIMANGA, "bibimanga.com") {
override val isNsfwSource = false
}
@MangaSourceParser("TREE_MANGA", "Tree Manga", "en")
class TreeManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.TREE_MANGA, "treemanga.com") {
override val datePattern = "MM/dd/yyyy"
}
@MangaSourceParser("MANGACV", "Manga Cv", "en")
class MangaCv(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANGACV, "mangacv.com",
pageSize = 10,
)
@MangaSourceParser("TOONILY", "Toonily", "en")
class Toonily(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.TOONILY, "toonily.com",
pageSize = 18,
) {
override val tagPrefix = "webtoon-genre/"
override val isNsfwSource = false
}
@MangaSourceParser("MANGA_MANHUA", "Manga Manhua", "en")
class MangaManhua(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGA_MANHUA, "mangamanhua.online", pageSize = 10)
@MangaSourceParser("MANGA_247", "247MANGA", "en")
class Manga247(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGA_247, "247manga.com") {
override val tagPrefix = "manhwa-genre/"
}
@MangaSourceParser("MANGA_365", "365Manga", "en")
class Manga365(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGA_365, "365manga.com")
@MangaSourceParser("MANGACLASH", "Mangaclash", "en")
class Mangaclash(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANGACLASH, "mangaclash.com",
pageSize = 18,
) {
override val datePattern = "MM/dd/yyyy"
}
@MangaSourceParser("ZINMANGA", "ZINMANGA", "en")
class Zinmanga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.ZINMANGA, "zinmanga.com")
@MangaSourceParser("STKISSMANGA", "Stkissmanga", "en")
class Stkissmanga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.STKISSMANGA, "1stkissmanga.me")
}

@ -1,60 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.assertNotNull
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import java.util.*
@MangaSourceParser("MANGA_SCANTRAD", "Manga Scantrad", "fr")
internal class MangaScantrad(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.MANGA_SCANTRAD, "manga-scantrad.io") {
override val datePattern = "d MMMM yyyy"
override val sourceLocale: Locale = Locale.FRENCH
override fun String.asMangaState(): MangaState? = when (this) {
"OnGoing",
-> MangaState.ONGOING
"Complété",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".summary_content")
val tags = postContent.getElementsContainingOwnText("Genre(s)")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
rating = postContent.selectFirstOrThrow(".post-rating")
.selectFirstOrThrow(".total_votes").text().toFloat() / 5f,
largeCoverUrl = root.selectFirst(".summary_image")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src")
.assertNotNull("largeCoverUrl"),
description = root.selectFirstOrThrow(".description-summary")
.firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Auteur(s)")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternatif")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("État")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
}

@ -1,46 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.util.*
@MangaSourceParser("MANGALINK_AR", "Mangalink", "ar")
internal class MangalinkParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGALINK_AR, "mangalink.online", pageSize = 10) {
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chaptersDeferred = async { getChapters(manga, doc) }
val root = doc.body().selectFirst("div.profile-manga")
?.selectFirst("div.summary_content")
?.selectFirst("div.post-content")
?: throw ParseException("Root not found", fullUrl)
val root2 = doc.body().selectFirst("div.content-area")
?.selectFirst("div.c-page")
?: throw ParseException("Root2 not found", fullUrl)
manga.copy(
tags = root.selectFirst("div.genres-content")?.select("a")
?.mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
title = a.text().toTitleCase(),
source = source,
)
} ?: manga.tags,
description = root2.selectFirst("div.description-summary")
?.selectFirst("div.summary__content")
?.select("p")
?.filterNot { it.ownText().startsWith("A brief description") }
?.joinToString { it.html() },
chapters = chaptersDeferred.await(),
)
}
}

@ -1,98 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("NEATMANGA", "NeatManga", "en")
internal class NeatManga(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.NEATMANGA, "neatmangas.com",
pageSize = 20,
) {
override val datePattern = "dd MMMM yyyy"
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val chaptersDeferred = async { getChapters(manga) }
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val root = doc.body().selectFirst("div.profile-manga")
?.selectFirst("div.summary_content")
?.selectFirst("div.post-content")
?: throw ParseException("Root not found", fullUrl)
val root2 = doc.body().selectFirst("div.content-area")
?.selectFirst("div.c-page")
?: throw ParseException("Root2 not found", fullUrl)
manga.copy(
tags = root.selectFirst("div.genres-content")?.select("a")
?.mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
title = a.text().toTitleCase(),
source = source,
)
} ?: manga.tags,
description = root2.getElementsMatchingOwnText("Summary")
.firstOrNull()
?.nextElementSibling()
?.select("p")
?.filterNot { it.ownText().startsWith("A brief description") }
?.joinToString { it.html() },
chapters = chaptersDeferred.await(),
)
}
private suspend fun getChapters(manga: Manga): List<MangaChapter> {
val slug = manga.url.removeSuffix('/').substringAfterLast('/')
val doc2 = webClient.httpPost(
"https://$domain/manga/$slug/ajax/chapters/",
mapOf(),
).parseHtml()
val ul = doc2.body().selectFirstOrThrow("ul")
val dateFormat = SimpleDateFormat(datePattern, Locale.US)
return ul.select("li").mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
MangaChapter(
id = generateUid(href),
name = a.ownText(),
number = i + 1,
url = href,
uploadDate = parseChapterDate(
dateFormat,
li.selectFirst("span.chapter-release-date i")?.text(),
),
source = source,
scanlator = null,
branch = null,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val root = doc.body().selectFirst("div.main-col-inner")
?.selectFirst("div.reading-content")
?: throw ParseException("Root not found", fullUrl)
return root.select("div.page-break").mapNotNull { div ->
val img = div.selectFirst("img")
if (img == null || img.attr("id").isNullOrEmpty()) {
return@mapNotNull null
}
val url = img.src()?.toRelativeUrl(domain) ?: div.parseFailed("Image src not found")
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
}

@ -1,53 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
@MangaSourceParser("PRISMA_SCANS", "Prisma Scans", "pt")
internal class PrismaScansParser(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.PRISMA_SCANS, "prismascans.net", 10) {
override val tagPrefix = "manga-genre/"
override val datePattern = "MMM dd, yyyy"
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".post-content")
val tags = postContent.getElementsContainingOwnText("Gênero")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
largeCoverUrl = root.selectFirst("picture")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src"),
description = root.selectFirstOrThrow(".manga-excerpt").firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Artista")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Título Alternativo")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
override fun String.asMangaState() = when (trim().lowercase(sourceLocale)) {
"em lançamento" -> MangaState.ONGOING
"completo",
"cancelado",
-> MangaState.FINISHED
else -> null
}
}

@ -1,37 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
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.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.util.*
@MangaSourceParser("REAPERSCANS_FR", "ReaperScansFr", "fr")
internal class ReaperScansFr(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.REAPERSCANS_FR, "reaperscans.fr") {
override val datePattern = "MM/dd/yyyy"
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chaptersDeferred = async { getChapters(manga, doc) }
val root = doc.body().selectFirstOrThrow(".site-content")
manga.copy(
tags = root.selectFirst("div.genres-content")?.select("a")?.mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
title = a.text().toTitleCase(),
source = source,
)
} ?: manga.tags,
description = root.requireElementById("nav-profile")
.selectFirstOrThrow(".description-summary")
.firstElementChild()?.html(),
chapters = chaptersDeferred.await(),
)
}
}

@ -1,86 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@MangaSourceParser("REAPER_SCANS_ID", "ReaperScansID", "id")
internal class ReaperScansParser(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.REAPER_SCANS_ID, "reaperscans.id") {
override val datePattern = "MMMM dd, yyyy"
override val tagPrefix = "genre/"
override val sourceLocale: Locale = Locale.ENGLISH
override fun String.asMangaState(): MangaState? = when (this) {
"OnGoing",
"Upcoming",
-> MangaState.ONGOING
"Completed",
"Dropped",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.requireElementById("nav-info")
val tags = postContent.getElementsContainingOwnText("Gênero")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
rating = postContent.selectFirstOrThrow(".post-rating")
.selectFirstOrThrow(".total_votes").text().toFloat() / 5f,
largeCoverUrl = root.selectFirst(".summary_image")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src")
.assertNotNull("largeCoverUrl"),
description = root.requireElementById("nav-profile")
.selectFirstOrThrow(".description-summary")
.firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Author(s)")
.firstOrNull()?.tableValue()?.text()?.trim(),
altTitle = postContent.getElementsContainingOwnText("Alternative")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://${domain}/semua-komik/").parseHtml()
val body = doc.body()
val root1 = body.selectFirst("header")?.selectFirst("ul.second-menu")
val root2 = body.selectFirst("div.genres_wrap")?.selectFirst("ul.list-unstyled")
if (root1 == null && root2 == null) {
doc.parseFailed("Root not found")
}
val list = root1?.select("li").orEmpty() + root2?.select("li").orEmpty()
val keySet = HashSet<String>(list.size)
return list.mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
val href = a.attr("href").removeSuffix("/")
.substringAfterLast(tagPrefix, "")
if (href.isEmpty() || !keySet.add(href)) {
return@mapNotNullToSet null
}
MangaTag(
key = href,
title = a.ownText().trim().ifEmpty {
a.selectFirst(".menu-image-title")?.text()?.trim() ?: return@mapNotNullToSet null
}.toTitleCase(),
source = source,
)
}
}
}

@ -1,76 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
@MangaSourceParser("SCANTRADVF", "ScantradVf", "fr")
internal class ScantradVf(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.SCANTRADVF, "scantrad-vf.co") {
override val datePattern = "d MMMM yyyy"
override val tagPrefix = "genre/"
override fun String.asMangaState(): MangaState? = when (this) {
"En cours",
-> MangaState.ONGOING
"Complété",
"Terminé",
-> MangaState.FINISHED
else -> null
}
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".summary_content")
val tags = postContent.getElementsContainingOwnText("Genre(s)")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
rating = postContent.selectFirstOrThrow(".post-rating")
.selectFirstOrThrow(".total_votes").text().toFloat() / 5f,
description = root.selectFirstOrThrow(".description-summary")
.firstElementChild()?.html(),
author = postContent.getElementsContainingOwnText("Auteur(s)")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://${domain}/genre/action/").parseHtml()
val body = doc.body()
val root1 = body.selectFirst("header")?.selectFirst("ul.second-menu")
val root2 = body.selectFirst("div.genres_wrap")?.selectFirst("ul.list-unstyled")
if (root1 == null && root2 == null) {
doc.parseFailed("Root not found")
}
val list = root2?.select("li").orEmpty()
val keySet = HashSet<String>(list.size)
return list.mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null
val href = a.attr("href").removeSuffix("/")
.substringAfterLast(tagPrefix, "")
if (href.isEmpty() || !keySet.add(href)) {
return@mapNotNullToSet null
}
MangaTag(
key = href,
title = a.ownText().trim().ifEmpty {
return@mapNotNullToSet null
}.toTitleCase(),
source = source,
)
}
}
}

@ -1,50 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara
import org.jsoup.nodes.Element
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.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import java.util.*
@MangaSourceParser("TATAKAE_SCANS", "Tatakae Scans", "pt")
internal class TatakaeScansParser(context: MangaLoaderContext) :
Madara6Parser(context, MangaSource.TATAKAE_SCANS, "tatakaescan.com", pageSize = 10) {
override val datePattern: String = "dd 'de' MMMMM 'de' yyyy"
override fun parseDetails(manga: Manga, body: Element, chapters: List<MangaChapter>): Manga {
val root = body.selectFirstOrThrow(".site-content")
val postContent = root.selectFirstOrThrow(".post-content")
val tags = postContent.getElementsContainingOwnText("Gênero")
.firstOrNull()?.tableValue()
?.getElementsByAttributeValueContaining("href", tagPrefix)
?.mapToSet { a -> a.asMangaTag() } ?: manga.tags
return manga.copy(
largeCoverUrl = root.selectFirst("picture")
?.selectFirst("img[data-src]")
?.attrAsAbsoluteUrlOrNull("data-src"),
description = (root.selectFirst(".detail-content")
?: root.selectFirstOrThrow(".manga-excerpt")).html(),
author = postContent.getElementsContainingOwnText("Autor")
.firstOrNull()?.tableValue()?.text()?.trim(),
state = postContent.getElementsContainingOwnText("Status")
.firstOrNull()?.tableValue()?.text()?.asMangaState(),
tags = tags,
isNsfw = body.hasClass("adult-content"),
chapters = chapters,
)
}
override fun String.asMangaState() = when (trim().lowercase(Locale.ROOT)) {
"em lançamento" -> MangaState.ONGOING
else -> null
}
}

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGALEK", "MangaLek", "ar")
internal class MangaLek(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANGALEK, "mangalek.com",
pageSize = 10,
)

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGALINK_AR", "Mangalink", "ar")
internal class MangalinkParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGALINK_AR, "mangalink.online", pageSize = 10)

@ -0,0 +1,17 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("ALLPORN_COMIC", "All Porn Comic", "en")
internal class AllPornComic(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ALLPORN_COMIC, "allporncomic.com", pageSize = 24) {
override val tagPrefix = "porncomic-genre/"
override val isNsfwSource = true
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("AQUAMANGA", "AquaManga", "en")
internal class AquaManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.AQUAMANGA, "aquamanga.com")

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("BIBIMANGA", "BibiManga", "en")
internal class BibiManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.BIBIMANGA, "bibimanga.com") {
override val isNsfwSource = false
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("FREEMANGA", "FreeManga", "en")
internal class FreeManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.FREEMANGA, "freemanga.me")

@ -0,0 +1,14 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HARIMANGA", "HariManga", "en")
internal class HariManga(context: MangaLoaderContext) :
MadaraParser( context, MangaSource.HARIMANGA, "harimanga.com", pageSize = 10,) {
override val datePattern = "MMMM d, yyyy"
}

@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HENTAI20", "Hentai20", "en")
internal class Hentai20(context: MangaLoaderContext) : MadaraParser(context, MangaSource.HENTAI20, "hentai20.io") {
override val tagPrefix = "manga-genre/"
override val isNsfwSource = true
}

@ -0,0 +1,17 @@
package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HENTAI_4FREE", "Hentai4Free", "en")
internal class Hentai4Free(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAI_4FREE, "hentai4free.net", pageSize = 24) {
override val tagPrefix = "hentai-tag/"
override val isNsfwSource = true
}

@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("ISEKAISCAN_EU", "IsekaiScan", "en")
internal class IsekaiScanEuParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ISEKAISCAN_EU, "isekaiscan.to") {
override val datePattern = "MM/dd/yyyy"
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("KISSMANGA", "KissManga", "en")
internal class KissManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.KISSMANGA, "kissmanga.in")

@ -0,0 +1,12 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGA_247", "247MANGA", "en")
internal class Manga247(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGA_247, "247manga.com") {
override val tagPrefix = "manhwa-genre/"
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGA_365", "365Manga", "en")
internal class Manga365(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGA_365, "365manga.com")

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGA_3S", "Manga3s", "en")
internal class Manga3s(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGA_3S, "manga3s.com") {
override val tagPrefix = "manhwa-genre/"
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGACV", "Manga Cv", "en")
internal class MangaCv(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGACV, "mangacv.com", pageSize = 10,)

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site.madara
package org.koitharu.kotatsu.parsers.site.madara.en
import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext
@ -6,6 +6,7 @@ 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.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*

@ -0,0 +1,12 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAEFFECT", "MangaEffect", "en")
internal class MangaEffect(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGAEFFECT, "mangaeffect.com") {
override val datePattern = "dd.MM.yyyy"
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGA_KOMI", "MangaKomi", "en")
internal class MangaKomi(context: MangaLoaderContext) : MadaraParser( context, MangaSource.MANGA_KOMI, "mangakomi.io", pageSize = 18,)

@ -0,0 +1,14 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGA_MANHUA", "Manga Manhua", "en")
internal class MangaManhua(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGA_MANHUA, "mangamanhua.online", pageSize = 10)
{
override val datePattern = "d MMMM، yyyy"
}

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site.madara
package org.koitharu.kotatsu.parsers.site.madara.en
import androidx.collection.arraySetOf
import org.jsoup.nodes.Element
@ -6,6 +6,7 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@ -97,15 +98,6 @@ internal class MangaRead(context: MangaLoaderContext) :
}
}
private fun Element.tableValue(): Element {
for (p in parents()) {
val children = p.children()
if (children.size == 2) {
return children[1]
}
}
parseFailed("Cannot find tableValue for node ${text()}")
}
private fun isNsfw(tags: Set<MangaTag>): Boolean {
return tags.any { it.key in nsfwTags }

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAROCK", "MangaRock", "en")
internal class MangaRock(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGAROCK, "mangarockteam.com")

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAROSIE", "MangaRosie", "en")
internal class MangaRosie(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.MANGAROSIE, "mangarosie.in",
pageSize = 16,
)

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGATX", "MangaTx", "en")
internal class MangaTx(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGATX, "mangatx.com")

@ -0,0 +1,14 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAWEEBS", "MangaWeebs", "en")
internal class MangaWeebs(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAWEEBS, "mangaweebs.in", pageSize = 20,) {
override val datePattern = "dd MMMM HH:mm"
}

@ -0,0 +1,12 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGACLASH", "Mangaclash", "en")
internal class Mangaclash(context: MangaLoaderContext) : MadaraParser(context, MangaSource.MANGACLASH, "mangaclash.com", pageSize = 18,) {
override val datePattern = "MM/dd/yyyy"
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHWACLAN", "ManhwaClan", "en")
internal class ManhwaClan(context: MangaLoaderContext) : MadaraParser( context, MangaSource.MANHWACLAN, "manhwaclan.com", pageSize = 10,)

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHWAKOOL", "Manhwa Kool", "en")
internal class ManhwaKool(context: MangaLoaderContext) : MadaraParser( context, MangaSource.MANHWAKOOL, "manhwakool.com", pageSize = 10,) {
override val datePattern: String = "MMMM d, yyyy"
}

@ -0,0 +1,17 @@
package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("NEATMANGA", "NeatManga", "en")
internal class NeatManga(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.NEATMANGA, "neatmangas.com",
pageSize = 20,
) {
override val datePattern = "dd MMMM yyyy"
}

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("PIANMANGA", "PianManga", "en")
internal class PianManga(context: MangaLoaderContext) : MadaraParser(
context, MangaSource.PIANMANGA, "pianmanga.me",
pageSize = 10,
)

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("S2MANGA", "S2Manga", "en")
internal class S2Manga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.S2MANGA, "s2manga.com")

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("STKISSMANGA", "Stkissmanga", "en")
internal class Stkissmanga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.STKISSMANGA, "1stkissmanga.me")

@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("TOONILY", "Toonily", "en")
internal class Toonily(context: MangaLoaderContext) : MadaraParser(context, MangaSource.TOONILY, "toonily.com", pageSize = 18,) {
override val tagPrefix = "webtoon-genre/"
override val isNsfwSource = false
}

@ -0,0 +1,14 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("TOPMANHUA", "Top Manhua", "en")
internal class TopManhua(context: MangaLoaderContext) : MadaraParser(context, MangaSource.TOPMANHUA, "www.topmanhua.com") {
override val tagPrefix = "manhua-genre/"
override val datePattern = "MM/dd/yyyy"
}

@ -0,0 +1,14 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("TREE_MANGA", "Tree Manga", "en")
internal class TreeManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.TREE_MANGA, "treemanga.com") {
override val datePattern = "MM/dd/yyyy"
}

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("ZINMANGA", "ZINMANGA", "en")
internal class Zinmanga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.ZINMANGA, "zinmanga.com")
{
override val datePattern = "MM/dd/yyyy"
}

@ -0,0 +1,14 @@
package org.koitharu.kotatsu.parsers.site.madara.es
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("AIYUMANGASCANLATION", "AiyuMangaScanlation", "es")
internal class AiyuMangaScanlation(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.AIYUMANGASCANLATION, "aiyumangascanlation.com") {
override val tagPrefix = "manga-genre/"
override val datePattern = "MM/dd/yyyy"
}

@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.site.madara.fr
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("ASTRALMANGA", "AstralManga", "fr")
internal class AstralManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ASTRALMANGA, "astral-manga.fr", pageSize = 12) {
override val datePattern = "dd/MM/yyyy"
}

@ -0,0 +1,16 @@
package org.koitharu.kotatsu.parsers.site.madara.fr
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.Locale
@MangaSourceParser("FRSCAN", "FrScan", "fr")
internal class FrScan(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.FRSCAN, "fr-scan.com") {
override val datePattern = "MMMM d, yyyy"
override val sourceLocale: Locale = Locale.FRENCH
}

@ -0,0 +1,59 @@
package org.koitharu.kotatsu.parsers.site.madara.fr
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("HENTAIZONE", "Hentaizone", "fr")
internal class Hentaizone(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAIZONE, "hentaizone.xyz", pageSize = 10) {
override val datePattern = "MMM d, yyyy"
override val sourceLocale: Locale = Locale.FRENCH
override val isNsfwSource = true
override suspend fun loadChapters(mangaUrl: String): List<MangaChapter> {
val url = mangaUrl.toAbsoluteUrl(domain).removeSuffix('/') + "/ajax/chapters/"
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val doc = webClient.httpPost(url, emptyMap()).parseHtml()
return doc.select("li.wp-manga-chapter").mapChapters(reversed = true) { i, li ->
val a = li.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href") + "?style=list"
// correct parse date missing a "."
val date_org = li.selectFirst("span.chapter-release-date i")?.text() ?: "janv 1, 2000"
val date_corect_parse = date_org
.replace("janv", "janv.")
.replace("févr", "févr.")
.replace("avr", "avr.")
.replace("juil", "juil.")
.replace("sept", "sept.")
.replace("nov", "nov.")
.replace("oct", "oct.")
.replace("déc", "déc.")
MangaChapter(
id = generateUid(href),
url = href,
name = a.text(),
number = i + 1,
branch = null,
uploadDate = parseChapterDate(
dateFormat,
date_corect_parse,
),
scanlator = null,
source = source,
)
}
}
}

@ -0,0 +1,27 @@
package org.koitharu.kotatsu.parsers.site.madara.fr
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.insertCookies
import java.util.Locale
@MangaSourceParser("HHENTAIFR", "HhentaiFr", "fr")
internal class HhentaiFr(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HHENTAIFR, "hhentai.fr") {
override val datePattern = "MMMM d, yyyy"
override val sourceLocale: Locale = Locale.FRENCH
override val isNsfwSource = true
init {
context.cookieJar.insertCookies(
domain,
"age_gate=32;",
)
}
}

@ -0,0 +1,16 @@
package org.koitharu.kotatsu.parsers.site.madara.fr
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.Locale
@MangaSourceParser("MANGA_SCANTRAD", "Manga Scantrad", "fr")
internal class MangaScantrad(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGA_SCANTRAD, "manga-scantrad.io") {
override val datePattern = "d MMMM yyyy"
override val sourceLocale: Locale = Locale.FRENCH
}

@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.site.madara.fr
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("REAPERSCANS_FR", "ReaperScansFr", "fr")
internal class ReaperScansFr(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.REAPERSCANS_FR, "reaperscans.fr") {
override val datePattern = "MM/dd/yyyy"
}

@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.site.madara.fr
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("SCANTRADVF", "ScantradVf", "fr")
internal class ScantradVf(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.SCANTRADVF, "scantrad-vf.co") {
override val datePattern = "d MMMM yyyy"
override val tagPrefix = "genre/"
}

@ -0,0 +1,17 @@
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.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.Locale
@MangaSourceParser("REAPER_SCANS_ID", "ReaperScansID", "id")
internal class ReaperScansParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.REAPER_SCANS_ID, "reaperscans.id") {
override val datePattern = "MMMM dd, yyyy"
override val tagPrefix = "genre/"
override val sourceLocale: Locale = Locale.ENGLISH
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HACHIMANGA", "HachiManga", "ja")
internal class HachiManga(context: MangaLoaderContext) : MadaraParser(context, MangaSource.HACHIMANGA, "hachiraw.com")

@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("ATLANTISSCAN", "Atlantisscan", "pt")
internal class Atlantisscan(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ATLANTISSCAN, "atlantisscan.com") {
override val datePattern = "dd/MM/yyyy"
}

@ -0,0 +1,17 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HENTAITECA", "Hentaiteca", "pt")
internal class Hentaiteca(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAITECA, "hentaiteca.net", pageSize = 10) {
override val datePattern = "MM/dd/yyyy"
override val tagPrefix = "genero/"
override val isNsfwSource = true
}

@ -0,0 +1,19 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HIPERCOOL", "Hipercool", "pt")
internal class Hipercool(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HIPERCOOL, "hipercool.xyz", pageSize = 20) {
override val datePattern = "MMMM d, yyyy"
override val tagPrefix = "manga-tag/"
override val isNsfwSource = true
}

@ -0,0 +1,15 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("PRISMA_SCANS", "Prisma Scans", "pt")
internal class PrismaScansParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.PRISMA_SCANS, "prismascans.net", 10) {
override val tagPrefix = "manga-genre/"
override val datePattern = "MMM dd, yyyy"
}

@ -0,0 +1,16 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("TATAKAE_SCANS", "Tatakae Scans", "pt")
internal class TatakaeScansParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.TATAKAE_SCANS, "tatakaescan.com", pageSize = 10) {
override val datePattern: String = "dd 'de' MMMMM 'de' yyyy"
}

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("BAKAMAN", "BakaMan", "th")
internal class BakaMan(context: MangaLoaderContext) : MadaraParser( context, MangaSource.BAKAMAN, "bakaman.net", pageSize = 18,) {
override val isNsfwSource = false
}

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("CAT_300", "Cat300", "th")
internal class Cat300(context: MangaLoaderContext) : MadaraParser(context, MangaSource.CAT_300, "cat300.com") {
override val isNsfwSource = true
}

@ -14,6 +14,7 @@ import java.text.SimpleDateFormat
import java.util.*
internal abstract class MangaReaderParser(
context: MangaLoaderContext,
source: MangaSource,
@ -24,13 +25,9 @@ internal abstract class MangaReaderParser(
override val sortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.NEWEST)
protected val idLocale
get() = Locale("in", "ID")
abstract val listUrl: String
abstract val tableMode: Boolean
protected open val listUrl = "/manga"
protected open val isNsfwSource = false
open val chapterDateFormat = SimpleDateFormat("MMM d, yyyy", idLocale)
open val chapterDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex()
@ -51,128 +48,87 @@ internal abstract class MangaReaderParser(
source = source,
)
}
return if (tableMode) parseInfoTable(docs, manga, chapters) else parseInfoList(docs, manga, chapters)
return parseInfo(docs, manga, chapters)
}
open suspend fun parseInfoTable(docs: Document, manga: Manga, chapters: List<MangaChapter>): Manga {
val mangaInfo =
open suspend fun parseInfo(docs: Document, manga: Manga, chapters: List<MangaChapter>): Manga {
/// set if is table
val tablemode =
docs.selectFirst("div.seriestucontent > div.seriestucontentr") ?: docs.selectFirst("div.seriestucontentr")
?: docs.selectFirst("div.seriestucon")
val state_select =
docs.selectFirst(".tsinfo div:contains(Status)") ?: docs.selectFirst(".tsinfo div:contains(Statut)")
?: docs.selectFirst(".tsinfo div:contains(حالة العمل)") ?: docs.selectFirst(".tsinfo div:contains(Estado)")
?: docs.selectFirst(".tsinfo div:contains(สถานะ)") ?: docs.selectFirst(".tsinfo div:contains(Stato )")
?: docs.selectFirst(".tsinfo div:contains(Durum)")
val mangaState = state_select?.lastElementChild()?.let {
when (it.text()) {
"مستمرةا",
"En curso",
"Ongoing",
"On going",
"Ativo",
"En Cours",
"OnGoing",
"Đang tiến hành",
"em lançamento",
"Онгоінг",
"Publishing",
"Devam Ediyor",
"Em Andamento",
"In Corso",
-> MangaState.ONGOING
"Completed",
"Completo",
"Complété",
"Fini",
"Terminé",
"Tamamlandı",
"Đã hoàn thành",
"مكتملة",
"Завершено",
"Finished",
"Finalizado",
"Completata",
-> MangaState.FINISHED
val tagMap = getOrCreateTagMap()
else -> null
}
val selecttag = if(tablemode != null)
{
tablemode.select(".seriestugenre > a")
}else
{
docs.select(".wd-full .mgen > a")
}
val tagMap = getOrCreateTagMap()
val tags = mangaInfo?.select(".seriestugenre > a")?.mapNotNullToSet { tagMap[it.text()] }
return manga.copy(
description = mangaInfo?.selectFirst("div.entry-content")?.html(),
state = mangaState,
author = mangaInfo?.selectFirst(".infotable td:contains(Author)")?.lastElementSibling()?.text(),
isNsfw = manga.isNsfw || docs.selectFirst(".restrictcontainer") != null,
tags = tags.orEmpty(),
chapters = chapters,
)
}
val tags = selecttag.mapNotNullToSet { tagMap[it.text()] }
open suspend fun parseInfoList(docs: Document, manga: Manga, chapters: List<MangaChapter>): Manga {
val stateselect = if(tablemode != null)
{
tablemode.selectFirst(".infotable td:contains(Status)") ?: tablemode.selectFirst(".infotable td:contains(Statut)")
?: tablemode.selectFirst(".infotable td:contains(حالة العمل)") ?: tablemode.selectFirst(".infotable td:contains(Estado)")
?: docs.selectFirst(".infotable td:contains(สถานะ)") ?: tablemode.selectFirst(".infotable td:contains(Stato )")
?: tablemode.selectFirst(".infotable td:contains(Durum)") ?: tablemode.selectFirst(".infotable td:contains(Statüsü)")
val state_select =
}else
{
docs.selectFirst(".tsinfo div:contains(Status)") ?: docs.selectFirst(".tsinfo div:contains(Statut)")
?: docs.selectFirst(".tsinfo div:contains(حالة العمل)") ?: docs.selectFirst(".tsinfo div:contains(Estado)")
?: docs.selectFirst(".tsinfo div:contains(สถานะ)") ?: docs.selectFirst(".tsinfo div:contains(Stato )")
?: docs.selectFirst(".tsinfo div:contains(Durum)")
?: docs.selectFirst(".tsinfo div:contains(Durum)") ?: docs.selectFirst(".tsinfo div:contains(Statüsü)")
}
val state = if(tablemode != null)
{
stateselect?.lastElementSibling()
val mangaState = state_select?.lastElementChild()?.let {
}else
{
stateselect?.lastElementChild()
}
val mangaState = state?.let {
when (it.text()) {
"مستمرةا",
"En curso",
"Ongoing",
"On going",
"Ativo",
"En Cours",
"OnGoing",
"Đang tiến hành",
"em lançamento",
"Онгоінг",
"Publishing",
"Devam Ediyor",
"Em Andamento",
"In Corso",
"مستمرة", "En curso", "Ongoing", "On going",
"Ativo", "En Cours", "OnGoing", "Đang tiến hành", "em lançamento", "Онгоінг", "Publishing",
"Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating",
"Lançando", "In Arrivo", "Emision", "En emision", "مستمر", "Curso", "En marcha", "Publicandose", "连载中",
-> MangaState.ONGOING
"Completed",
"Completo",
"Complété",
"Fini",
"Terminé",
"Tamamlandı",
"Đã hoàn thành",
"مكتملة",
"Завершено",
"Finished",
"Finalizado",
"Completata",
"Completed", "Completo", "Complété", "Fini", "Terminé", "Tamamlandı", "Đã hoàn thành", "مكتملة", "Завершено",
"Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído", "Concluido", "已完结",
-> MangaState.FINISHED
else -> null
}
}
val tags = docs.select(".wd-full .mgen > a").mapNotNullToSet { getOrCreateTagMap()[it.text()] }
return manga.copy(
description =
docs.selectFirst("div.entry-content")?.html(),
state = mangaState,
author =
docs.selectFirst(".tsinfo div:contains(Author)")?.lastElementChild()?.text()
?: docs.selectFirst(".tsinfo div:contains(Auteur)")?.lastElementChild()?.text()
?: docs.selectFirst(".tsinfo div:contains(Artist)")?.lastElementChild()?.text()
?: docs.selectFirst(".tsinfo div:contains(Durum)")?.lastElementChild()?.text(),
val author = tablemode?.selectFirst(".infotable td:contains(Author)")?.lastElementSibling()?.text()?:
docs.selectFirst(".tsinfo div:contains(Author)")?.lastElementChild()?.text() ?:
docs.selectFirst(".tsinfo div:contains(Auteur)")?.lastElementChild()?.text() ?:
docs.selectFirst(".tsinfo div:contains(Artist)")?.lastElementChild()?.text() ?:
docs.selectFirst(".tsinfo div:contains(Durum)")?.lastElementChild()?.text()
isNsfw = manga.isNsfw
val nsfw = docs.selectFirst(".restrictcontainer") != null
|| docs.selectFirst(".info-right .alr") != null
|| docs.selectFirst(".postbody .alr") != null,
|| docs.selectFirst(".postbody .alr") != null
return manga.copy(
description = tablemode?.selectFirst("div.entry-content")?.html() ?:
docs.selectFirst("div.entry-content")?.html(),
state = mangaState,
author = author,
isNsfw = manga.isNsfw || nsfw,
tags = tags,
chapters = chapters,
)
@ -257,25 +213,45 @@ internal abstract class MangaReaderParser(
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val chapterUrl = chapter.url.toAbsoluteUrl(domain)
val docs = webClient.httpGet(chapterUrl).parseHtml()
val script = docs.selectFirstOrThrow("script:containsData(ts_reader)")
val images = JSONObject(script.data().substringAfter('(').substringBeforeLast(')'))
.getJSONArray("sources")
.getJSONObject(0)
.getJSONArray("images")
val pages = ArrayList<MangaPage>(images.length())
for (i in 0 until images.length()) {
pages.add(
val test = docs.select("script:containsData(ts_reader)")
if(test.isNullOrEmpty())
{
return docs.select("div#readerarea img").map { img ->
val url = img.imageUrl()
MangaPage(
id = generateUid(images.getString(i)),
url = images.getString(i),
id = generateUid(url),
url = url,
preview = null,
source = source,
),
)
)
}
}else
{
val script = docs.selectFirstOrThrow("script:containsData(ts_reader)")
val images = JSONObject(script.data().substringAfter('(').substringBeforeLast(')'))
.getJSONArray("sources")
.getJSONObject(0)
.getJSONArray("images")
val pages = ArrayList<MangaPage>(images.length())
for (i in 0 until images.length()) {
pages.add(
MangaPage(
id = generateUid(images.getString(i)),
url = images.getString(i),
preview = null,
source = source,
),
)
}
return pages
}
return pages
}
override suspend fun getTags(): Set<MangaTag> {

@ -14,8 +14,5 @@ internal class Ozulscans(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("ozulscans.com")
override val listUrl: String get() = "/manga"
override val tableMode: Boolean get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("yyyy,d MMM", Locale("ar", "AR"))
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("ANIGLISCANS", "Anigli Scans", "en")
internal class AnigliScans(context: MangaLoaderContext) :
@ -16,8 +14,5 @@ internal class AnigliScans(context: MangaLoaderContext) :
override val listUrl: String
get() = "/series"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("ARENASCANS", "Arena Scans", "en")
internal class ArenaScans(context: MangaLoaderContext) :
@ -14,10 +12,4 @@ internal class ArenaScans(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("arenascans.net")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("ASURASCANS", "Asura Scans", "en")
internal class AsuraScansParser(context: MangaLoaderContext) :
@ -14,11 +12,5 @@ internal class AsuraScansParser(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("asurascans.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("AZUREMANGA", "Azure Manga", "en")
internal class AzureManga(context: MangaLoaderContext) :
@ -14,10 +13,4 @@ internal class AzureManga(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("azuremanga.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("COSMICSCANS", "CosmicScans", "en")
internal class CosmicScansParser(context: MangaLoaderContext) :
@ -14,10 +12,4 @@ internal class CosmicScansParser(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("cosmicscans.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -6,7 +6,7 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
import java.util.Locale
@MangaSourceParser("ELARCPAGE", "Elarcpage", "en")
internal class Elarcpage(context: MangaLoaderContext) :
@ -16,8 +16,7 @@ internal class Elarcpage(context: MangaLoaderContext) :
override val listUrl: String
get() = "/series"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("FLAMESCANS", "Flame Scans", "en")
internal class FlameScans(context: MangaLoaderContext) :
@ -16,8 +14,4 @@ internal class FlameScans(context: MangaLoaderContext) :
override val listUrl: String
get() = "/series"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("KUMASCANS", "Kuma Scans", "en")
internal class KumaScans(context: MangaLoaderContext) :
@ -14,10 +13,4 @@ internal class KumaScans(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("kumascans.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("MANHWALOVER", "ManhwaLover", "en")
internal class ManhwaLover(context: MangaLoaderContext) :
@ -14,12 +12,6 @@ internal class ManhwaLover(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("manhwalover.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val isNsfwSource: Boolean = true
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("MANHWAX", "Manhwax", "en")
internal class Manhwax(context: MangaLoaderContext) :
@ -14,12 +12,5 @@ internal class Manhwax(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("manhwax.org")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val isNsfwSource: Boolean = true
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("NIGHTSCANS", "Nightscans", "en")
internal class Nightscans(context: MangaLoaderContext) :
@ -14,10 +12,4 @@ internal class Nightscans(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("nightscans.org")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("PHANTOMSCANS", "Phantomscans", "en")
internal class Phantomscans(context: MangaLoaderContext) :
@ -14,10 +12,4 @@ internal class Phantomscans(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("phantomscans.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("RAVENSCANS", "Ravenscans", "en")
internal class Ravenscans(context: MangaLoaderContext) :
@ -14,10 +12,4 @@ internal class Ravenscans(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("ravenscans.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,8 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("READKOMIK", "Readkomik", "en")
internal class Readkomik(context: MangaLoaderContext) :
@ -14,11 +13,5 @@ internal class Readkomik(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("readkomik.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("SKY_MANGA", "Sky Manga", "en")
internal class SkyManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SKY_MANGA, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("skymanga.work")
override val listUrl = "/manga-list"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("DD-MM-yyy", Locale.ENGLISH)
}

@ -5,8 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("SURYASCANS", "Suryascans", "en")
internal class Suryascans(context: MangaLoaderContext) :
@ -14,10 +12,4 @@ internal class Suryascans(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("suryascans.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -5,19 +5,10 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("VOIDSCANS", "Void Scans", "en")
internal class VoidScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.VOIDSCANS, pageSize = 150, searchPageSize = 150) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("void-scans.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
}

@ -16,8 +16,6 @@ internal class CartelDeManhwas(context: MangaLoaderContext) :
override val listUrl: String
get() = "/series"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("es", "ES"))
}

@ -14,9 +14,6 @@ internal class DragonTranslationParser(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("dragontranslation.com")
override val listUrl: String get() = "/manga"
override val tableMode: Boolean get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
}

@ -14,10 +14,6 @@ internal class GREMORYMANGAS(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("gremorymangas.com")
override val listUrl: String get() = "/manga"
override val tableMode: Boolean
get() = true
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("es", "ES"))
}

@ -14,8 +14,6 @@ internal class MiauScan(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("miauscan.com")
override val listUrl: String get() = "/manga"
override val tableMode: Boolean get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("es", "ES"))

@ -14,10 +14,5 @@ internal class Raikiscan(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("raikiscan.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("es", "ES"))
}

@ -14,10 +14,6 @@ internal class Senpaiediciones(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("senpaiediciones.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("es", "ES"))
}

@ -14,10 +14,6 @@ internal class Shadowmangas(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("shadowmangas.com")
override val listUrl: String
get() = "/manga"
override val tableMode: Boolean
get() = false
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("es", "ES"))
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save