Merge pull request #283 from KotatsuApp/devi4

add sources and fix
pull/327/head
Koitharu 3 years ago committed by GitHub
commit a61e441e79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -85,7 +85,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : MangaParser(contex
coverUrl = jo.getString("cover_url"),
largeCoverUrl = null,
description = jo.getStringOrNull("desc"),
tags = jo.selectGenres("genres", tagsMap),
tags = jo.selectGenres(tagsMap),
state = runCatching {
if (jo.getBoolean("translation_completed")) {
MangaState.FINISHED
@ -203,8 +203,8 @@ internal class ComickFunParser(context: MangaLoaderContext) : MangaParser(contex
return chaptersBuilder.toList()
}
private fun JSONObject.selectGenres(name: String, tags: SparseArrayCompat<MangaTag>): Set<MangaTag> {
val array = optJSONArray(name) ?: return emptySet()
private fun JSONObject.selectGenres(tags: SparseArrayCompat<MangaTag>): Set<MangaTag> {
val array = optJSONArray("genres") ?: return emptySet()
val res = ArraySet<MangaTag>(array.length())
for (i in 0 until array.length()) {
val id = array.getInt(i)

@ -0,0 +1,179 @@
package org.koitharu.kotatsu.parsers.site.all
import androidx.collection.ArraySet
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@MangaSourceParser("HENTAIFOX", "Hentai Fox", type = ContentType.HENTAI)
internal class HentaiFox(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.HENTAIFOX, 20) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("hentaifox.com")
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
if (!tags.isNullOrEmpty()) {
append("/tag/")
append(tag?.key.orEmpty())
if (page > 1) {
append("/pag/")
append(page)
append("/")
}
} else if (!query.isNullOrEmpty()) {
append("/search/?q=")
append(query.urlEncoded())
if (page > 1) {
append("&page=")
append(page)
}
} else {
if (page > 2) {
append("/pag/")
append(page)
append("/")
} else if (page > 1) {
append("/page/")
append(page)
append("/")
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select(".lc_galleries .thumb").map { div ->
val href = div.selectFirstOrThrow(".inner_thumb a").attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
title = div.select("h2.g_title").text(),
altTitle = null,
url = href,
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = isNsfwSource,
coverUrl = div.selectFirstOrThrow("img").src().orEmpty(),
tags = emptySet(),
state = null,
author = null,
source = source,
)
}
}
//Tags are deliberately reduced because there are too many and this slows down the application.
//only the most popular ones are taken.
override suspend fun getTags(): Set<MangaTag> {
return coroutineScope {
(1..3).map { page ->
async { getTags(page) }
}
}.awaitAll().flattenTo(ArraySet(360))
}
private suspend fun getTags(page: Int): Set<MangaTag> {
val url = "https://$domain/tags/popular/pag/$page/"
val root = webClient.httpGet(url).parseHtml()
return root.parseTags()
}
private fun Element.parseTags() = select(".list_tags a.tag_btn").mapToSet {
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
MangaTag(
key = key,
title = it.selectFirstOrThrow("h3").text(),
source = source,
)
}
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val urlChapters = manga.url.replace("/gallery/", "/g/") + "1/"
return manga.copy(
altTitle = null,
tags = doc.select("ul.tags a.tag_btn ").mapNotNullToSet {
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
MangaTag(
key = key,
title = it.html().substringBefore("<span"),
source = source,
)
},
author = doc.selectFirst("ul.artists a.tag_btn")?.html()?.substringBefore("<span"),
description = null,
chapters = listOf(
MangaChapter(
id = manga.id,
name = manga.title,
number = 1,
url = urlChapters,
scanlator = null,
uploadDate = 0,
branch = doc.selectFirstOrThrow("ul.languages a.tag_btn").html().substringBefore("<span"),
source = source,
),
),
)
}
override suspend fun getRelatedManga(seed: Manga): List<Manga> {
val doc = webClient.httpGet(seed.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.body().selectFirstOrThrow(".related_galleries")
return root.select("div.thumb").mapNotNull { div ->
val a = div.selectFirst(".inner_thumb a") ?: return@mapNotNull null
val href = a.attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(a.host ?: domain),
altTitle = null,
title = div.selectFirstOrThrow("h2.g_title").text(),
author = null,
coverUrl = div.selectFirst("img")?.src().orEmpty(),
tags = emptySet(),
rating = RATING_UNKNOWN,
state = null,
isNsfw = isNsfwSource,
source = source,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml()
val totalPages = doc.selectFirstOrThrow(".total_pages").text().toInt()
val rawUrl = chapter.url.replace("/1/", "/")
return (1..totalPages).map {
val url = "$rawUrl$it/"
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
override suspend fun getPageUrl(page: MangaPage): String {
val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.body()
return root.requireElementById("gimg").attrAsAbsoluteUrl("data-src")
}
}

@ -0,0 +1,180 @@
package org.koitharu.kotatsu.parsers.site.all
import androidx.collection.ArraySet
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@MangaSourceParser("IMHENTAI", "ImHentai", type = ContentType.HENTAI)
internal class ImHentai(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.IMHENTAI, pageSize = 20) {
override val sortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING)
override val configKeyDomain = ConfigKey.Domain("imhentai.xxx")
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
if (!query.isNullOrEmpty()) {
append("/search/?key=")
append(query.urlEncoded())
append("&page=")
append(page)
} else if (!tags.isNullOrEmpty()) {
append("/tag/")
append(tag?.key.orEmpty())
append("/")
when (sortOrder) {
SortOrder.UPDATED -> append("")
SortOrder.POPULARITY -> append("popular/")
else -> append("")
}
append("?page=")
append(page)
} else {
append("/search/?page=")
append(page)
when (sortOrder) {
SortOrder.UPDATED -> append("&lt=1&pp=0")
SortOrder.POPULARITY -> append("&lt=0&pp=1")
SortOrder.RATING -> append("&lt=0&pp=0")
else -> append("&lt=1&pp=0")
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.galleries div.thumb").map { div ->
val a = div.selectFirstOrThrow(".inner_thumb a")
val href = a.attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img")?.src().orEmpty(),
title = div.selectFirst(".caption")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = isNsfwSource,
)
}
}
//Tags are deliberately reduced because there are too many and this slows down the application.
//only the most popular ones are taken.
override suspend fun getTags(): Set<MangaTag> {
return coroutineScope {
(1..3).map { page ->
async { getTags(page) }
}
}.awaitAll().flattenTo(ArraySet(360))
}
private suspend fun getTags(page: Int): Set<MangaTag> {
val url = "https://$domain/tags/popular/?page=$page"
val root = webClient.httpGet(url).parseHtml()
return root.parseTags()
}
private fun Element.parseTags() = select("div.stags a.tag_btn").mapToSet {
val href = it.attr("href").substringAfterLast("tag/").substringBeforeLast('/')
MangaTag(
key = href,
title = it.selectFirstOrThrow("h3.list_tag").text(),
source = source,
)
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
manga.copy(
tags = doc.body().select("li:contains(Tags) a.tag").mapNotNullToSet {
val href = it.attr("href").substringAfterLast("tag/").substringBeforeLast('/')
val name = it.html().substringBeforeLast("<span")
MangaTag(
key = href,
title = name,
source = source,
)
},
author = doc.selectFirst("li:contains(Artists) a.tag")?.html()?.substringBefore("<span"),
chapters = listOf(
MangaChapter(
id = manga.id,
name = manga.title,
number = 1,
url = manga.url,
scanlator = null,
uploadDate = 0,
branch = doc.selectFirst("li:contains(Language) a.tag")?.html()?.substringBeforeLast("<span"),
source = source,
),
),
)
}
override suspend fun getRelatedManga(seed: Manga): List<Manga> {
val doc = webClient.httpGet(seed.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.body().selectFirstOrThrow("div.related")
return root.select("div.thumb").mapNotNull { div ->
val a = div.selectFirstOrThrow(".inner_thumb a")
val href = a.attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img")?.src().orEmpty(),
title = div.selectFirst(".caption")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = false,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val totalPages = doc.selectFirstOrThrow(".pages").text().replace("Pages: ", "").toInt() + 1
val domainImg = doc.requireElementById("append_thumbs").selectFirstOrThrow("img").src()?.replace("1t.jpg", "")
val pages = ArrayList<MangaPage>(totalPages)
for (i in 1 until totalPages) {
val url = "$domainImg$i.jpg"
pages.add(
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
),
)
}
return pages
}
}

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

@ -114,7 +114,7 @@ internal abstract class AnimeBootstrapParser(
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chaptersDeferred = async { getChapters(manga, doc) }
val chaptersDeferred = async { getChapters(doc) }
val desc = doc.selectFirstOrThrow(selectDesc).html()
@ -141,7 +141,7 @@ internal abstract class AnimeBootstrapParser(
protected open val selectChapter = "div.anime__details__episodes a"
protected open suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
protected open suspend fun getChapters(doc: Document): List<MangaChapter> {
return doc.body().select(selectChapter).mapChapters(reversed = true) { i, a ->
val href = a.attr("href")
MangaChapter(

@ -102,7 +102,7 @@ internal class PapScan(context: MangaLoaderContext) :
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chaptersDeferred = async { getChapters(manga, doc) }
val chaptersDeferred = async { getChapters(doc) }
val desc = doc.selectFirstOrThrow(selectDesc).html()
@ -126,7 +126,7 @@ internal class PapScan(context: MangaLoaderContext) :
)
}
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
override suspend fun getChapters(doc: Document): List<MangaChapter> {
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return doc.body().select(selectChapter).mapChapters(reversed = true) { i, li ->
val href = li.selectFirstOrThrow("a").attr("href")

@ -0,0 +1,167 @@
package org.koitharu.kotatsu.parsers.site.ar
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.json.JSONArray
import org.json.JSONObject
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("FLIXSCANS", "Flix Scans", "ar")
internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.FLIXSCANS, 18) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("flixscans.com")
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val json = if (!query.isNullOrEmpty()) {
if (page > 1) {
return emptyList()
}
val url = "https://api.$domain/api/v1/search/serie"
val body = JSONObject()
body.put("title", query.urlEncoded())
webClient.httpPost(url, body).parseJson().getJSONArray("data")
} else if (!tags.isNullOrEmpty()) {
if (page > 1) {
return emptyList()
}
val tagQuery = tags.joinToString(separator = ",") { it.key }
val url = "https://api.$domain/api/v1/search/advance?=&genres=$tagQuery&serie_type=webtoon"
webClient.httpGet(url).parseJson().getJSONArray("data")
} else {
val url = "https://api.$domain/api/v1/webtoon/homepage/latest/home?page=$page"
webClient.httpGet(url).parseJson().getJSONArray("data")
}
return json.mapJSON { j ->
val href = "https://$domain/series/${j.getString("prefix")}-${j.getString("id")}-${j.getString("slug")}"
val cover = "https://api.$domain/storage/" + j.getString("thumbnail")
Manga(
id = generateUid(href),
title = j.getString("title"),
altTitle = null,
url = href,
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = cover,
tags = emptySet(),
state = when (j.getString("status")) {
"ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED
else -> null
},
author = null,
source = source,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/search/advance").parseHtml()
val json = JSONArray(doc.requireElementById("__NUXT_DATA__").data())
val tagsList = json.getJSONArray(3).toString().replace("[", "").replace("]", "").split(",")
return tagsList.mapNotNullToSet { idTag ->
val id = idTag.toInt()
val idKey = json.getJSONObject(id).getInt("id")
val key = json.get(idKey).toString()
val idName = json.getJSONObject(id).getInt("name")
val name = json.get(idName).toString()
MangaTag(
key = key,
title = name,
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val chaptersDeferred = async { loadChapters(manga.url) }
val json = JSONArray(doc.requireElementById("__NUXT_DATA__").data())
val descId = json.getJSONObject(6).getInt("story")
val desc = json.getString(descId)
val tagsId = json.getJSONObject(6).getInt("genres")
val tagsList = json.getJSONArray(tagsId).toString().replace("[", "").replace("]", "").split(",")
val ratingId = json.getJSONObject(6).getInt("rating")
val rating = json.getString(ratingId)
val nsfwId = json.getJSONObject(6).getInt("nsfw")
val nsfw = json.getBoolean(nsfwId)
manga.copy(
description = desc,
tags = tagsList.mapToSet { idTag ->
val id = idTag.toInt()
val idKey = json.getJSONObject(id).getInt("id")
val key = json.get(idKey).toString()
val idName = json.getJSONObject(id).getInt("name")
val name = json.get(idName).toString()
MangaTag(
key = key,
title = name,
source = source,
)
},
rating = rating?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
isNsfw = nsfw,
chapters = chaptersDeferred.await(),
)
}
private val dateFormat = SimpleDateFormat("yyyy-MM-dd", sourceLocale)
private suspend fun loadChapters(baseUrl: String): List<MangaChapter> {
val key = baseUrl.substringAfter("-").substringBefore("-")
val seriesKey = baseUrl.substringAfterLast("/").substringBefore("-")
val json = JSONArray(webClient.httpGet("https://api.$domain/api/v1/webtoon/chapters/$key-desc").parseRaw())
return json.mapJSONIndexed { i, j ->
val url = "https://$domain/read/webtoon/$seriesKey-${j.getString("id")}-${j.getString("slug")}"
val date = j.getString("createdAt").substringBeforeLast("T")
MangaChapter(
id = generateUid(url),
url = url,
name = j.getString("slug").replace('-', ' '),
number = i + 1,
branch = null,
uploadDate = dateFormat.tryParse(date),
scanlator = null,
source = source,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val json = JSONArray(doc.requireElementById("__NUXT_DATA__").data())
val chapterData = json.getJSONObject(6).getInt("chapterData")
val pageLocate = json.getJSONObject(chapterData).getInt("webtoon")
val jsonPages = json.getJSONArray(pageLocate)
val pages = ArrayList<MangaPage>(jsonPages.length())
for (i in 0 until jsonPages.length()) {
val id = jsonPages.getInt(i)
val url = "https://api.$domain/storage/" + json.getString(id)
pages.add(
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
)
}
return pages
}
}

@ -0,0 +1,120 @@
package org.koitharu.kotatsu.parsers.site.ar
import okhttp3.Headers
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@MangaSourceParser("MANGASTORM", "Manga Storm", "ar")
internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGASTORM, 30) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY)
override val configKeyDomain = ConfigKey.Domain("mangastorm.org")
override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP)
.build()
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url =
if (!tags.isNullOrEmpty()) {
buildString {
append("https://")
append(domain)
append("/categories/")
append(tag?.key.orEmpty())
append("?page=")
append(page)
}
} else {
buildString {
append("https://")
append(domain)
append("/mangas?page=")
append(page)
if (!query.isNullOrEmpty()) {
append("&query=")
append(query.urlEncoded())
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.row div.col").map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
title = div.select(".manga-ct-title").text(),
altTitle = null,
url = href,
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirstOrThrow("img").src().orEmpty(),
tags = emptySet(),
state = null,
author = null,
source = source,
)
}
}
override suspend fun getTags(): Set<MangaTag> = emptySet()
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.selectFirstOrThrow(".card-body .col-lg-9")
return manga.copy(
altTitle = null,
state = null,
tags = root.select(".flex-wrap a").mapNotNullToSet { a ->
MangaTag(
key = a.attr("href").substringAfterLast('/'),
title = a.text(),
source = source,
)
},
author = null,
description = root.selectFirstOrThrow(".card-text").text(),
chapters = doc.select(".card-body a.btn-fixed-width").mapChapters(reversed = true) { i, a ->
val url = a.attrAsRelativeUrl("href")
MangaChapter(
id = generateUid(url),
name = a.text(),
number = i + 1,
url = url,
scanlator = null,
uploadDate = 0,
branch = null,
source = source,
)
},
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml().requireElementById("content")
return doc.select("div.text-center .img-fluid").map { img ->
val url = img.src()?.toRelativeUrl(domain) ?: img.parseFailed("Image src not found")
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
}

@ -17,7 +17,7 @@ import java.util.*
internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.TEAMXNOVEL, 10) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
override val configKeyDomain = ConfigKey.Domain("team1x12.com")
override val configKeyDomain = ConfigKey.Domain("team11x11.com")
override suspend fun getListPage(
page: Int,
@ -26,9 +26,9 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://$domain")
append("https://")
append(domain)
if (!tags.isNullOrEmpty()) {
append("/series?genre=")
append(tag?.key.orEmpty())
@ -57,7 +57,6 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.listupd .bs .bsx").ifEmpty {
doc.select("div.post-body .box")
}.map { div ->
@ -97,7 +96,6 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val mangaUrl = manga.url.toAbsoluteUrl(domain)
val maxPageChapterSelect = doc.select(".pagination .page-item a")
var maxPageChapter = 1
if (!maxPageChapterSelect.isNullOrEmpty()) {
@ -108,7 +106,6 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
}
}
}
return manga.copy(
altTitle = null,
state = when (doc.selectFirstOrThrow(".full-list-info:contains(الحالة:) a").text()) {

@ -9,7 +9,7 @@ import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@MangaSourceParser("CLONEMANGA", "CloneManga", "en")
@MangaSourceParser("CLONEMANGA", "Clone Manga", "en")
internal class CloneMangaParser(context: MangaLoaderContext) : MangaParser(context, MangaSource.CLONEMANGA) {
override val sortOrders: Set<SortOrder> = Collections.singleton(

@ -11,7 +11,7 @@ import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("COMICEXTRA", "ComicExtra", "en")
@MangaSourceParser("COMICEXTRA", "Comic Extra", "en")
internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.COMICEXTRA, 25) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST)

@ -0,0 +1,146 @@
package org.koitharu.kotatsu.parsers.site.en
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet
import java.util.*
@MangaSourceParser("FAKKU", "Fakku", "en", ContentType.HENTAI)
internal class Fakku(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.FAKKU, pageSize = 25) {
override val sortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.NEWEST, SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("fakku.cc")
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
when {
!query.isNullOrEmpty() -> {
append("/search?q=")
append(query.urlEncoded())
append("&")
}
!tags.isNullOrEmpty() -> {
append("/tags/")
append(tag?.key.orEmpty())
append("?")
}
else -> {
append("?")
}
}
append("page=")
append(page)
append("&sort=")
when (sortOrder) {
SortOrder.ALPHABETICAL -> append("title")
SortOrder.NEWEST -> append("created_at")
SortOrder.UPDATED -> append("published_at")
else -> append("published_at")
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.entries .entry a").map { a ->
val href = a.attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img")?.src().orEmpty(),
title = a.selectFirst(".title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = isNsfwSource,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
val root = webClient.httpGet("https://$domain/tags").parseHtml()
return root.select("div.entries .entry a").mapToSet {
MangaTag(
key = it.attr("href").substringAfterLast("/"),
title = it.selectFirstOrThrow(".name").text(),
source = source,
)
}
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val genreDeferred = async {
webClient.httpGet(manga.url.toAbsoluteUrl(domain) + ".json").parseJson()
}
val genre = genreDeferred.await()
manga.copy(
author = doc.selectFirst("tr.artists a")?.text(),
tags = if (genre.toString().contains("tags")) {
genre.getJSONArray("tags").mapJSONToSet {
MangaTag(
key = it.getString("slug"),
title = it.getString("name"),
source = source,
)
}
} else {
emptySet()
},
chapters = listOf(
MangaChapter(
id = manga.id,
name = manga.title,
number = 1,
url = manga.url + "/1",
scanlator = null,
uploadDate = 0,
branch = null,
source = source,
),
),
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml()
val totalPages = doc.selectFirstOrThrow(".total").text().toInt()
val rawUrl = chapter.url.substringBeforeLast("/")
return (1..totalPages).map {
val url = "$rawUrl/$it"
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
override suspend fun getPageUrl(page: MangaPage): String {
val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.body()
return root.selectFirstOrThrow(".page img").attrAsAbsoluteUrl("src")
}
}

@ -14,7 +14,7 @@ import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("LIKEMANGA", "LikeManga", "en")
@MangaSourceParser("LIKEMANGA", "Like Manga", "en")
internal class LikeManga(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LIKEMANGA, 36) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST)

@ -14,7 +14,7 @@ import org.koitharu.kotatsu.parsers.util.json.mapJSON
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("MANGAOWL", "Mangaowl", "en")
@MangaSourceParser("MANGAOWL", "Manga Owl .To", "en")
internal class Mangaowl(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.MANGAOWL, pageSize = 24) {

@ -9,7 +9,7 @@ import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@MangaSourceParser("MANHWA18", "Manhwa18", "en", type = ContentType.HENTAI)
@MangaSourceParser("MANHWA18", "Manhwa 18", "en", type = ContentType.HENTAI)
class Manhwa18Parser(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.MANHWA18, pageSize = 18, searchPageSize = 18) {

@ -0,0 +1,168 @@
package org.koitharu.kotatsu.parsers.site.en
import androidx.collection.ArraySet
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@MangaSourceParser("PURURIN", "Pururin", "en", ContentType.HENTAI)
internal class Pururin(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.PURURIN, pageSize = 20) {
override val sortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING, SortOrder.ALPHABETICAL)
override val configKeyDomain = ConfigKey.Domain("pururin.to")
override suspend fun getListPage(
page: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val tag = tags.oneOrThrowIfMany()
val url = buildString {
append("https://")
append(domain)
if (!query.isNullOrEmpty()) {
append("/search?q=")
append(query.urlEncoded())
append("&page=")
append(page)
} else {
append("/browse")
if (!tags.isNullOrEmpty()) {
append("/tags/content/")
append(tag?.key.orEmpty())
append("/")
}
append("?page=")
append(page)
append("&sort=")
when (sortOrder) {
SortOrder.UPDATED -> append("")
SortOrder.POPULARITY -> append("most-viewed")
SortOrder.RATING -> append("highest-rated")
SortOrder.ALPHABETICAL -> append("title")
else -> append("")
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select(".row-gallery a.card-gallery").map { a ->
val href = a.attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img.card-img-top")?.src().orEmpty(),
title = a.selectFirst(".title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = isNsfwSource,
)
}
}
override suspend fun getTags(): Set<MangaTag> {
return coroutineScope {
(1..4).map { page ->
async { getTags(page) }
}
}.awaitAll().flattenTo(ArraySet(360))
}
private suspend fun getTags(page: Int): Set<MangaTag> {
val url = "https://$domain/tags/content?order=uses&page=$page"
val root = webClient.httpGet(url).parseHtml()
return root.parseTags()
}
private fun Element.parseTags() = select("table tr td a").mapToSet {
val href = it.attr("href").substringAfterLast("content/").substringBeforeLast('/')
MangaTag(
key = href,
title = it.text(),
source = source,
)
}
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
manga.copy(
description = doc.selectFirst("p.mb-2")?.text().orEmpty(),
rating = doc.selectFirst("td span.rating")?.attr("content")?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
tags = doc.body().select("tr:contains(Contents) ul.list-inline a").mapNotNullToSet {
val href = it.attr("href").substringAfterLast("content/").substringBeforeLast('/')
MangaTag(
key = href,
title = it.text(),
source = source,
)
},
author = doc.selectFirst("a[itemprop=author]")?.text(),
chapters = listOf(
MangaChapter(
id = manga.id,
name = manga.title,
number = 1,
url = manga.url,
scanlator = null,
uploadDate = 0,
branch = null,
source = source,
),
),
)
}
override suspend fun getRelatedManga(seed: Manga): List<Manga> {
val doc = webClient.httpGet(seed.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.body().selectFirstOrThrow(".row-gallery-small")
return root.select("a.card-gallery").mapNotNull { a ->
val href = a.attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img.card-img-top")?.src().orEmpty(),
title = a.selectFirst(".title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = false,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
return doc.select(".gallery-preview img").map { url ->
val img = url.src()?.toRelativeUrl(domain) ?: url.parseFailed("Image src not found")
val urlImage = img.replace("t.", ".")
MangaPage(
id = generateUid(urlImage),
url = urlImage,
preview = null,
source = source,
)
}
}
}

@ -99,12 +99,12 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
state = parseStatus(contents.select("span.book-status").text().orEmpty()),
author = contents.selectFirst("h5.card-title")?.attr("title")?.substringAfter(", "),
chapters = if (doc.select("div.chapters").isEmpty()) {
doc.select(oneShotChapterListSelector()).mapChapters(reversed = true) { _, item ->
doc.select(oneShotChapterListSelector).mapChapters(reversed = true) { _, item ->
oneShotChapterFromElement(item)
}
} else {
val chapters = ChaptersListBuilder(10)
doc.select(regularChapterListSelector()).reversed().forEachIndexed { i, item ->
doc.select(regularChapterListSelector).reversed().forEachIndexed { i, item ->
val chaptername = item.select("div.col-10.text-truncate").text().replace("&nbsp;", " ").trim()
val scanelement = item.select("ul.chapter-list > li")
scanelement.forEach { chapters.add(regularChapterFromElement(it, chaptername, i)) }
@ -114,7 +114,7 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
)
}
private fun oneShotChapterListSelector() = "div.chapter-list-element > ul.list-group li.list-group-item"
private val oneShotChapterListSelector = "div.chapter-list-element > ul.list-group li.list-group-item"
private fun oneShotChapterFromElement(element: Element): MangaChapter {
val href = element.selectFirstOrThrow("div.row > .text-right > a").attrAsRelativeUrl("href")
@ -130,7 +130,7 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
)
}
private fun regularChapterListSelector() = "div.chapters > ul.list-group li.p-0.list-group-item"
private val regularChapterListSelector = "div.chapters > ul.list-group li.p-0.list-group-item"
private fun regularChapterFromElement(element: Element, chName: String, number: Int): MangaChapter {
val href = element.selectFirstOrThrow("div.row > .text-right > a").attrAsRelativeUrl("href")

@ -27,7 +27,7 @@ internal abstract class FmreaderParser(
SortOrder.ALPHABETICAL,
)
protected open val listeurl = "/manga-list.html"
protected open val listUrl = "/manga-list.html"
protected open val datePattern = "MMMM d, yyyy"
protected open val tagPrefix = "manga-list-genre-"
@ -66,7 +66,7 @@ internal abstract class FmreaderParser(
val url = buildString {
append("https://")
append(domain)
append(listeurl)
append(listUrl)
append("?page=")
append(page.toString())
when {
@ -114,7 +114,7 @@ internal abstract class FmreaderParser(
protected open val selectBodyTag = "ul.filter-type li a"
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listeurl").parseHtml()
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfter(tagPrefix).substringBeforeLast(".html")
MangaTag(
@ -134,7 +134,7 @@ internal abstract class FmreaderParser(
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chaptersDeferred = async { getChapters(manga, doc) }
val chaptersDeferred = async { getChapters(doc) }
val desc = doc.selectFirstOrThrow(selectDesc).html()
val stateDiv = doc.selectFirst(selectState)
val state = stateDiv?.let {
@ -145,7 +145,6 @@ internal abstract class FmreaderParser(
else -> null
}
}
val alt = doc.body().selectFirst(selectAlt)?.text()?.replace("Other names", "")
val auth = doc.body().selectFirst(selectAut)?.text()
manga.copy(
@ -168,7 +167,7 @@ internal abstract class FmreaderParser(
protected open val selectDate = "div.chapter-time"
protected open val selectChapter = "ul.list-chapters a"
protected open suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
protected open suspend fun getChapters(doc: Document): List<MangaChapter> {
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return doc.body().select(selectChapter).mapChapters(reversed = true) { i, a ->
val href = a.attrAsRelativeUrl("href")
@ -194,10 +193,8 @@ internal abstract class FmreaderParser(
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
return doc.select(selectPage).map { img ->
val url = img.src()?.toRelativeUrl(domain) ?: img.parseFailed("Image src not found")
MangaPage(
id = generateUid(url),
url = url,

@ -10,11 +10,11 @@ import org.koitharu.kotatsu.parsers.site.fmreader.FmreaderParser
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
@MangaSourceParser("MANHWA18COM", "Manhwa18 .Com", "en", ContentType.HENTAI)
@MangaSourceParser("MANHWA18COM", "Manhwa 18 .Com", "en", ContentType.HENTAI)
internal class Manhwa18Com(context: MangaLoaderContext) :
FmreaderParser(context, MangaSource.MANHWA18COM, "manhwa18.com") {
override val listeurl = "/tim-kiem"
override val listUrl = "/tim-kiem"
override val selectState = "div.info-item:contains(Status) span.info-value "
override val selectAlt = "div.info-item:contains(Other name) span.info-value "
override val selectTag = "div.info-item:contains(Genre) span.info-value a"
@ -45,7 +45,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
else -> append("last_update")
}
} else {
append(listeurl)
append(listUrl)
append("?page=")
append(page.toString())
when {
@ -87,7 +87,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
}
override suspend fun getTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listeurl").parseHtml()
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("/")
MangaTag(
@ -101,7 +101,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chaptersDeferred = async { getChapters(manga, doc) }
val chaptersDeferred = async { getChapters(doc) }
val desc = doc.selectFirstOrThrow(selectDesc).html()
val stateDiv = doc.selectFirst(selectState)
val state = stateDiv?.let {
@ -129,7 +129,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
)
}
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
override suspend fun getChapters(doc: Document): List<MangaChapter> {
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return doc.body().select(selectChapter).mapChapters(reversed = true) { i, a ->
val href = a.attrAsRelativeUrl("href")

@ -25,7 +25,7 @@ internal class OlimpoScans(context: MangaLoaderContext) :
val url = buildString {
append("https://")
append(domain)
append(listeurl)
append(listUrl)
append("?page=")
append(page.toString())
when {

@ -37,7 +37,7 @@ internal class Klz9(context: MangaLoaderContext) :
val url = buildString {
append("https://")
append(domain)
append("/$listeurl")
append("/$listUrl")
append("?page=")
append(page.toString())
when {
@ -81,12 +81,12 @@ internal class Klz9(context: MangaLoaderContext) :
}
}
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
override suspend fun getChapters(doc: Document): List<MangaChapter> {
val slug = doc.selectFirstOrThrow("div.h0rating").attr("slug")
val docload =
val docLoad =
webClient.httpGet("https://$domain/app/manga/controllers/cont.listChapter.php?slug=$slug").parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return docload.body().select(selectChapter).mapChapters(reversed = true) { i, a ->
return docLoad.body().select(selectChapter).mapChapters(reversed = true) { i, a ->
val href = "/" + a.selectFirstOrThrow("a.chapter").attrAsRelativeUrl("href")
val dateText = a.selectFirst(selectDate)?.text()
MangaChapter(
@ -109,8 +109,8 @@ internal class Klz9(context: MangaLoaderContext) :
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val cid = doc.selectFirstOrThrow("#chapter").attr("value")
val docload = webClient.httpGet("https://$domain/app/manga/controllers/cont.listImg.php?cid=$cid").parseHtml()
return docload.select(selectPage).map { img ->
val docLoad = webClient.httpGet("https://$domain/app/manga/controllers/cont.listImg.php?cid=$cid").parseHtml()
return docLoad.select(selectPage).map { img ->
val url = img.src()?.toRelativeUrl(domain) ?: img.parseFailed("Image src not found")
MangaPage(

@ -3,7 +3,6 @@ package org.koitharu.kotatsu.parsers.site.fmreader.ja
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
@ -11,16 +10,16 @@ import org.koitharu.kotatsu.parsers.site.fmreader.FmreaderParser
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
@MangaSourceParser("WELOVEMANGA", "WeLoveManga", "ja")
@MangaSourceParser("WELOVEMANGA", "We Love Manga", "ja")
internal class WeLoveManga(context: MangaLoaderContext) :
FmreaderParser(context, MangaSource.WELOVEMANGA, "welovemanga.one") {
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
override suspend fun getChapters(doc: Document): List<MangaChapter> {
val mid = doc.selectFirstOrThrow("div.cmt input").attr("value")
val docload =
val docLoad =
webClient.httpGet("https://$domain/app/manga/controllers/cont.Listchapter.php?mid=$mid").parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return docload.body().select(selectChapter).mapChapters(reversed = true) { i, a ->
return docLoad.body().select(selectChapter).mapChapters(reversed = true) { i, a ->
val href = a.selectFirstOrThrow("a").attrAsRelativeUrl("href")
val dateText = a.selectFirst(selectDate)?.text()
MangaChapter(
@ -43,8 +42,8 @@ internal class WeLoveManga(context: MangaLoaderContext) :
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val cid = doc.selectFirstOrThrow("#chapter").attr("value")
val docload = webClient.httpGet("https://$domain/app/manga/controllers/cont.listImg.php?cid=$cid").parseHtml()
return docload.select("img").map { img ->
val docLoad = webClient.httpGet("https://$domain/app/manga/controllers/cont.listImg.php?cid=$cid").parseHtml()
return docLoad.select("img").map { img ->
val url = img.src()?.toRelativeUrl(domain) ?: img.parseFailed("Image src not found")
MangaPage(

@ -38,7 +38,6 @@ internal abstract class FoolSlideParser(
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
val doc = if (!query.isNullOrEmpty()) {
val url = buildString {
append("https://$domain/$searchUrl")
@ -62,7 +61,6 @@ internal abstract class FoolSlideParser(
}
webClient.httpGet(url).parseHtml()
}
return doc.select("div.list div.group").map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
Manga(
@ -90,26 +88,22 @@ internal abstract class FoolSlideParser(
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val testAdultPage = webClient.httpGet(fullUrl).parseHtml()
val doc = if (testAdultPage.selectFirst("div.info form") != null) {
webClient.httpPost(fullUrl, "adult=true").parseHtml()
} else {
testAdultPage
}
val chapters = getChapters(manga, doc)
val chapters = getChapters(doc)
val desc = if (doc.selectFirstOrThrow(selectInfo).html().contains("</b>")) {
doc.selectFirstOrThrow(selectInfo).text().substringAfterLast(": ")
} else {
doc.selectFirstOrThrow(selectInfo).text()
}
val author = if (doc.selectFirstOrThrow(selectInfo).html().contains("</b>")) {
doc.selectFirstOrThrow(selectInfo).text().substringAfter(": ").substringBefore("Art")
} else {
null
}
manga.copy(
coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl,
description = desc,
@ -124,7 +118,7 @@ internal abstract class FoolSlideParser(
protected open val selectDate = ".meta_r"
protected open val selectChapter = "div.list div.element"
protected open suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
protected open suspend fun getChapters(doc: Document): List<MangaChapter> {
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return doc.body().select(selectChapter).mapChapters(reversed = true) { i, div ->
val a = div.selectFirstOrThrow(".title a")

@ -77,7 +77,7 @@ internal class AssortedScans(context: MangaLoaderContext) :
} else {
testAdultPage
}
val chapters = getChapters(manga, doc)
val chapters = getChapters(doc)
val desc = doc.getElementById("series-desc")?.selectFirst("div")?.html()
val alt = doc.getElementById("series-aliases")?.selectFirst("div.alias")?.text()
val author = doc.getElementById("series-authors")?.selectFirst("div.author")?.text()
@ -97,7 +97,7 @@ internal class AssortedScans(context: MangaLoaderContext) :
)
}
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
override suspend fun getChapters(doc: Document): List<MangaChapter> {
return doc.body().select("div.chapter").mapChapters(reversed = true) { i, div ->
val a = div.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href")

@ -5,6 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.foolslide.FoolSlideParser
@MangaSourceParser("DEATHTOLLSCANS", "DeathToll Scans", "en")
@MangaSourceParser("DEATHTOLLSCANS", "Death Toll Scans", "en")
internal class Deathtollscans(context: MangaLoaderContext) :
FoolSlideParser(context, MangaSource.DEATHTOLLSCANS, "reader.deathtollscans.net", 26)

@ -21,7 +21,7 @@ internal class Seinagi(context: MangaLoaderContext) :
} else {
testAdultPage
}
val chapters = getChapters(manga, doc)
val chapters = getChapters(doc)
val desc = if (doc.selectFirstOrThrow(selectInfo).html().contains("Description")) {
doc.selectFirstOrThrow(selectInfo).text().substringAfter("Description: ").substringBefore("Readings")
} else {

@ -19,7 +19,7 @@ internal class Pzykosis666hFansub(context: MangaLoaderContext) :
} else {
testAdultPage
}
val chapters = getChapters(manga, doc)
val chapters = getChapters(doc)
val desc = if (doc.selectFirstOrThrow(selectInfo).html().contains("Descripción")) {
doc.selectFirstOrThrow(selectInfo).text().substringAfter("Descripción: ").substringBefore("Lecturas")
} else {

@ -25,7 +25,7 @@ internal class SeinagiAdulto(context: MangaLoaderContext) :
} else {
testAdultPage
}
val chapters = getChapters(manga, doc)
val chapters = getChapters(doc)
val desc = if (doc.selectFirstOrThrow(selectInfo).html().contains("Descripción")) {
doc.selectFirstOrThrow(selectInfo).text().substringAfter("Descripción: ").substringBefore("Lecturas")
} else {

@ -15,7 +15,7 @@ import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.getIntOrDefault
import java.util.*
@MangaSourceParser("BENTOMANGA", "BentoManga", "fr")
@MangaSourceParser("BENTOMANGA", "Bento Manga", "fr")
internal class BentomangaParser(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.BENTOMANGA, 10) {
override val sortOrders: Set<SortOrder> = EnumSet.of(

@ -9,6 +9,7 @@ import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import java.lang.IllegalArgumentException
import java.text.SimpleDateFormat
import java.util.*
@ -48,20 +49,19 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
tags: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
if (!query.isNullOrEmpty()) {
throw IllegalArgumentException("Search is not supported by this source")
}
if (sortOrder == SortOrder.ALPHABETICAL) {
if (page > 1) {
return emptyList()
}
val url = buildString {
append("https://")
append(domain)
append("/api/get/catalog?page=0&filter=all")
}
val json = webClient.httpGet(url).parseJsonArray()
return json.mapJSON { j ->
val urlManga = "https://$domain/api/get/card/${j.getString("slug")}"
val img = "https://$domain/upload/min_cover/${j.getString("image")}"
@ -93,7 +93,6 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
append(page)
}
val json = webClient.httpGet(url).parseJsonArray()
return json.mapJSON { j ->
val urlManga = "https://$domain/api/get/card/${j.getString("manga_slug")}"
val img = "https://$domain/upload/min_cover/${j.getString("manga_image")}"
@ -119,10 +118,8 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
override suspend fun getDetails(manga: Manga): Manga {
val json = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseJson()
val jsonManga = json.getJSONObject("manga")
val chapters = json.getJSONObject("chapters").toString().split("{\"id\":").drop(1) // Possible improvement here
val chapters = json.getJSONObject("chapters").toString().split("{\"id\":").drop(1)
val slug = manga.url.substringAfterLast("/")
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.FRANCE)
return manga.copy(
@ -140,8 +137,7 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
val url = "https://$domain/api/get/chapter/$slug/$id"
val date = getDateString(
it.substringAfter("\"date\":\"").substringBefore("\",").toLong(),
) // Possible improvement here
)
MangaChapter(
id = generateUid(url),
name = "Chapitre : $id",
@ -159,27 +155,25 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
private val simpleDateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.FRANCE)
private fun getDateString(time: Long): String = simpleDateFormat.format(time * 1000L)
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val jsonPage = webClient.httpGet(fullUrl).parseJson()
val idManga = jsonPage.getJSONObject("manga").getString("id")
val slugChapter = chapter.url.substringAfterLast("/")
val pages = jsonPage.getJSONObject("chapter").getJSONArray("files").toString()
.replace("[", "").replace("]", "").replace("\"", "")
.split(",") // Possible improvement here
return pages.map { img ->
val url = "https://$domain/upload/chapitre/$idManga/$slugChapter/$img"
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
val idManga = jsonPage.getJSONObject("manga").getInt("id")
val slug = jsonPage.getJSONObject("chapter").getInt("chapter")
val jsonPages = jsonPage.getJSONObject("chapter").getJSONArray("files")
val pages = ArrayList<MangaPage>(jsonPages.length())
for (i in 0 until jsonPages.length()) {
val url = "https://$domain/upload/chapters/$idManga/$slug/${jsonPages.getString(i)}"
pages.add(
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
),
)
}
return pages
}
override suspend fun getTags(): Set<MangaTag> = emptySet()

@ -167,7 +167,6 @@ internal class ScansMangasMe(context: MangaLoaderContext) :
val pages = ArrayList<MangaPage>(images.length())
for (i in 0 until images.length()) {
val pageTake = images.getJSONObject(i)
pages.add(
MangaPage(

@ -5,6 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.heancmsalt.HeanCmsAlt
@MangaSourceParser("LEGIONSCANS", "CerberuSeries", "es")
@MangaSourceParser("LEGIONSCANS", "Cerberus Series", "es")
internal class CerberuSeries(context: MangaLoaderContext) :
HeanCmsAlt(context, MangaSource.LEGIONSCANS, "cerberuseries.xyz")

@ -9,7 +9,7 @@ import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("DOUJINDESU", "DoujinDesu", "id")
@MangaSourceParser("DOUJINDESU", "Doujin Desu", "id")
class DoujinDesuParser(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.DOUJINDESU, pageSize = 18) {
override val configKeyDomain: ConfigKey.Domain

@ -12,7 +12,7 @@ import java.util.*
private const val STATUS_ONGOING = "連載"
private const val STATUS_FINISHED = "完結"
@MangaSourceParser("NICOVIDEO_SEIGA", "NicoVideo Seiga", "ja")
@MangaSourceParser("NICOVIDEO_SEIGA", "Nico Video Seiga", "ja")
class NicovideoSeigaParser(context: MangaLoaderContext) :
MangaParser(context, MangaSource.NICOVIDEO_SEIGA),
MangaParserAuthProvider {

@ -33,9 +33,8 @@ internal abstract class MadaraParser(
protected open val tagPrefix = "manga-genre/"
protected open val datePattern = "MMMM d, yyyy"
protected open val stylepage = "?style=list"
protected open val postreq = false
protected open val stylePage = "?style=list"
protected open val postReq = false
init {
paginator.firstPage = 0
@ -52,7 +51,6 @@ internal abstract class MadaraParser(
parseFailed("Cannot find tableValue for node ${text()}")
}
@JvmField
protected val ongoing: Set<String> = hashSetOf(
"مستمرة",
@ -358,7 +356,7 @@ internal abstract class MadaraParser(
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
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(
@ -378,8 +376,7 @@ internal abstract class MadaraParser(
}
protected open suspend fun loadChapters(mangaUrl: String, document: Document): List<MangaChapter> {
val doc = if (postreq) {
val doc = if (postReq) {
val mangaId = document.select("div#manga-chapters-holder").attr("data-id")
val url = "https://$domain/wp-admin/admin-ajax.php"
val postdata = "action=manga_get_chapters&manga=$mangaId"
@ -388,13 +385,11 @@ internal abstract class MadaraParser(
val url = mangaUrl.toAbsoluteUrl(domain).removeSuffix('/') + "/ajax/chapters/"
webClient.httpPost(url, emptyMap()).parseHtml()
}
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return doc.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 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(
@ -413,13 +408,35 @@ internal abstract class MadaraParser(
}
}
override suspend fun getRelatedManga(seed: Manga): List<Manga> {
val doc = webClient.httpGet(seed.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.body().selectFirstOrThrow(".related-manga")
return root.select("div.related-reading-wrap").mapNotNull { div ->
val a = div.selectFirst("a") ?: return@mapNotNull null
val href = a.attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(a.host ?: domain),
altTitle = null,
title = div.selectFirstOrThrow(".widget-title").text(),
author = null,
coverUrl = div.selectFirst("img")?.src().orEmpty(),
tags = emptySet(),
rating = RATING_UNKNOWN,
state = null,
isNsfw = isNsfwSource,
source = source,
)
}
}
protected open val selectBodyPage = "div.main-col-inner div.reading-content"
protected open val selectPage = "div.page-break, div.login-required"
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chapterProtector = doc.getElementById("chapter-protector-data")
if (chapterProtector == null) {
val root = doc.body().selectFirstOrThrow(selectBodyPage)

@ -21,7 +21,7 @@ internal class Ero18x(context: MangaLoaderContext) :
return doc.body().select(selectChapter).mapChapters(reversed = true) { i, li ->
val a = li.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href")
val link = href + stylepage
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(

@ -12,5 +12,5 @@ internal class MangaTop(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGATOP, "mangatop.site") {
override val datePattern = "d MMMM yyyy"
override val sourceLocale: Locale = Locale.ENGLISH
override val stylepage = ""
override val stylePage = ""
}

@ -13,13 +13,11 @@ import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.mapChapters
import org.koitharu.kotatsu.parsers.util.parseFailed
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("MANHWARAW", "Manhwa Raw", "", ContentType.HENTAI)
internal class ManhwaRaw(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHWARAW, "manhwa-raw.com", 10) {
override val datePattern = "MMMM d"
override val sourceLocale: Locale = Locale.ENGLISH
override val datePattern = "MM/dd"
override val withoutAjax = true
override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
@ -27,10 +25,9 @@ internal class ManhwaRaw(context: MangaLoaderContext) :
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
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()
val name = a.selectFirst("h4")?.text() ?: a.ownText()
MangaChapter(
id = generateUid(href),
name = name,

@ -10,7 +10,7 @@ import java.util.Locale
@MangaSourceParser("MANYTOON_CLUB", "Many Toon .Club", "", ContentType.HENTAI)
internal class ManyToonClub(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANYTOON_CLUB, "manytoon.club") {
override val postreq = true
override val postReq = true
override val listUrl = "manhwa-raw/"
override val tagPrefix = "manhwa-raw-genre/"
override val sourceLocale: Locale = Locale.ENGLISH

@ -5,7 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("AZORANOV", "Azoranov", "ar")
@MangaSourceParser("AZORANOV", "Azora Nov", "ar")
internal class Azoranov(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.AZORANOV, "azoranov.com", pageSize = 10) {
override val tagPrefix = "series-genre/"

@ -8,7 +8,7 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("GATEMANGA", "Gate Manga", "ar")
internal class GateManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.GATEMANGA, "gatemanga.com") {
override val postreq = true
override val postReq = true
override val datePattern = "d MMMM، yyyy"
override val listUrl = "ar/"
override val withoutAjax = true

@ -6,8 +6,8 @@ import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGA_LEK", "Manga-Lek", "ar")
internal class Manga_Lek(context: MangaLoaderContext) :
internal class MangaLekCom(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGA_LEK, "manga-lek.com") {
override val listUrl = "mangalek/"
override val postreq = true
override val postReq = true
}

@ -9,5 +9,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
internal class MangaLeks(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGALEKS, "mangaleks.com") {
override val datePattern = "yyyy/MM/dd"
override val postreq = true
override val postReq = true
}

@ -7,4 +7,4 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGALIKE", "Manga Like", "ar")
internal class MangaLike(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGALIKE, "mangalike.me", pageSize = 10)
MadaraParser(context, MangaSource.MANGALIKE, "manga-like.net", pageSize = 10)

@ -0,0 +1,12 @@
package org.koitharu.kotatsu.parsers.site.madara.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGATIME", "Manga Time", "ar")
internal class MangaTime(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGATIME, "mangatime.co") {
override val datePattern = "d MMMM، yyyy"
}

@ -5,9 +5,9 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGARBIC", "Mangarbic", "ar")
@MangaSourceParser("MANGARBIC", "Manga Arabic", "ar")
internal class Mangarbic(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGARBIC, "mangarabic.com") {
override val postreq = true
override val postReq = true
override val datePattern = "yyyy/MM/dd"
}

@ -8,6 +8,6 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGASPARK", "Manga Spark", "ar")
internal class Mangaspark(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGASPARK, "mangaspark.org", pageSize = 10) {
override val postreq = true
override val postReq = true
override val datePattern = "d MMMM، yyyy"
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("NIJITRANSLATIONS", "Niji Translations", "ar")
internal class NijiTranslations(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.NIJITRANSLATIONS, "niji-translations.com") {
override val postreq = true
override val postReq = true
}

@ -5,6 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("PEWPIECE", "PewPiece", "ar")
@MangaSourceParser("PEWPIECE", "Pew Piece", "ar")
internal class PewPiece(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.PEWPIECE, "pewpiece.com")

@ -10,5 +10,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
internal class AdultWebtoon(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ADULT_WEBTOON, "adultwebtoon.com") {
override val tagPrefix = "adult-webtoon-genre/"
override val postreq = true
override val postReq = true
}

@ -9,5 +9,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
internal class Astrallibrary(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ASTRALLIBRARY, "astrallibrary.net", 18) {
override val datePattern = "dd MMM"
override val postreq = true
override val postReq = true
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("BLOG_MANGA", "Blog Manga", "en")
internal class BlogManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.BLOG_MANGA, "blogmanga.net") {
override val postreq = true
override val postReq = true
}

@ -11,5 +11,5 @@ internal class BoysLove(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.BOYS_LOVE, "boyslove.me", 20) {
override val tagPrefix = "boyslove-genre/"
override val listUrl = "boyslove/"
override val postreq = true
override val postReq = true
}

@ -110,7 +110,7 @@ internal class CoffeeMangaTop(context: MangaLoaderContext) :
return doc.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 link = href + stylePage
MangaChapter(
id = generateUid(href),
url = link,

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("CREEPYSCANS", "Creepy Scans", "en")
internal class CreepyScans(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.CREEPYSCANS, "creepyscans.com") {
override val stylepage = ""
override val stylePage = ""
}

@ -9,7 +9,7 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("FREECOMICONLINE", "Free Comic Online", "en", ContentType.HENTAI)
internal class FreeComicOnline(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.FREECOMICONLINE, "freecomiconline.me") {
override val postreq = true
override val postReq = true
override val listUrl = "comic/"
override val tagPrefix = "comic-genre/"
}

@ -5,7 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("GDSCANS", "GdScans", "en")
@MangaSourceParser("GDSCANS", "Gd Scans", "en")
internal class GdScans(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.GDSCANS, "gdscans.com", 10) {
override val tagPrefix = "webtoon-genre/"

@ -10,5 +10,5 @@ internal class GourmetScans(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.GOURMETSCANS, "gourmetscans.net") {
override val listUrl = "project/"
override val tagPrefix = "genre/"
override val stylepage = ""
override val stylePage = ""
}

@ -6,11 +6,11 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HMANHWA", "HManhwa", "en", ContentType.HENTAI)
@MangaSourceParser("HMANHWA", "H Manhwa", "en", ContentType.HENTAI)
internal class HManhwa(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HMANHWA, "hmanhwa.com") {
override val tagPrefix = "manhwa-genre/"
override val listUrl = "manhwa/"
override val datePattern = "dd MMM"
override val postreq = true
override val postReq = true
}

@ -5,7 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HSCANS", "HScans", "en")
@MangaSourceParser("HSCANS", "H Scans", "en")
internal class HScans(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HSCANS, "hscans.com", 10) {

@ -9,5 +9,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HENTAIMANGA", "Hentai Manga", "en", ContentType.HENTAI)
internal class HentaiManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAIMANGA, "hentaimanga.me", 36) {
override val postreq = true
override val postReq = true
}

@ -9,5 +9,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HENTAIWEBTOON", "Hentai Webtoon", "en", ContentType.HENTAI)
internal class HentaiWebtoon(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAIWEBTOON, "hentaiwebtoon.com") {
override val postreq = true
override val postReq = true
}

@ -9,5 +9,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HENTAIXCOMIC", "Hentai x Comic", "en", ContentType.HENTAI)
internal class HentaixComic(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAIXCOMIC, "hentaixcomic.com", 16) {
override val postreq = true
override val postReq = true
}

@ -9,5 +9,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("HENTAIXYURI", "Hentai x Yuri", "en", ContentType.HENTAI)
internal class HentaixYuri(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAIXYURI, "hentaixyuri.com", 16) {
override val postreq = true
override val postReq = true
}

@ -14,15 +14,15 @@ import java.text.SimpleDateFormat
@MangaSourceParser("HENTAIXDICKGIRL", "Hentai x Dickgirl", "en", ContentType.HENTAI)
internal class Hentaixdickgirl(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HENTAIXDICKGIRL, "hentaixdickgirl.com", 16) {
override val postReq = 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 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(

@ -14,7 +14,7 @@ internal class InstaManhwa(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.INSTAMANHWA, "www.instamanhwa.com", 15) {
override val tagPrefix = "genre/"
override val listUrl = "latest/"
override val postreq = true
override val postReq = true
override val datePattern = "d MMMM, yyyy"
override val sortOrders: Set<SortOrder> = EnumSet.of(
@ -113,7 +113,7 @@ internal class InstaManhwa(context: MangaLoaderContext) :
return doc.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 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(

@ -113,7 +113,7 @@ internal class IsekaiScan(context: MangaLoaderContext) :
return doc.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 link = href + stylePage
MangaChapter(
id = generateUid(href),
url = link,

@ -5,6 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("ITSYOURIGHTMANHUA", "Itsyourightmanhua", "en")
@MangaSourceParser("ITSYOURIGHTMANHUA", "Its You Right Manhua", "en")
internal class Itsyourightmanhua(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.ITSYOURIGHTMANHUA, "itsyourightmanhua.com", 10)

@ -5,6 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("JAIMINISBOX", "Jaiminisbox", "en")
@MangaSourceParser("JAIMINISBOX", "Jaiminis Box", "en")
internal class Jaiminisbox(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.JAIMINISBOX, "jaiminisbox.net")

@ -5,6 +5,6 @@ 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")
@MangaSourceParser("JIMANGA", "Ji Manga", "en")
internal class JiManga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.JIMANGA, "jimanga.com")

@ -9,6 +9,6 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("LOLICONMOBI", "Lolicon Mobi", "en", ContentType.HENTAI)
internal class LoliconMobi(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.LOLICONMOBI, "lolicon.mobi") {
override val postreq = true
override val postReq = true
override val tagPrefix = "lolicon-genre/"
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGABOB", "Manga Bob", "en")
internal class MangaBob(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGABOB, "mangabob.com") {
override val postreq = true
override val postReq = true
}

@ -9,5 +9,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
internal class MangaClashTv(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGACLASH_TV, "mangaclash.tv", pageSize = 10) {
override val datePattern = "MM/dd/yyyy"
override val postreq = true
override val postReq = true
}

@ -146,7 +146,7 @@ internal class MangaDass(context: MangaLoaderContext) :
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 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(

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGADINOTOP", "Manga Dino", "en")
internal class MangaDinoTop(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGADINOTOP, "mangadino.top", 10) {
override val postreq = true
override val postReq = true
}

@ -144,7 +144,7 @@ internal class MangaDna(context: MangaLoaderContext) :
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 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(

@ -5,7 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAEFFECT", "MangaEffect", "en")
@MangaSourceParser("MANGAEFFECT", "Manga Effect", "en")
internal class MangaEffect(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAEFFECT, "mangaeffect.com") {
override val datePattern = "dd.MM.yyyy"

@ -9,6 +9,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAFORFREE", "Manga For Free", "en", ContentType.HENTAI)
internal class MangaForFree(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAFORFREE, "mangaforfree.com", 10) {
override val postreq = true
override val postReq = true
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAFOXFULL", "Manga Fox Full", "en")
internal class MangaFoxFull(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAFOXFULL, "mangafoxfull.com") {
override val postreq = true
override val postReq = true
}

@ -8,6 +8,6 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAFREAK", "Manga Freak", "en")
internal class MangaFreak(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAFREAK, "mangafreak.online") {
override val postreq = true
override val postReq = true
override val datePattern = "dd MMMM، yyyy"
}

@ -8,7 +8,7 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGALEVELING", "Manga Leveling", "en")
internal class MangaLeveling(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGALEVELING, "mangaleveling.com", 30) {
override val postreq = true
override val postReq = true
override val tagPrefix = "comics-genre/"
override val listUrl = "comics/"
override val datePattern = "MM/dd/yyyy"

@ -7,6 +7,4 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGA_MANHUA", "Manga Manhua", "en")
internal class MangaManhua(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGA_MANHUA, "mangamanhua.online", pageSize = 10) {
override val datePattern = "d MMMM، yyyy"
}
MadaraParser(context, MangaSource.MANGA_MANHUA, "mangaonlineteam.com", pageSize = 10)

@ -6,8 +6,8 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAOWLBLOG", "MangaOwl .Blog", "en", ContentType.HENTAI)
@MangaSourceParser("MANGAOWLBLOG", "Manga Owl .Blog", "en", ContentType.HENTAI)
internal class MangaOwlBlog(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAOWLBLOG, "mangaowl.blog", 20) {
override val postreq = true
override val postReq = true
}

@ -5,7 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAOWL_IO", "MangaOwl .Io", "en")
@MangaSourceParser("MANGAOWL_IO", "Manga Owl .Io", "en")
internal class MangaOwlIo(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAOWL_IO, "mangaowl.io") {
override val listUrl = "mangaowl-all/"

@ -112,7 +112,7 @@ internal class MangaPure(context: MangaLoaderContext) :
return doc.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 link = href + stylePage
MangaChapter(
id = generateUid(href),
url = link,

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGARAWINFO", "Manga-Raw .Info", "en")
internal class MangaRawInfo(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGARAWINFO, "manga-raw.info", 20) {
override val postreq = true
override val postReq = true
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAROCKY", "Manga Rocky", "en")
internal class MangaRocky(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAROCKY, "mangarocky.com") {
override val postreq = true
override val postReq = true
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAUPDATESTOP", "Manga Updates .Top", "en")
internal class MangaUpdatesTop(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAUPDATESTOP, "mangaupdates.top", 10) {
override val postreq = true
override val postReq = true
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGANELO", "Manga Nelo", "en")
internal class Manganelo(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGANELO, "manganelo.biz", 10) {
override val postreq = true
override val postReq = true
}

@ -6,8 +6,8 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAOWL_ONE", "MangaOwl .One", "en", ContentType.HENTAI)
@MangaSourceParser("MANGAOWL_ONE", "Manga Owl .One", "en", ContentType.HENTAI)
internal class MangaowlOne(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAOWL_ONE, "mangaowl.one") {
override val postreq = true
override val postReq = true
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANGAX1", "MangaX1", "en")
internal class Mangax1(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANGAX1, "mangax1.com") {
override val postreq = true
override val postReq = true
}

@ -8,5 +8,5 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHUASCANINFO", "Manhua Scan .Info", "en")
internal class ManhuaScanInfo(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHUASCANINFO, "manhuascan.info", 10) {
override val postreq = true
override val postReq = true
}

@ -5,8 +5,8 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHUAES", "Manhuaes", "en")
@MangaSourceParser("MANHUAES", "ManhuaEs", "en")
internal class Manhuaes(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHUAES, "manhuaes.com") {
override val postreq = true
override val postReq = true
}

@ -5,6 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHUAGA", "Manhuaga", "en")
@MangaSourceParser("MANHUAGA", "ManhuaGa", "en")
internal class Manhuaga(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHUAGA, "manhuaga.com")

@ -5,7 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHUASY", "Manhuasy", "en")
@MangaSourceParser("MANHUASY", "ManhuaSy", "en")
internal class Manhuasy(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHUASY, "www.manhuasy.com") {
override val listUrl = "manhua/"

@ -5,6 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHUAUS", "Manhuaus", "en")
@MangaSourceParser("MANHUAUS", "ManhuaUs", "en")
internal class Manhuaus(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHUAUS, "manhuaus.com")

@ -6,8 +6,8 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHWA18APP", "Manhwa18 .App", "en", ContentType.HENTAI)
@MangaSourceParser("MANHWA18APP", "Manhwa 18 .App", "en", ContentType.HENTAI)
internal class Manhwa18App(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHWA18APP, "manhwa18.app") {
override val postreq = true
override val postReq = true
}

@ -6,9 +6,8 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHWA18ORG", "Manhwa18 .Org", "en", ContentType.HENTAI)
@MangaSourceParser("MANHWA18ORG", "Manhwa 18 .Org", "en", ContentType.HENTAI)
internal class Manhwa18Org(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHWA18ORG, "manhwa18.org") {
override val postreq = true
override val postReq = true
}

@ -5,6 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHWA2READ", "Manhwa2Read", "en")
@MangaSourceParser("MANHWA2READ", "Manhwa 2 Read", "en")
internal class Manhwa2Read(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHWA2READ, "manhwa2read.com")

@ -9,7 +9,7 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MANHWARAW_COM", "Manhwa Raw .Com", "en", ContentType.HENTAI)
internal class ManhwaRawCom(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MANHWARAW_COM, "manhwaraw.com") {
override val postreq = true
override val postReq = true
override val listUrl = "manhwa-raw/"
override val tagPrefix = "manhwa-raw-genre/"
}

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

Loading…
Cancel
Save