Merge pull request #217 from davvarrr/master

add source and fix
Koitharu 3 years ago committed by GitHub
commit 506f6f7d30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.all
import androidx.collection.ArraySet
import org.json.JSONArray

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.all
import androidx.collection.ArraySet
import androidx.collection.SparseArrayCompat

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.all
import androidx.collection.SparseArrayCompat
import androidx.collection.set

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.all
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.all
import androidx.collection.ArraySet
import kotlinx.coroutines.async

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.all
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.be
import androidx.collection.ArraySet
import org.json.JSONArray

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.en
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.MangaLoaderContext

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.en
import androidx.collection.ArrayMap
import org.koitharu.kotatsu.parsers.MangaLoaderContext

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.es
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.fr
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
@ -10,32 +10,9 @@ 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
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.RATING_UNKNOWN
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.assertNotNull
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrlOrNull
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrl
import org.koitharu.kotatsu.parsers.util.concatUrl
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.flattenTo
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.getIntOrDefault
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.ownTextOrNull
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.parseJson
import org.koitharu.kotatsu.parsers.util.requireElementById
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.textOrNull
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.toTitleCase
import org.koitharu.kotatsu.parsers.util.urlBuilder
import java.util.Calendar
import java.util.EnumSet

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.fr
import okhttp3.Headers
import org.json.JSONObject
@ -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

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.fr
import okhttp3.Headers
import org.koitharu.kotatsu.parsers.MangaLoaderContext

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.id
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site
package org.koitharu.kotatsu.parsers.site.ja
import org.koitharu.kotatsu.parsers.InternalParsersApi
import org.koitharu.kotatsu.parsers.MangaLoaderContext

@ -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")

@ -8,6 +8,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage
@ -29,23 +30,26 @@ 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
internal abstract class MangaReaderParser(
context: MangaLoaderContext,
source: MangaSource,
domain: String,
pageSize: Int,
searchPageSize: Int,
) : PagedMangaParser(context, source, pageSize, searchPageSize) {
override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.NEWEST)
protected open val listUrl = "/manga"
protected open val isNsfwSource = false
open val chapterDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
protected open val datePattern = "MMMM d, yyyy"
private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex()
@ -53,6 +57,7 @@ internal abstract class MangaReaderParser(
override suspend fun getDetails(manga: Manga): Manga {
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val chapters = docs.select("#chapterlist > ul > li").mapChapters(reversed = true) { index, element ->
val url = element.selectFirst("a")?.attrAsRelativeUrl("href") ?: return@mapChapters null
MangaChapter(
@ -61,7 +66,7 @@ internal abstract class MangaReaderParser(
url = url,
number = index + 1,
scanlator = null,
uploadDate = chapterDateFormat.tryParse(element.selectFirst(".chapterdate")?.text()),
uploadDate = dateFormat.tryParse(element.selectFirst(".chapterdate")?.text()),
branch = null,
source = source,
)
@ -92,6 +97,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 +109,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 +126,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 +210,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 +236,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 +255,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 +324,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,10 @@
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.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("AREASCANS", "Areascans", "ar")
internal class Areascans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.AREASCANS, "www.areascans.net", pageSize = 20, searchPageSize = 10)

@ -0,0 +1,10 @@
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.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("BEASTSCANS", "Beast Scans", "ar")
internal class BeastScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.BEASTSCANS, "beast-scans.com", pageSize = 20, searchPageSize = 10)

@ -2,19 +2,9 @@ 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("GALAXYMANGA", "Galaxymanga", "ar")
internal class Galaxymanga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.GALAXYMANGA, pageSize = 40, searchPageSize = 30) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("galaxymanga.org")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
}
MangaReaderParser(context, MangaSource.GALAXYMANGA, "galaxymanga.org", pageSize = 40, searchPageSize = 30)

@ -2,20 +2,12 @@ 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("MANGAPROTM", "MangaProtm", "ar")
internal class MangaProtm(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MANGAPROTM, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("mangaprotm.com")
MangaReaderParser(context, MangaSource.MANGAPROTM, "mangaprotm.com", pageSize = 20, searchPageSize = 20) {
override val listUrl = "/series"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
}

@ -2,19 +2,9 @@ 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("MANGAATREND", "Mangaatrend", "ar")
internal class Mangaatrend(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MANGAATREND, pageSize = 40, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("mangaatrend.net")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
}
MangaReaderParser(context, MangaSource.MANGAATREND, "mangaatrend.net", pageSize = 40, searchPageSize = 20)

@ -2,7 +2,6 @@ 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.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource
@ -22,15 +21,13 @@ import java.util.Locale
@MangaSourceParser("OXAPK", "Oxapk", "ar")
internal class Oxapk(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.OXAPK, pageSize = 24, searchPageSize = 10) {
MangaReaderParser(context, MangaSource.OXAPK, "oxapk.com", pageSize = 24, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("oxapk.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
override val sourceLocale: Locale = Locale.ENGLISH
override suspend fun getDetails(manga: Manga): Manga {
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val chapters = docs.select("#chapterlist > ul > li").mapChapters(reversed = true) { index, element ->
val url = element.selectFirst("a")?.attrAsRelativeUrl("href") ?: return@mapChapters null
MangaChapter(
@ -40,7 +37,7 @@ internal class Oxapk(context: MangaLoaderContext) :
number = index + 1,
scanlator = null,
uploadDate = parseChapterDate(
chapterDateFormat,
dateFormat,
element.selectFirst("div.chapter-link-time")?.text(),
),
branch = null,
@ -50,7 +47,7 @@ internal class Oxapk(context: MangaLoaderContext) :
return parseInfo(docs, manga, chapters)
}
protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
date ?: return 0
return when {
date.endsWith("منذ ", ignoreCase = true) -> {

@ -2,17 +2,9 @@ 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("OZULSCANS", "Ozulscans", "ar")
internal class Ozulscans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.OZULSCANS, pageSize = 30, searchPageSize = 30) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("ozulscans.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
}
MangaReaderParser(context, MangaSource.OZULSCANS, "ozulscans.com", pageSize = 30, searchPageSize = 30)

@ -3,7 +3,6 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.jsoup.nodes.Document
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.MangaSource
@ -20,20 +19,16 @@ import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.toTitleCase
import org.koitharu.kotatsu.parsers.util.tryParse
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("SWATEAM", "Swa Team", "ar")
internal class SwaTeam(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SWATEAM, pageSize = 42, searchPageSize = 39) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("swatop.club")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("dd-MM-yyyy", Locale("ar", "AR"))
MangaReaderParser(context, MangaSource.SWATEAM, "swatop.club", pageSize = 42, searchPageSize = 39) {
override val datePattern = "dd-MM-yyyy"
override suspend fun getDetails(manga: Manga): Manga {
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val chapters = docs.select("div.bixbox li").mapChapters(reversed = true) { index, element ->
val url = element.selectFirst("a")?.attrAsRelativeUrl("href") ?: return@mapChapters null
MangaChapter(
@ -42,7 +37,7 @@ internal class SwaTeam(context: MangaLoaderContext) :
url = url,
number = index + 1,
scanlator = null,
uploadDate = chapterDateFormat.tryParse(element.selectFirst(".chapterdate")?.text()),
uploadDate = dateFormat.tryParse(element.selectFirst(".chapterdate")?.text()),
branch = null,
source = source,
)

@ -2,17 +2,13 @@ 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("ANIGLISCANS", "Anigli Scans", "en")
internal class AnigliScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.ANIGLISCANS, pageSize = 47, searchPageSize = 47) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("anigliscans.com")
override val listUrl: String
get() = "/series"
MangaReaderParser(context, MangaSource.ANIGLISCANS, "anigliscans.com", pageSize = 47, searchPageSize = 47) {
override val listUrl = "/series"
override val datePattern = "MMM d, yyyy"
}

@ -2,14 +2,13 @@ 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("ARENASCANS", "Arena Scans", "en")
internal class ArenaScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.ARENASCANS, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("arenascans.net")
MangaReaderParser(context, MangaSource.ARENASCANS, "arenascans.net", pageSize = 20, searchPageSize = 20) {
override val datePattern = "MMM d, yyyy"
}

@ -2,15 +2,12 @@ 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("ASURASCANS", "Asura Scans", "en")
internal class AsuraScansParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.ASURASCANS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("asura.gg")
MangaReaderParser(context, MangaSource.ASURASCANS, "asura.gg", pageSize = 20, searchPageSize = 10) {
override val datePattern = "MMM d, yyyy"
}

@ -2,15 +2,13 @@ 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("AZUREMANGA", "Azure Manga", "en")
internal class AzureManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.AZUREMANGA, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("azuremanga.com")
MangaReaderParser(context, MangaSource.AZUREMANGA, "azuremanga.com", pageSize = 20, searchPageSize = 10) {
override val datePattern = "MMM d, yyyy"
}

@ -0,0 +1,60 @@
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.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
@MangaSourceParser("BABELTOON", "BabelToon", "en")
internal class BabelToon(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.BABELTOON, "babeltoon.com", pageSize = 20, searchPageSize = 10) {
override val listUrl = "/series"
override val selectMangaliste = ".postbody .listupd .maindet .inmain"
override suspend fun getDetails(manga: Manga): Manga {
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
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 = dateFormat.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,
)
}
}
}

@ -2,14 +2,13 @@ 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("COSMICSCANS", "CosmicScans", "en")
internal class CosmicScansParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.COSMICSCANS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("cosmicscans.com")
MangaReaderParser(context, MangaSource.COSMICSCANS, "cosmicscans.com", pageSize = 20, searchPageSize = 10) {
override val datePattern = "MMM d, yyyy"
}

@ -2,21 +2,13 @@ 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("ELARCPAGE", "Elarcpage", "en")
internal class Elarcpage(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.ELARCPAGE, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("elarcpage.com")
MangaReaderParser(context, MangaSource.ELARCPAGE, "elarcpage.com", pageSize = 20, searchPageSize = 10) {
override val listUrl: String
get() = "/series"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH)
override val listUrl = "/series"
override val datePattern = "MMM d, yyyy"
}

@ -2,16 +2,13 @@ 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("FLAMESCANS", "Flame Scans", "en")
internal class FlameScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.FLAMESCANS, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("flamescans.org")
MangaReaderParser(context, MangaSource.FLAMESCANS, "flamescans.org", pageSize = 20, searchPageSize = 20) {
override val listUrl: String
get() = "/series"
override val listUrl = "/series"
override val datePattern = "MMM d, yyyy"
}

@ -0,0 +1,14 @@
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.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("FREAKSCANS", "FreakScans", "en")
internal class FreakScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.FREAKSCANS, "freakscans.com", pageSize = 20, searchPageSize = 20) {
override val datePattern = "MMM d, yyyy"
}

@ -2,15 +2,13 @@ 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("KUMASCANS", "Kuma Scans", "en")
internal class KumaScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.KUMASCANS, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("kumascans.com")
MangaReaderParser(context, MangaSource.KUMASCANS, "kumascans.com", pageSize = 20, searchPageSize = 20) {
override val datePattern = "MMM d, yyyy"
}

@ -2,22 +2,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
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("LUNAR_SCAN", "Lunar Scan", "en")
internal class LunarScan(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.LUNAR_SCAN, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("lunarscan.org")
MangaReaderParser(context, MangaSource.LUNAR_SCAN, "lunarscan.org", pageSize = 20, searchPageSize = 20) {
override val listUrl = "/series"
override val isNsfwSource: Boolean = true
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.ENGLISH)
}

@ -2,16 +2,13 @@ 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("MANHWALOVER", "ManhwaLover", "en")
internal class ManhwaLover(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MANHWALOVER, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("manhwalover.com")
MangaReaderParser(context, MangaSource.MANHWALOVER, "manhwalover.com", pageSize = 20, searchPageSize = 20) {
override val isNsfwSource: Boolean = true
override val datePattern = "MMM d, yyyy"
}

@ -2,15 +2,13 @@ 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("MANHWAX", "Manhwax", "en")
internal class Manhwax(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MANHWAX, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("manhwax.org")
MangaReaderParser(context, MangaSource.MANHWAX, "manhwax.org", pageSize = 20, searchPageSize = 20) {
override val isNsfwSource: Boolean = true
override val datePattern = "MMM d, yyyy"
}

@ -2,14 +2,12 @@ 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("NIGHTSCANS", "Nightscans", "en")
internal class Nightscans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.NIGHTSCANS, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("nightscans.org")
MangaReaderParser(context, MangaSource.NIGHTSCANS, "nightscans.org", pageSize = 20, searchPageSize = 20) {
override val datePattern = "MMM d, yyyy"
}

@ -2,14 +2,12 @@ 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("PHANTOMSCANS", "Phantomscans", "en")
internal class Phantomscans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.PHANTOMSCANS, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("phantomscans.com")
MangaReaderParser(context, MangaSource.PHANTOMSCANS, "phantomscans.com", pageSize = 20, searchPageSize = 20) {
override val datePattern = "MMM d, yyyy"
}

@ -0,0 +1,14 @@
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.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("QUEENSCANS", "QueenScans", "en")
internal class QueenScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.QUEENSCANS, "queenscans.com", pageSize = 30, searchPageSize = 10) {
override val listUrl = "/comics"
override val datePattern = "MMM d, yyyy"
}

@ -2,14 +2,12 @@ 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("RAVENSCANS", "Ravenscans", "en")
internal class Ravenscans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.RAVENSCANS, pageSize = 10, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("ravenscans.com")
MangaReaderParser(context, MangaSource.RAVENSCANS, "ravenscans.com", pageSize = 10, searchPageSize = 10) {
override val datePattern = "MMM d, yyyy"
}

@ -2,16 +2,14 @@ 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("READKOMIK", "Readkomik", "en")
internal class Readkomik(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.READKOMIK, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("readkomik.com")
MangaReaderParser(context, MangaSource.READKOMIK, "readkomik.com", pageSize = 20, searchPageSize = 20) {
override val datePattern = "MMM d, yyyy"
}

@ -2,19 +2,14 @@ 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("REALMSCANS", "RealmScans", "en")
internal class RealmScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.REALMSCANS, pageSize = 30, searchPageSize = 50) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("realmscans.xyz")
MangaReaderParser(context, MangaSource.REALMSCANS, "realmscans.xyz", pageSize = 30, searchPageSize = 50) {
override val listUrl = "/series"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH)
override val datePattern = "dd MMM yyyy"
}

@ -2,19 +2,14 @@ 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")
MangaReaderParser(context, MangaSource.SKY_MANGA, "skymanga.work", pageSize = 20, searchPageSize = 20) {
override val listUrl = "/manga-list"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("DD-MM-yyy", Locale.ENGLISH)
override val datePattern = "DD-MM-yyy"
}

@ -2,14 +2,12 @@ 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("SURYASCANS", "Suryascans", "en")
internal class Suryascans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SURYASCANS, pageSize = 5, searchPageSize = 5) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("suryascans.com")
MangaReaderParser(context, MangaSource.SURYASCANS, "suryascans.com", pageSize = 5, searchPageSize = 5) {
override val datePattern = "MMM d, yyyy"
}

@ -2,13 +2,12 @@ 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("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")
MangaReaderParser(context, MangaSource.VOIDSCANS, "void-scans.com", pageSize = 150, searchPageSize = 150) {
override val datePattern = "MMM d, yyyy"
}

@ -2,20 +2,13 @@ package org.koitharu.kotatsu.parsers.site.mangareader.es
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("CARTELDEMANHWAS", "Cartel De Manhwas", "es")
internal class CartelDeManhwas(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.CARTELDEMANHWAS, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("carteldemanhwas.com")
MangaReaderParser(context, MangaSource.CARTELDEMANHWAS, "carteldemanhwas.com", pageSize = 20, searchPageSize = 20) {
override val listUrl: String
get() = "/series"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("es", "ES"))
override val listUrl = "/series"
override val datePattern = "MMM d, yyyy"
}

@ -1,19 +0,0 @@
package org.koitharu.kotatsu.parsers.site.mangareader.es
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("DRAGONTRANSLATION", "DragonTranslation", "es")
internal class DragonTranslationParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.DRAGONTRANSLATION, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("dragontranslation.net")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
}

@ -2,18 +2,9 @@ package org.koitharu.kotatsu.parsers.site.mangareader.es
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("GREMORYMANGAS", "Gremory Mangas", "es")
internal class GREMORYMANGAS(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.GREMORYMANGAS, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("gremorymangas.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("es", "ES"))
}
MangaReaderParser(context, MangaSource.GREMORYMANGAS, "gremorymangas.com", pageSize = 20, searchPageSize = 20)

@ -2,16 +2,16 @@ package org.koitharu.kotatsu.parsers.site.mangareader.es
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.util.Locale
@MangaSourceParser("LEGIONSCANS", "Legion Scans", "es")
internal class LegionScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.LEGIONSCANS, pageSize = 20, searchPageSize = 20) {
MangaReaderParser(context, MangaSource.LEGIONSCANS, "legionscans.com", pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("legionscans.com")
override val datePattern = "MMM d, yyyy"
override val sourceLocale: Locale = Locale.ENGLISH
}

@ -2,19 +2,9 @@ package org.koitharu.kotatsu.parsers.site.mangareader.es
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("MIAUSCAN", "Miau Scan", "es")
internal class MiauScan(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MIAUSCAN, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("miauscan.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("es", "ES"))
}
MangaReaderParser(context, MangaSource.MIAUSCAN, "miauscan.com", pageSize = 20, searchPageSize = 20)

@ -2,17 +2,12 @@ package org.koitharu.kotatsu.parsers.site.mangareader.es
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("RAIKISCAN", "Raikiscan", "es")
internal class Raikiscan(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.RAIKISCAN, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("raikiscan.com")
MangaReaderParser(context, MangaSource.RAIKISCAN, "raikiscan.com", pageSize = 20, searchPageSize = 20) {
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("es", "ES"))
override val datePattern = "MMM d, yyyy"
}

@ -2,18 +2,12 @@ package org.koitharu.kotatsu.parsers.site.mangareader.es
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("SENPAIEDICIONES", "Senpaiediciones", "es")
internal class Senpaiediciones(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SENPAIEDICIONES, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("senpaiediciones.com")
MangaReaderParser(context, MangaSource.SENPAIEDICIONES, "senpaiediciones.com", pageSize = 20, searchPageSize = 20) {
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("es", "ES"))
override val datePattern = "MMM d, yyyy"
}

@ -2,18 +2,12 @@ package org.koitharu.kotatsu.parsers.site.mangareader.es
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("SHADOWMANGAS", "Shadowmangas", "es")
internal class Shadowmangas(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SHADOWMANGAS, pageSize = 10, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("shadowmangas.com")
MangaReaderParser(context, MangaSource.SHADOWMANGAS, "shadowmangas.com", pageSize = 10, searchPageSize = 10) {
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale("es", "ES"))
override val datePattern = "MMM d, yyyy"
}

@ -0,0 +1,13 @@
package org.koitharu.kotatsu.parsers.site.mangareader.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.mangareader.MangaReaderParser
@MangaSourceParser("SKYMANGAS", "Sky Mangas", "es")
internal class SkyMangas(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SKYMANGAS, "skymangas.com", pageSize = 20, searchPageSize = 10) {
override val encodedSrc = true
}

@ -2,18 +2,12 @@ package org.koitharu.kotatsu.parsers.site.mangareader.fr
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("BANANASCAN", "Banana Scan", "fr")
internal class BananaScan(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.BANANASCAN, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("banana-scan.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.FRENCH)
MangaReaderParser(context, MangaSource.BANANASCAN, "banana-scan.com", pageSize = 20, searchPageSize = 20) {
override val datePattern = "MMM d, yyyy"
}

@ -2,19 +2,12 @@ package org.koitharu.kotatsu.parsers.site.mangareader.fr
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("EPSILONSCAN", "Epsilonscan", "fr")
internal class EpsilonscanParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.EPSILONSCAN, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("epsilonscan.fr")
MangaReaderParser(context, MangaSource.EPSILONSCAN, "epsilonscan.fr", pageSize = 20, searchPageSize = 10) {
override val isNsfwSource: Boolean = true
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.FRENCH)
}

@ -2,18 +2,9 @@ package org.koitharu.kotatsu.parsers.site.mangareader.fr
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("LEGACY_SCANS", "Legacy Scans", "fr")
internal class LegacyScansParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.LEGACY_SCANS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("legacy-scans.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.FRENCH)
}
MangaReaderParser(context, MangaSource.LEGACY_SCANS, "legacy-scans.com", pageSize = 20, searchPageSize = 10)

@ -3,7 +3,6 @@ package org.koitharu.kotatsu.parsers.site.mangareader.fr
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.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaSource
@ -16,16 +15,10 @@ import org.koitharu.kotatsu.parsers.util.requireElementById
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.toRelativeUrl
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("LELMANGA", "LelManga", "fr")
internal class LelManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.LELMANGA, pageSize = 21, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("www.lelmanga.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
MangaReaderParser(context, MangaSource.LELMANGA, "www.lelmanga.com", pageSize = 21, searchPageSize = 20) {
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
@ -42,7 +35,7 @@ internal class LelManga(context: MangaLoaderContext) :
}
}
protected fun Element.src(): String? {
private fun Element.src(): String? {
var result = absUrl("data-src")
if (result.isEmpty()) result = absUrl("data-cfsrc")
if (result.isEmpty()) result = absUrl("src")

@ -2,18 +2,12 @@ package org.koitharu.kotatsu.parsers.site.mangareader.fr
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("PHENIXSCANS", "Phenixscans", "fr")
internal class PhenixscansParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.PHENIXSCANS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("phenixscans.fr")
MangaReaderParser(context, MangaSource.PHENIXSCANS, "phenixscans.fr", pageSize = 20, searchPageSize = 10) {
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.FRENCH)
override val datePattern = "MMM d, yyyy"
}

@ -2,18 +2,13 @@ package org.koitharu.kotatsu.parsers.site.mangareader.fr
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("SUSHISCAN", "SushiScan", "fr")
internal class SushiScan(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SUSHISCAN, pageSize = 20, searchPageSize = 10) {
MangaReaderParser(context, MangaSource.SUSHISCAN, "sushiscan.net", pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("sushiscan.net")
override val listUrl = "/catalogue"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMM d, yyyy", Locale.FRENCH)
override val datePattern = "MMM d, yyyy"
}

@ -2,17 +2,9 @@ package org.koitharu.kotatsu.parsers.site.mangareader.fr
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("SUSHISCANFR", "Sushi Scan FR", "fr")
internal class SushiScanFR(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.SUSHISCANFR, pageSize = 36, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("sushiscan.fr")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.FRENCH)
}
MangaReaderParser(context, MangaSource.SUSHISCANFR, "sushiscan.fr", pageSize = 36, searchPageSize = 10)

@ -2,17 +2,9 @@ package org.koitharu.kotatsu.parsers.site.mangareader.fr
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("VFSCAN", "Vf Scan", "fr")
internal class VfScan(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.VFSCAN, pageSize = 18, searchPageSize = 18) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("www.vfscan.com")
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.FRENCH)
}
MangaReaderParser(context, MangaSource.VFSCAN, "www.vfscan.com", pageSize = 18, searchPageSize = 18)

@ -2,16 +2,17 @@ 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.util.Locale
@MangaSourceParser("AINZSCANS", "Ainz Scans", "id")
internal class AinzScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.AINZSCANS, pageSize = 20, searchPageSize = 10) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("ainzscans.site")
MangaReaderParser(context, MangaSource.AINZSCANS, "ainzscans.site", pageSize = 20, searchPageSize = 10) {
override val listUrl = "/series"
override val datePattern = "MMM d, yyyy"
override val sourceLocale: Locale = Locale.ENGLISH
}

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

Loading…
Cancel
Save