add source and fix japscan

devi 3 years ago
parent 69e0a531df
commit aec87a9a67

@ -49,7 +49,7 @@ internal class JapScanParser(context: MangaLoaderContext) : PagedMangaParser(con
override val configKeyDomain = ConfigKey.Domain("www.japscan.lol", "japscan.ws")
override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP)
.add("User-Agent", UserAgents.CHROME_MOBILE)
.build()
override suspend fun getListPage(
@ -68,21 +68,19 @@ internal class JapScanParser(context: MangaLoaderContext) : PagedMangaParser(con
.build()
val root = webClient.httpGet(url).parseHtml()
.requireElementById("main")
.selectFirstOrThrow(".flex-wrap")
return root.select(".mainTitle")
.map { p ->
val div = checkNotNull(p.parent())
val a = div.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href")
.selectFirstOrThrow(".p-2.row.d-flex")
return root.select("div.col-4")
.map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
title = p.text(),
title = div.selectFirstOrThrow("p.p-1 a").text(),
altTitle = null,
url = href,
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirstOrThrow("img").attrAsAbsoluteUrl("src"),
coverUrl = div.selectFirstOrThrow("img.img-fluid").attrAsAbsoluteUrl("src"),
tags = setOf(),
state = null,
author = null,
@ -128,6 +126,27 @@ internal class JapScanParser(context: MangaLoaderContext) : PagedMangaParser(con
)
}
private fun extractQuotedContent(input: String): List<String> {
val regex = Regex("'(.*?)'")
return regex.findAll(input).map { it.groupValues[1] }.toList()
}
private fun listJSToKey(jsList: MutableList<String>, offsettab: Int, listKey: List<String>): MutableList<String> {
for (i in 0 until jsList.size) {
if (jsList[i].contains("0x")) {
var decoupeHexa = jsList[i].split("('")[1]
decoupeHexa = decoupeHexa.split("')")[0]
var indexkey = Integer.decode(decoupeHexa) - offsettab - 1
if (indexkey < 0) {
indexkey = listKey.size - 1
}
jsList[i] = listKey[indexkey]
}
}
return jsList
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val chapterUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(chapterUrl).parseHtml()
@ -137,20 +156,67 @@ internal class JapScanParser(context: MangaLoaderContext) : PagedMangaParser(con
val embeddedData = doc.requireElementById("data").attr("data-data")
val script = webClient.httpGet(scriptUrl).parseRaw()
val shortkeyRegex = Regex("""'([\dA-Z]{2})'""", RegexOption.IGNORE_CASE)
val longkeyRegex = Regex("""'([\dA-Z]{20})'""", RegexOption.IGNORE_CASE)
var tabKey = "'" + script.split("=['")[1]
tabKey = tabKey.split("];")[0]
val listKey = tabKey.split("','").toMutableList()
var decoupeOffset = script.split("-0x")[1]
decoupeOffset = "0x" + decoupeOffset.split(";")[0]
val offsettab = Integer.decode(decoupeOffset)
var decoupeFuncOrder = script.split("while(!![])")[1]
decoupeFuncOrder = decoupeFuncOrder.split("if")[0]
val listKeyOrder = extractQuotedContent(decoupeFuncOrder).toMutableList()
if (listKeyOrder.size < 3) {
throw Exception("L'ordre des clés n'a pas pu être déterminé")
}
var goodorder = false
for (i in 0 until listKey.size) {
for (z in 0 until listKeyOrder.size) {
if (listKey[Integer.decode(listKeyOrder[z]) - offsettab - 1].contains("[0-9]".toRegex())) {
goodorder = true
} else {
goodorder = false
break
}
}
if (goodorder) {
break
}
val firstElement = listKey.removeAt(0)
listKey.add(firstElement)
}
if (!goodorder) {
throw Exception("L'ordre des clés n'a pas pu être déterminé")
}
val zjscalc = script.split("/[A-Z0-9]/gi,")[1]
val calc1 = zjscalc.split(",")[0]
var calc1tab = calc1.split("+").toMutableList()
calc1tab = listJSToKey(calc1tab, offsettab, listKey)
val calc2 = zjscalc.split(",")[1]
var calc2tab = calc2.split("+").toMutableList()
calc2tab = listJSToKey(calc2tab, offsettab, listKey)
val longTables = longkeyRegex.findAll(script).map {
it.groupValues[1]
}.toList()
var key1 = calc1tab.joinToString("")
var key2 = calc2tab.joinToString("")
val shortTables = shortkeyRegex.findAll(script).map {
it.groupValues[1]
}.toList()
key1 = key1.replace("'", "")
key2 = key2.replace("'", "")
key1 = key1.replace(" ", "")
key2 = key2.replace(" ", "")
val keyTables = listOf(
shortTables[1].reversed() + longTables[1].reversed() + longTables[4].reversed() + longTables[0].reversed(),
shortTables[2].reversed() + longTables[3].reversed() + longTables[5].reversed() + longTables[2].reversed(),
key1.reversed(),
key2.reversed(),
)
var error: Exception? = null

@ -264,13 +264,14 @@ internal abstract class MadaraParser(
protected open val selectgenre = "div.genres-content a"
protected open val selectdate = "span.chapter-release-date i"
protected open val selectchapter = "li.wp-manga-chapter"
protected open val selectTestAsync = "div.listing-chapters_wrap"
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val body = doc.body()
val testchekasync = body.select("div.listing-chapters_wrap")
val testchekasync = body.select(selectTestAsync)
val chaptersDeferred = if (testchekasync.isNullOrEmpty()) {
async { loadChapters(manga.url, doc) }
@ -329,10 +330,10 @@ internal abstract class MadaraParser(
)
}
protected open suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
val root2 = doc.body().selectFirstOrThrow("div.content-area")
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return root2.select(selectchapter).mapChapters(reversed = true) { i, li ->
return doc.body().select(selectchapter).mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
val link = href + stylepage
@ -389,6 +390,8 @@ internal abstract class MadaraParser(
}
}
protected open val selectPage = "div.page-break"
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
@ -396,7 +399,7 @@ internal abstract class MadaraParser(
val chapterProtector = doc.getElementById("chapter-protector-data")
if (chapterProtector == null) {
val root = doc.body().selectFirstOrThrow("div.main-col-inner").selectFirstOrThrow("div.reading-content")
return root.select("div.page-break").map { div ->
return root.select(selectPage).map { div ->
val img = div.selectFirstOrThrow("img")
val url = img.src()?.toRelativeUrl(domain) ?: div.parseFailed("Image src not found")
MangaPage(
@ -436,30 +439,31 @@ internal abstract class MadaraParser(
val d = date?.lowercase() ?: return 0
return when {
d.endsWith(" ago") || d.endsWith(" atrás") || // Handle translated 'ago' in Portuguese.
d.startsWith("") || // other translated 'ago' in Portuguese.
d.endsWith(" hace") || // other translated 'ago' in Spanish
d.endsWith(" önce") || // Handle translated 'ago' in Turkish.
d.endsWith(" trước") || // Handle translated 'ago' in Viêt Nam.
d.startsWith("il y a") || // Handle translated 'ago' in French.
//If there is no ago but just a motion of time
// short Hours
d.endsWith(" h") ||
// short Day
d.endsWith(" d") ||
// Day in Portuguese
d.endsWith(" días") || d.endsWith(" día") ||
// Day in French
d.endsWith(" jour") || d.endsWith(" jours") ||
// Hours in Portuguese
d.endsWith(" horas") || d.endsWith(" hora") ||
// Hours in french
d.endsWith(" heure") || d.endsWith(" heures") ||
// Minutes in English
d.endsWith(" mins") ||
// Minutes in Portuguese
d.endsWith(" minutos") || d.endsWith(" minuto") ||
//Minutes in French
d.endsWith(" minute") || d.endsWith(" minutes") -> parseRelativeDate(date)
d.startsWith("") || // other translated 'ago' in Portuguese.
d.endsWith(" hace") || // other translated 'ago' in Spanish
d.endsWith(" назад") || // other translated 'ago' in Russian
d.endsWith(" önce") || // Handle translated 'ago' in Turkish.
d.endsWith(" trước") || // Handle translated 'ago' in Viêt Nam.
d.startsWith("il y a") || // Handle translated 'ago' in French.
//If there is no ago but just a motion of time
// short Hours
d.endsWith(" h") ||
// short Day
d.endsWith(" d") ||
// Day in Portuguese
d.endsWith(" días") || d.endsWith(" día") ||
// Day in French
d.endsWith(" jour") || d.endsWith(" jours") ||
// Hours in Portuguese
d.endsWith(" horas") || d.endsWith(" hora") ||
// Hours in french
d.endsWith(" heure") || d.endsWith(" heures") ||
// Minutes in English
d.endsWith(" mins") ||
// Minutes in Portuguese
d.endsWith(" minutos") || d.endsWith(" minuto") ||
//Minutes in French
d.endsWith(" minute") || d.endsWith(" minutes") -> parseRelativeDate(date)
// Handle 'yesterday' and 'today', using midnight
d.startsWith("year") -> Calendar.getInstance().apply {
@ -505,6 +509,7 @@ internal abstract class MadaraParser(
"day",
"days",
"d",
"день",
).anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("jam", "saat", "heure", "hora", "horas", "hour", "hours", "h").anyWordIn(date) -> cal.apply {
@ -523,6 +528,7 @@ internal abstract class MadaraParser(
"minuto",
"mins",
"phút",
"минут",
).anyWordIn(date) -> cal.apply {
add(
Calendar.MINUTE,
@ -554,10 +560,10 @@ internal abstract class MadaraParser(
private fun createRequestTemplate() =
("action=madara_load_more&page=1&template=madara-core%2Fcontent%2Fcontent-search&vars%5Bs%5D=&vars%5B" +
"orderby%5D=meta_value_num&vars%5Bpaged%5D=1&vars%5Btemplate%5D=search&vars%5Bmeta_query" +
"%5D%5B0%5D%5Brelation%5D=AND&vars%5Bmeta_query%5D%5Brelation%5D=OR&vars%5Bpost_type" +
"%5D=wp-manga&vars%5Bpost_status%5D=publish&vars%5Bmeta_key%5D=_latest_update&vars%5Border" +
"%5D=desc&vars%5Bmanga_archives_item_layout%5D=default").split(
"orderby%5D=meta_value_num&vars%5Bpaged%5D=1&vars%5Btemplate%5D=search&vars%5Bmeta_query" +
"%5D%5B0%5D%5Brelation%5D=AND&vars%5Bmeta_query%5D%5Brelation%5D=OR&vars%5Bpost_type" +
"%5D=wp-manga&vars%5Bpost_status%5D=publish&vars%5Bmeta_key%5D=_latest_update&vars%5Border" +
"%5D=desc&vars%5Bmanga_archives_item_layout%5D=default").split(
'&',
).map {
val pos = it.indexOf('=')

@ -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("FALCONMANGA", "FalconManga", "ar")
internal class FalconManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.FALCONMANGA, "falconmanga.com") {
override val datePattern = "d MMMM، yyyy"
}

@ -0,0 +1,11 @@
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("KOLMANGA", "KolManga", "ar")
internal class KolManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.KOLMANGA, "kolmanga.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("MANGALEKS", "MangaLeks", "ar")
internal class MangaLeks(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGALEKS, "mangaleks.com") {
override val datePattern = "yyyy/MM/dd"
override val postreq = true
}

@ -0,0 +1,11 @@
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("ARCANESCANS", "ArcaneScans", "en")
internal class ArcaneScans(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ARCANESCANS, "arcanescans.com", 10)

@ -0,0 +1,14 @@
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("COMIZ", "Comiz", "en")
internal class Comiz(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.COMIZ, "v2.comiz.net", 10) {
override val isNsfwSource = true
}

@ -0,0 +1,14 @@
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("DUCKMANGA", "DuckManga", "en")
internal class DuckManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.DUCKMANGA, "duckmanga.com", 20) {
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("GRABBER", "Grabber", "en")
internal class Grabber(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.GRABBER, "grabber.zone", 20) {
override val tagPrefix = "type/"
override val datePattern = "dd.MM.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("HENTAI3Z", "Hentai3z", "en")
internal class Hentai3z(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAI3Z, "hentai3z.xyz", pageSize = 20) {
override val isNsfwSource = true
override val withoutAjax = true
}

@ -0,0 +1,49 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
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.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrlOrNull
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.mapChapters
import org.koitharu.kotatsu.parsers.util.parseFailed
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import java.text.SimpleDateFormat
@MangaSourceParser("HENTAIXDICKGIRL", "Hentaixdickgirl", "en")
internal class Hentaixdickgirl(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAIXDICKGIRL, "hentaixdickgirl.com", 16) {
override val isNsfwSource = true
override val postreq = true
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
val root2 = doc.body().selectFirstOrThrow("div.listing-chapters_wrap")
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return root2.select(selectchapter).mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
val link = href + stylepage
val dateText = li.selectFirst("a.c-new-tag")?.attr("title") ?: li.selectFirst(selectdate)?.text()
val name = a.selectFirst("p")?.text() ?: a.ownText()
MangaChapter(
id = generateUid(href),
name = name,
number = i + 1,
url = link,
uploadDate = parseChapterDate(
dateFormat,
dateText,
),
source = source,
scanlator = null,
branch = null,
)
}
}
}

@ -0,0 +1,11 @@
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("JIMANGA", "JiManga", "en")
internal class JiManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.JIMANGA, "jimanga.com")

@ -0,0 +1,202 @@
package org.koitharu.kotatsu.parsers.site.madara.en
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
@MangaSourceParser("MANGADASS", "MangaDass", "en")
internal class MangaDass(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGADASS, "mangadass.com", 20) {
override val isNsfwSource = true
override val datePattern = "dd MMM yyyy"
override val withoutAjax = true
override val selectchapter = "li.a-h"
override val selectdesc = "div.ss-manga"
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val url = buildString {
append("https://")
append(domain)
val pages = page + 1
when {
!query.isNullOrEmpty() -> {
append("/?s=")
append(query.urlEncoded())
append("&page=")
append(pages.toString())
}
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append("/")
append(pages.toString())
append("?")
}
else -> {
append("/$listeurl")
append("/")
append(pages.toString())
append("?")
}
}
append("orderby=")
when (sortOrder) {
SortOrder.POPULARITY -> append("views")
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.row.c-tabs-item__content").ifEmpty {
doc.select("div.page-item-detail")
}.map { div ->
val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found")
val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,
tags = summary?.selectFirst(".mg_genres")?.select("a")?.mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
title = a.text().ifEmpty { return@mapNotNullToSet null }.toTitleCase(),
source = source,
)
}.orEmpty(),
author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
else -> null
},
source = source,
isNsfw = isNsfwSource,
)
}
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val body = doc.body()
val chaptersDeferred = async { getChapters(manga, doc) }
val desc = body.select(selectdesc).let {
if (it.select("p").text().isNotEmpty()) {
it.select("p").joinToString(separator = "\n\n") { p ->
p.text().replace("<br>", "\n")
}
} else {
it.text()
}
}
val stateDiv = (body.selectFirst("div.post-content_item:contains(Status)"))?.selectLast("div.summary-content")
val state = stateDiv?.let {
when (it.text()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
else -> null
}
}
val alt =
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()
manga.copy(
tags = doc.body().select(selectgenre).mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
title = a.text().toTitleCase(),
source = source,
)
},
description = desc,
altTitle = alt,
state = state,
chapters = chaptersDeferred.await(),
)
}
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
val root2 = doc.body().selectFirstOrThrow("div.panel-manga-chapter")
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return root2.select(selectchapter).mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
val link = href + stylepage
val dateText = li.selectFirst("a.c-new-tag")?.attr("title") ?: li.selectFirst(selectdate)?.text()
val name = a.selectFirst("p")?.text() ?: a.ownText()
MangaChapter(
id = generateUid(href),
name = name,
number = i + 1,
url = link,
uploadDate = parseChapterDate(
dateFormat,
dateText,
),
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().selectFirstOrThrow("div.read-manga").selectFirstOrThrow("div.read-content")
return root.select("img").map { img ->
val url = img.src()?.toRelativeUrl(domain) ?: img.parseFailed("Image src not found")
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
}

@ -0,0 +1,198 @@
package org.koitharu.kotatsu.parsers.site.madara.en
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
@MangaSourceParser("MANGADNA", "MangaDna", "en")
internal class MangaDna(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGADNA, "mangadna.com", 20) {
override val isNsfwSource = true
override val datePattern = "dd MMM yyyy"
override val withoutAjax = true
override val selectdesc = "div.dsct"
override val selectchapter = "li.a-h"
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val url = buildString {
append("https://")
append(domain)
val pages = page + 1
when {
!query.isNullOrEmpty() -> {
append("/page/")
append(pages.toString())
append("/?s=")
append(query.urlEncoded())
append("&post_type=wp-manga&")
}
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append("/page/")
append(pages.toString())
append("?")
}
else -> {
append("/$listeurl")
append("/page/")
append(pages.toString())
append("?")
}
}
append("m_orderby=")
when (sortOrder) {
SortOrder.POPULARITY -> append("views")
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.home-item").map { div ->
val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found")
val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".hcontent")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("div.hitem-rate span")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,
tags = summary?.selectFirst(".mg_genres")?.select("a")?.mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
title = a.text().ifEmpty { return@mapNotNullToSet null }.toTitleCase(),
source = source,
)
}.orEmpty(),
author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
else -> null
},
source = source,
isNsfw = isNsfwSource,
)
}
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val body = doc.body()
val chaptersDeferred = async { getChapters(manga, doc) }
val desc = body.select(selectdesc).let {
if (it.select("p").text().isNotEmpty()) {
it.select("p").joinToString(separator = "\n\n") { p ->
p.text().replace("<br>", "\n")
}
} else {
it.text()
}
}
val stateDiv = (body.selectFirst("div.post-content_item:contains(Status)"))?.selectLast("div.summary-content")
val state = stateDiv?.let {
when (it.text()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
else -> null
}
}
val alt =
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()
manga.copy(
tags = doc.body().select(selectgenre).mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
title = a.text().toTitleCase(),
source = source,
)
},
description = desc,
altTitle = alt,
state = state,
chapters = chaptersDeferred.await(),
)
}
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
val root2 = doc.body().selectFirstOrThrow("div.panel-manga-chapter")
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return root2.select(selectchapter).mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a")
val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
val link = href + stylepage
val dateText = li.selectFirst("a.c-new-tag")?.attr("title") ?: li.selectFirst(selectdate)?.text()
val name = a.selectFirst("p")?.text() ?: a.ownText()
MangaChapter(
id = generateUid(href),
name = name,
number = i + 1,
url = link,
uploadDate = parseChapterDate(
dateFormat,
dateText,
),
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().selectFirstOrThrow("div.read-manga").selectFirstOrThrow("div.read-content")
return root.select("img").map { img ->
val url = img.src()?.toRelativeUrl(domain) ?: img.parseFailed("Image src not found")
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
}

@ -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("MANGAFASTNET", "Manga Fast Net", "en")
internal class MangaFastNet(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAFASTNET, "manhuafast.net") {
override val withoutAjax = true
}

@ -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("MANGAGOYAOI", "Mangagoyaoi", "en")
internal class Mangagoyaoi(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAGOYAOI, "mangagoyaoi.com") {
override val isNsfwSource = true
}

@ -0,0 +1,105 @@
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.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.*
@MangaSourceParser("MANHWAZ", "Manhwaz", "en")
internal class Manhwaz(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHWAZ, "manhwaz.com", 40) {
override val listeurl = "genre/manhwa"
override val tagPrefix = "genre/"
override val withoutAjax = true
override val selectTestAsync = "div.list-chapter"
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val url = buildString {
append("https://")
append(domain)
val pages = page + 1
when {
!query.isNullOrEmpty() -> {
append("/search?s=")
append(query.urlEncoded())
append("&page=")
append(pages.toString())
}
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append("?page=")
append(pages.toString())
append("&")
}
else -> {
append("/$listeurl")
append("?page=")
append(pages.toString())
append("&")
}
}
append("m_orderby=")
when (sortOrder) {
SortOrder.POPULARITY -> append("views")
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
else -> append("latest")
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.row.c-tabs-item__content").ifEmpty {
doc.select("div.page-item-detail")
}.map { div ->
val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found")
val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,
tags = summary?.selectFirst(".mg_genres")?.select("a")?.mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
title = a.text().ifEmpty { return@mapNotNullToSet null }.toTitleCase(),
source = source,
)
}.orEmpty(),
author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
else -> null
},
source = source,
isNsfw = isNsfwSource,
)
}
}
}

@ -0,0 +1,14 @@
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("PARITEHABER", "Paritehaber", "en")
internal class Paritehaber(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.PARITEHABER, "www.paritehaber.com", 10) {
override val isNsfwSource = true
}

@ -0,0 +1,11 @@
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("RIO2MANGANET", "Rio2MangaNet", "en")
internal class Rio2MangaNet(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.RIO2MANGANET, "rio2manga.net", 10)

@ -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("SHIBAMANGA", "Shiba Manga", "en")
internal class ShibaManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.SHIBAMANGA, "shibamanga.com") {
override val datePattern = "MM/dd/yyyy"
}

@ -0,0 +1,14 @@
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("WEBCOMIC", "WebComic", "en")
internal class WebComic(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.WEBCOMIC, "webcomic.me") {
override val postreq = true
}

@ -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("COCORIP", "Cocorip", "es")
internal class Cocorip(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.COCORIP, "cocorip.net", 16) {
override val datePattern = "dd/MM/yyyy"
}

@ -0,0 +1,88 @@
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.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrlOrNull
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.host
import org.koitharu.kotatsu.parsers.util.parseFailed
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.urlEncoded
import java.util.EnumSet
@MangaSourceParser("DRAGONTRANSLATION", "DragonTranslation", "es")
internal class DragonTranslationParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.DRAGONTRANSLATION, "dragontranslation.net", 30) {
override val sortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
)
override val selectPage = "div#chapter_imgs img"
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val url = buildString {
append("https://")
append(domain)
val pages = page + 1
when {
!query.isNullOrEmpty() -> {
append("/mangas?buscar=")
append(query.urlEncoded())
append("&page=")
append(pages.toString())
}
!tags.isNullOrEmpty() -> {
append("/mangas?tag=")
for (tag in tags) {
append(tag.key)
}
append("&page=")
append(pages.toString())
}
else -> {
append("/mangas")
append("?page=")
append(pages.toString())
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.video-bg div.col-6 ").map { div ->
val href =
div.selectFirst("a.series-link")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img.thumb-img")?.src().orEmpty(),
title = div.selectFirst("div.series-box h5")?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = isNsfwSource,
)
}
}
}

@ -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("KOINOBORISCAN", "Koinobori Scan", "es")
internal class KoinoboriScan(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.KOINOBORISCAN, "koinoboriscan.com") {
override val postreq = true
}

@ -0,0 +1,15 @@
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("LECTORUNITOON", "Lectorunitoon", "es")
internal class Lectorunitoon(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.LECTORUNITOON, "lectorunitoon.com", 10) {
override val tagPrefix = "generos/"
override val datePattern = "dd/MM/yyyy"
}

@ -0,0 +1,11 @@
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("RIGHTDARKSCAN", "Rightdark Scan", "es")
internal class RightdarkScan(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.RIGHTDARKSCAN, "rightdark-scan.com", 10)

@ -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("TRADUCCIONESMOONLIGHT", "Traducciones Moonlight", "es")
internal class TraduccionesMoonlight(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.TRADUCCIONESMOONLIGHT, "traduccionesmoonlight.com") {
override val datePattern = "d MMMM, yyyy"
}

@ -0,0 +1,14 @@
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
@MangaSourceParser("INDO18H", "Indo18h", "id")
internal class Indo18h(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.INDO18H, "indo18h.com", 24) {
override val isNsfwSource = true
override val withoutAjax = true
}

@ -0,0 +1,103 @@
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.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.*
import java.util.Locale
@MangaSourceParser("MANHWAPLUS", "Manhwa Plus", "id")
internal class ManhwaPlus(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHWAPLUS, "manhwaplus.pro", 10) {
override val isNsfwSource = true
override val tagPrefix = "genre/"
override val datePattern = "MMMM d, yyyy"
override val sourceLocale: Locale = Locale.ENGLISH
override val withoutAjax = true
override val listeurl = "series/"
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val url = buildString {
append("https://")
append(domain)
val pages = page + 1
when {
!query.isNullOrEmpty() -> {
append("/page/")
append(pages.toString())
append("/?s=")
append(query.urlEncoded())
append("&post_type=wp-manga&")
}
!tags.isNullOrEmpty() -> {
append("/$tagPrefix")
for (tag in tags) {
append(tag.key)
}
append("/page/")
append(pages.toString())
append("?")
}
else -> {
append("/$listeurl")
append("/page/")
append(pages.toString())
append("?")
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.row.c-tabs-item__content").ifEmpty {
doc.select("div.page-item-detail")
}.map { div ->
val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found")
val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.attr("data-wpfc-original-src") ?: div.selectFirst("img")?.src()
.orEmpty(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4")
?: div.selectFirst("h5.series-title"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,
tags = summary?.selectFirst(".mg_genres")?.select("a")?.mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
title = a.text().ifEmpty { return@mapNotNullToSet null }.toTitleCase(),
source = source,
)
}.orEmpty(),
author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
else -> null
},
source = source,
isNsfw = isNsfwSource,
)
}
}
}

@ -0,0 +1,16 @@
package org.koitharu.kotatsu.parsers.site.madara.ru
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("MANGAZAVR", "Mangazavr", "ru")
internal class Mangazavr(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAZAVR, "mangazavr.ru") {
override val datePattern = "dd.MM.yyyy"
override val isNsfwSource = true
}

@ -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
import java.util.Locale
@MangaSourceParser("MANHUABUG", "Manhuabug", "th")
internal class Manhuabug(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHUABUG, "www.manhuabug.com", 10) {
override val datePattern: String = "d MMMM yyyy"
override val sourceLocale: Locale = Locale.ENGLISH
}

@ -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
import java.util.Locale
@MangaSourceParser("MANHUAKEY", "Manhuakey", "th")
internal class Manhuakey(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHUAKEY, "www.manhuakey.com", 10) {
override val datePattern: String = "d MMMM yyyy"
override val sourceLocale: Locale = Locale.ENGLISH
}

@ -0,0 +1,16 @@
package org.koitharu.kotatsu.parsers.site.madara.tr
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("KUROIMANGA", "Kuroi Manga", "tr")
internal class KuroiManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.KUROIMANGA, "www.kuroimanga.com") {
override val datePattern = "d MMMM yyyy"
override val isNsfwSource = true
}

@ -0,0 +1,16 @@
package org.koitharu.kotatsu.parsers.site.madara.tr
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("NIVERAFANSUB", "Nivera Fansub", "tr")
internal class NiveraFansub(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.NIVERAFANSUB, "niverafansub.com") {
override val datePattern = "d MMMM yyyy"
override val isNsfwSource = true
}

@ -0,0 +1,16 @@
package org.koitharu.kotatsu.parsers.site.madara.tr
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("VIYAFANSUB", "Viya Fansub", "tr")
internal class ViyaFansub(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.VIYAFANSUB, "viyafansub.com") {
override val datePattern = "d MMMM yyyy"
override val isNsfwSource = true
}

@ -0,0 +1,12 @@
package org.koitharu.kotatsu.parsers.site.madara.vi
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("MANGAZODIAC", "Manga Zodiac", "vi")
internal class MangaZodiac(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAZODIAC, "mangazodiac.com")

@ -29,6 +29,7 @@ import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.tryParse
import org.koitharu.kotatsu.parsers.util.urlEncoded
import java.text.SimpleDateFormat
import java.util.Base64
import java.util.EnumSet
import java.util.Locale
@ -92,6 +93,7 @@ internal abstract class MangaReaderParser(
tablemode.selectFirst(".infotable td:contains(Status)")
?: tablemode.selectFirst(".infotable td:contains(Statut)")
?: tablemode.selectFirst(".infotable td:contains(حالة العمل)")
?: tablemode.selectFirst(".infotable td:contains(الحالة)")
?: tablemode.selectFirst(".infotable td:contains(Estado)")
?: docs.selectFirst(".infotable td:contains(สถานะ)")
?: tablemode.selectFirst(".infotable td:contains(Stato )")
@ -103,7 +105,7 @@ internal abstract class MangaReaderParser(
?: 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(Statüsü)")
?: docs.selectFirst(".tsinfo div:contains(Statü)")
?: docs.selectFirst(".tsinfo div:contains(Statü)") ?: docs.selectFirst(".tsinfo div:contains(الحالة)")
}
val state = if (tablemode != null) {
@ -120,7 +122,7 @@ internal abstract class MangaReaderParser(
"En cours \uD83D\uDFE2", "En cours de publication", "Đ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", "Publicando", "连载中",
"Devam ediyor",
"Devam ediyor", "Devam Etmekte",
-> MangaState.ONGOING
"Completed", "Completo", "Complété", "Fini", "Achevé", "Terminé", "Terminé ⚫", "Tamamlandı", "Đã hoàn thành", "Hoàn Thành", "مكتملة",
@ -204,8 +206,10 @@ internal abstract class MangaReaderParser(
return parseMangaList(webClient.httpGet(url).parseHtml())
}
protected open val selectMangaliste = ".postbody .listupd .bs .bsx"
protected open fun parseMangaList(docs: Document): List<Manga> {
return docs.select(".postbody .listupd .bs .bsx").mapNotNull {
return docs.select(selectMangaliste).mapNotNull {
val a = it.selectFirst("a") ?: return@mapNotNull null
val relativeUrl = a.attrAsRelativeUrl("href")
val rating = it.selectFirst(".numscore")?.text()
@ -228,12 +232,15 @@ internal abstract class MangaReaderParser(
}
}
protected open val encodedSrc = false
protected open val selectScript = "div.wrapper script"
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val chapterUrl = chapter.url.toAbsoluteUrl(domain)
val docs = webClient.httpGet(chapterUrl).parseHtml()
val test = docs.select("script:containsData(ts_reader)")
if (test.isNullOrEmpty()) {
if (test.isNullOrEmpty() and !encodedSrc) {
return docs.select("div#readerarea img").map { img ->
val url = img.imageUrl()
MangaPage(
@ -244,11 +251,32 @@ internal abstract class MangaReaderParser(
)
}
} else {
val script = docs.selectFirstOrThrow("script:containsData(ts_reader)")
val images = JSONObject(script.data().substringAfter('(').substringBeforeLast(')'))
.getJSONArray("sources")
.getJSONObject(0)
.getJSONArray("images")
val images = if (encodedSrc) {
val script = docs.select(selectScript)
var decode = ""
for (i in script) {
if (i.attr("src").startsWith("data:text/javascript;base64,")) {
decode = Base64.getDecoder().decode(i.attr("src").replace("data:text/javascript;base64,", ""))
.decodeToString()
if (decode.startsWith("ts_reader.run")) {
break
}
}
}
JSONObject(decode.substringAfter('(').substringBeforeLast(')'))
.getJSONArray("sources")
.getJSONObject(0)
.getJSONArray("images")
} else {
val script = docs.selectFirstOrThrow("script:containsData(ts_reader)")
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(
@ -292,7 +320,7 @@ internal abstract class MangaReaderParser(
return@withLock tagMap
}
private fun Element.imageUrl(): String {
protected open fun Element.imageUrl(): String {
return attrAsAbsoluteUrlOrNull("src")
?: attrAsAbsoluteUrlOrNull("data-src")
?: attrAsAbsoluteUrlOrNull("data-cfsrc")

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.parsers.site.mangareader.ar
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("AREASCANS", "Areascans", "ar")
internal class Areascans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.AREASCANS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("www.areascans.net")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
}

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.parsers.site.mangareader.ar
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("BEASTSCANS", "Beast Scans", "ar")
internal class BeastScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.BEASTSCANS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("beast-scans.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
}

@ -0,0 +1,65 @@
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.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrl
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.mapChapters
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.tryParse
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("BABELTOON", "BabelToon", "en")
internal class BabelToon(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.BABELTOON, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("babeltoon.com")
override val listUrl = "/series"
override val selectMangaliste = ".postbody .listupd .maindet .inmain"
override val chapterDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
override suspend fun getDetails(manga: Manga): Manga {
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val chapters = docs.select(".eplister > ul > li").mapChapters(reversed = true) { index, element ->
val url = element.selectFirst("a")?.attrAsRelativeUrl("href") ?: return@mapChapters null
MangaChapter(
id = generateUid(url),
name = element.selectFirst(".epl-num")?.text() ?: "Chapter ${index + 1}",
url = url,
number = index + 1,
scanlator = null,
uploadDate = chapterDateFormat.tryParse(element.selectFirst(".epl-date")?.text()),
branch = null,
source = source,
)
}
return parseInfo(docs, manga, chapters)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val chapterUrl = chapter.url.toAbsoluteUrl(domain)
val docs = webClient.httpGet(chapterUrl).parseHtml()
return docs.select("div.epcontent img").map { img ->
val url = img.imageUrl()
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
}

@ -0,0 +1,15 @@
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
@MangaSourceParser("FREAKSCANS", "FreakScans", "en")
internal class FreakScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.FREAKSCANS, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("freakscans.com")
}

@ -0,0 +1,17 @@
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
@MangaSourceParser("QUEENSCANS", "QueenScans", "en")
internal class QueenScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.QUEENSCANS, pageSize = 30, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("queenscans.com")
override val listUrl = "/comics"
}

@ -8,12 +8,13 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("DRAGONTRANSLATION", "DragonTranslation", "es")
internal class DragonTranslationParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.DRAGONTRANSLATION, pageSize = 20, searchPageSize = 10) {
@MangaSourceParser("SKYMANGAS", "Sky Mangas", "es")
internal class SkyMangas(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SKYMANGAS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("dragontranslation.net")
get() = ConfigKey.Domain("skymangas.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("es", "ES"))
override val encodedSrc = true
}

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.parsers.site.mangareader.id
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("DOUJINDESURIP", "Doujin Desu Rip", "id")
internal class DoujinDesuRip(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.DOUJINDESURIP, pageSize = 10, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("doujindesu.rip")
override val isNsfwSource = true
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("in", "ID"))
}

@ -2,29 +2,12 @@ package org.koitharu.kotatsu.parsers.site.mangareader.id
import org.json.JSONObject
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.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN
import org.koitharu.kotatsu.parsers.model.WordSet
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrl
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.mapChapters
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.tryParse
import org.koitharu.kotatsu.parsers.util.*
import java.text.DateFormat
import java.util.Calendar
@ -118,13 +101,6 @@ internal class Komikcast(context: MangaLoaderContext) :
}
}
private fun Element.imageUrl(): String {
return attrAsAbsoluteUrlOrNull("src")
?: attrAsAbsoluteUrlOrNull("data-src")
?: attrAsAbsoluteUrlOrNull("data-cfsrc")
?: ""
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val chapterUrl = chapter.url.toAbsoluteUrl(domain)
val docs = webClient.httpGet(chapterUrl).parseHtml()

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.parsers.site.mangareader.id
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("KOMIKLOKALCFD", "Komiklokal Cfd", "id")
internal class KomiklokalCfd(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.KOMIKLOKALCFD, pageSize = 30, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("komiklokal.cfd")
override val isNsfwSource = true
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
}

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.parsers.site.mangareader.id
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("MANHWAINDOICU", "Manhwa Indo Icu", "id")
internal class ManhwaIndoIcu(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MANHWAINDOICU, pageSize = 30, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("manhwaindo.icu")
override val isNsfwSource = true
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
}

@ -0,0 +1,18 @@
package org.koitharu.kotatsu.parsers.site.mangareader.id
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("NONBIRI", "Nonbiri", "id")
internal class Nonbiri(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.NONBIRI, pageSize = 15, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("nonbiri.space")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("in", "ID"))
}

@ -0,0 +1,21 @@
package org.koitharu.kotatsu.parsers.site.mangareader.ja
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("MANGAMATE", "Manga Mate", "ja")
internal class MangaMate(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MANGAMATE, pageSize = 10, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("manga-mate.org")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("M月 d, yyyy", Locale.ENGLISH)
override val encodedSrc = true
}

@ -0,0 +1,18 @@
package org.koitharu.kotatsu.parsers.site.mangareader.th
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("MANGAMOONS", "Manga Moons", "th")
internal class MangaMoons(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MANGAMOONS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("manga-moons.net")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("th", "TH"))
}

@ -0,0 +1,18 @@
package org.koitharu.kotatsu.parsers.site.mangareader.tr
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("AFRODITSCANS", "Afrodit Scans", "tr")
internal class AfroditScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.AFRODITSCANS, pageSize = 24, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("afroditscans.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("tr"))
}

@ -0,0 +1,19 @@
package org.koitharu.kotatsu.parsers.site.mangareader.tr
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("ATHENAFANSUB", "AthenaFansub", "tr")
internal class AthenaFansub(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.ATHENAFANSUB, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("athenafansub.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("tr", "TR"))
}

@ -0,0 +1,19 @@
package org.koitharu.kotatsu.parsers.site.mangareader.tr
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("NYXMANGA", "Nyx Manga", "tr")
internal class NyxManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.NYXMANGA, pageSize = 14, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("nyxmanga.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("tr", "TR"))
}

@ -0,0 +1,19 @@
package org.koitharu.kotatsu.parsers.site.mangareader.tr
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("SPARTANMANGA", "Spartan Manga", "tr")
internal class SpartanManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SPARTANMANGA, pageSize = 40, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("spartanmanga.com.tr")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("tr", "TR"))
}
Loading…
Cancel
Save