Add, fix sources

Manual addition of lang on Bato.To
Add multi tag , lang and rework tags on exhentai
Add lang on imhentai
pull/404/head
devi 2 years ago
parent b3be87f541
commit d6b578acb0

@ -215,18 +215,21 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
throw ParseException("Cannot find gernes list", scripts[0].baseUri()) throw ParseException("Cannot find gernes list", scripts[0].baseUri())
} }
override suspend fun getAvailableLocales(): Set<Locale> { override suspend fun getAvailableLocales(): Set<Locale> = setOf(
val jsRaw = webClient.httpGet("https://$domain/amsta/build/jss-btoto_v22.js").parseRaw() Locale.CHINESE, Locale.ENGLISH, Locale.US, Locale.FRENCH, Locale.GERMAN, Locale.ITALIAN, Locale.JAPANESE,
val langRaw = jsRaw.substringAfter("items: {").substringBefore(",\"_t\"").split("code\":\"").drop(1) Locale("af"), Locale("ar"), Locale("az"), Locale("eu"), Locale("be"),
return langRaw.mapNotNullToSet { Locale("bn"), Locale("bs"), Locale("bg"), Locale("my"), Locale("km"),
val lang = it.substringBefore("\",\"") Locale("ceb"), Locale("zh_hk"), Locale("zh_tw"), Locale("hr"), Locale("cs"),
if (lang.contains("-")) { Locale("da"), Locale("nl"), Locale("eo"), Locale("et"), Locale("fil"),
return@mapNotNullToSet null Locale("fi"), Locale("ka"), Locale("el"), Locale("ht"), Locale("he"),
} else { Locale("hi"), Locale("hu"), Locale("id"), Locale("kk"), Locale("ko"),
Locale(lang) Locale("lv"), Locale("ms"), Locale("ml"), Locale("mo"), Locale("mn"),
} Locale("ne"), Locale("no"), Locale("fa"), Locale("pl"), Locale("pt"),
} Locale("pt_br"), Locale("pt_pt"), Locale("ro"), Locale("ru"), Locale("sr"),
} Locale("si"), Locale("sk"), Locale("es"), Locale("es_419"), Locale("ta"),
Locale("te"), Locale("th"), Locale("ti"), Locale("tr"), Locale("uk"),
Locale("vi"), Locale("zu"),
)
private suspend fun search(page: Int, query: String): List<Manga> { private suspend fun search(page: Int, query: String): List<Manga> {
val url = buildString { val url = buildString {

@ -23,7 +23,7 @@ private const val CHAPTERS_LIMIT = 99999
@MangaSourceParser("COMICK_FUN", "ComicK") @MangaSourceParser("COMICK_FUN", "ComicK")
internal class ComickFunParser(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.COMICK_FUN, 20) { internal class ComickFunParser(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.COMICK_FUN, 20) {
override val configKeyDomain = ConfigKey.Domain("comick.app") override val configKeyDomain = ConfigKey.Domain("comick.cc")
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,

@ -1,7 +1,10 @@
package org.koitharu.kotatsu.parsers.site.all package org.koitharu.kotatsu.parsers.site.all
import androidx.collection.ArrayMap
import androidx.collection.SparseArrayCompat import androidx.collection.SparseArrayCompat
import androidx.collection.set import androidx.collection.set
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
@ -40,7 +43,7 @@ internal class ExHentaiParser(
private val authCookies = arrayOf("ipb_member_id", "ipb_pass_hash") private val authCookies = arrayOf("ipb_member_id", "ipb_pass_hash")
private var updateDm = false private var updateDm = false
private val nextPages = SparseArrayCompat<Long>() private val nextPages = SparseArrayCompat<Long>()
private val suspiciousContentKey = ConfigKey.ShowSuspiciousContent(true) private val suspiciousContentKey = ConfigKey.ShowSuspiciousContent(false)
override val isAuthorized: Boolean override val isAuthorized: Boolean
get() { get() {
@ -89,17 +92,31 @@ internal class ExHentaiParser(
} }
is MangaListFilter.Advanced -> { is MangaListFilter.Advanced -> {
append("&f_search=")
var fCats = 0
if (filter.tags.isNotEmpty()) { if (filter.tags.isNotEmpty()) {
var fCats = 0 filter.tags.forEach {
for (tag in filter.tags) { if (it.title.startsWith("- ")) {
tag.key.toIntOrNull()?.let { fCats = fCats or it } ?: run { it.key.toIntOrNull()?.let { fCats = fCats or it } ?: run {
search += tag.key + " " search += it.key + " "
}
} else {
append(" tag:".urlEncoded())
append(it.key)
} }
} }
if (fCats != 0) { }
append("&f_cats=")
append(1023 - fCats) if (filter.locale != null) {
} append(" language:".urlEncoded())
append(filter.locale.toLanguagePath())
}
if (fCats != 0) {
append("&f_cats=")
append(1023 - fCats)
} }
} }
@ -163,8 +180,18 @@ internal class ExHentaiParser(
val root = doc.body().selectFirstOrThrow("div.gm") val root = doc.body().selectFirstOrThrow("div.gm")
val cover = root.getElementById("gd1")?.children()?.first() val cover = root.getElementById("gd1")?.children()?.first()
val title = root.getElementById("gd2") val title = root.getElementById("gd2")
val taglist = root.getElementById("taglist") val tagList = root.getElementById("taglist")
val tabs = doc.body().selectFirst("table.ptt")?.selectFirst("tr") val tabs = doc.body().selectFirst("table.ptt")?.selectFirst("tr")
val lang =
root.getElementById("gd3")?.selectFirst("tr:contains(Language)")?.selectFirst(".gdt2")?.text() ?: "Unknown"
val tagMap = getOrCreateTagMap()
val tagF =
tagList?.selectFirst("tr:contains(female:)")?.select("a")?.mapNotNullToSet { tagMap[it.text()] }.orEmpty()
val tagM =
tagList?.selectFirst("tr:contains(male:)")?.select("a")?.mapNotNullToSet { tagMap[it.text()] }.orEmpty()
val tags = tagF + tagM
return manga.copy( return manga.copy(
title = title?.getElementById("gn")?.text()?.cleanupTitle() ?: manga.title, title = title?.getElementById("gn")?.text()?.cleanupTitle() ?: manga.title,
altTitle = title?.getElementById("gj")?.text()?.cleanupTitle() ?: manga.altTitle, altTitle = title?.getElementById("gj")?.text()?.cleanupTitle() ?: manga.altTitle,
@ -174,10 +201,11 @@ internal class ExHentaiParser(
?.toFloatOrNull() ?.toFloatOrNull()
?.div(5f) ?: manga.rating, ?.div(5f) ?: manga.rating,
largeCoverUrl = cover?.styleValueOrNull("background")?.cssUrl(), largeCoverUrl = cover?.styleValueOrNull("background")?.cssUrl(),
description = taglist?.select("tr")?.joinToString("<br>") { tr -> tags = tags,
description = tagList?.select("tr")?.joinToString("<br>") { tr ->
val (tc, td) = tr.children() val (tc, td) = tr.children()
val subtags = td.select("a").joinToString { it.html() } val subTags = td.select("a").joinToString { it.html() }
"<b>${tc.html()}</b> $subtags" "<b>${tc.html()}</b> $subTags"
}, },
chapters = tabs?.select("a")?.findLast { a -> chapters = tabs?.select("a")?.findLast { a ->
a.text().toIntOrNull() != null a.text().toIntOrNull() != null
@ -194,7 +222,7 @@ internal class ExHentaiParser(
uploadDate = 0L, uploadDate = 0L,
source = source, source = source,
scanlator = null, scanlator = null,
branch = null, branch = lang,
) )
} }
chapters.toList() chapters.toList()
@ -221,18 +249,78 @@ internal class ExHentaiParser(
return doc.body().requireElementById("img").attrAsAbsoluteUrl("src") return doc.body().requireElementById("img").attrAsAbsoluteUrl("src")
} }
private val tags =
"ahegao,anal,angel,apron,bandages,bbw,bdsm,beauty mark,big areolae,big ass,big breasts,big clit,big lips," +
"big nipples,bikini,blackmail,bloomers,blowjob,bodysuit,bondage,breast expansion,bukkake,bunny girl,business suit," +
"catgirl,centaur,cheating,chinese dress,christmas,collar,corset,cosplaying,cowgirl,crossdressing,cunnilingus," +
"dark skin,daughter,deepthroat,defloration,demon girl,double penetration,dougi,dragon,drunk,elf,exhibitionism,farting," +
"females only,femdom,filming,fingering,fishnets,footjob,fox girl,furry,futanari,garter belt,ghost,giantess," +
"glasses,gloves,goblin,gothic lolita,growth,guro,gyaru,hair buns,hairy,hairy armpits,handjob,harem,hidden sex," +
"horns,huge breasts,humiliation,impregnation,incest,inverted nipples,kemonomimi,kimono,kissing,lactation," +
"latex,leg lock,leotard,lingerie,lizard girl,maid,masked face,masturbation,midget,miko,milf,mind break," +
"mind control,monster girl,mother,muscle,nakadashi,netorare,nose hook,nun,nurse,oil,paizuri,panda girl," +
"pantyhose,piercing,pixie cut,policewoman,ponytail,pregnant,rape,rimjob,robot,scat,lolicon,schoolgirl uniform," +
"sex toys,shemale,sister,small breasts,smell,sole dickgirl,sole female,squirting,stockings,sundress,sweating," +
"swimsuit,swinging,tail,tall girl,teacher,tentacles,thigh high boots,tomboy,transformation,twins,twintails," +
"unusual pupils,urination,vore,vtuber,widow,wings,witch,wolf girl,x-ray,yuri,zombie,sole male,males only,yaoi," +
"tomgirl,tall man,oni,shotacon,prostate massage,policeman,males only,huge penis,fox boy,feminization,dog boy,dickgirl on male,big penis"
private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex()
override suspend fun getAvailableTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet()
}
protected suspend fun getOrCreateTagMap(): Map<String, MangaTag> = mutex.withLock {
tagCache?.let { return@withLock it }
val tagMap = ArrayMap<String, MangaTag>()
val tagElements = tags.split(",")
for (el in tagElements) {
if (el.isEmpty()) continue
tagMap[el] = MangaTag(
title = el,
key = el,
source = source,
)
}
val doc = webClient.httpGet("https://${domain}").parseHtml() val doc = webClient.httpGet("https://${domain}").parseHtml()
val root = doc.body().requireElementById("searchbox").selectFirstOrThrow("table") val root = doc.body().requireElementById("searchbox").selectFirstOrThrow("table")
return root.select("div.cs").mapNotNullToSet { div -> root.select("div.cs").mapNotNullToSet { div ->
val id = div.id().substringAfterLast('_').toIntOrNull() val id = div.id().substringAfterLast('_').toIntOrNull() ?: return@mapNotNullToSet null
?: return@mapNotNullToSet null val name = "- " + div.text().toTitleCase()
MangaTag( tagMap[name] = MangaTag(
title = div.text().toTitleCase(), title = name,
key = id.toString(), key = id.toString(),
source = source, source = source,
) )
} }
tagCache = tagMap
return@withLock tagMap
}
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
Locale.JAPANESE,
Locale.ENGLISH,
Locale.CHINESE,
Locale("nl"),
Locale.FRENCH,
Locale.GERMAN,
Locale("hu"),
Locale.ITALIAN,
Locale("kr"),
Locale("pl"),
Locale("pt"),
Locale("ru"),
Locale("es"),
Locale("th"),
Locale("vi"),
)
private fun Locale.toLanguagePath() = when (language) {
else -> getDisplayLanguage(Locale.ENGLISH).lowercase()
} }
override suspend fun getUsername(): String { override suspend fun getUsername(): String {

@ -22,49 +22,42 @@ internal class ImHentai(context: MangaLoaderContext) :
override val configKeyDomain = ConfigKey.Domain("imhentai.xxx") override val configKeyDomain = ConfigKey.Domain("imhentai.xxx")
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> { override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
append("/search/?page=")
append(page.toString())
when (filter) { when (filter) {
is MangaListFilter.Search -> { is MangaListFilter.Search -> {
append("/search/?key=") append("&key=")
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
append("&page=")
append(page)
} }
is MangaListFilter.Advanced -> { is MangaListFilter.Advanced -> {
val tag = filter.tags.oneOrThrowIfMany()
if (filter.tags.isNotEmpty()) { if (filter.tags.isNotEmpty()) {
append("/tag/") append("&key=")
append(tag?.key.orEmpty()) append(filter.tags.joinToString(separator = ",") { it.key })
append("/") }
when (filter.sortOrder) {
SortOrder.UPDATED -> append("") var lang = "&en=1&jp=1&es=1&fr=1&kr=1&de=1&ru=1"
SortOrder.POPULARITY -> append("popular/") filter.locale?.let {
else -> append("") lang = "&en=0&jp=0&es=0&fr=0&kr=0&de=0&ru=0"
} lang = lang.replace("${it.language}=0", "${it.language}=1")
append("?page=") }
append(page) append(lang)
} else {
append("/search/?page=") when (filter.sortOrder) {
append(page) SortOrder.UPDATED -> append("&lt=1&pp=0")
when (filter.sortOrder) { SortOrder.POPULARITY -> append("&lt=0&pp=1")
SortOrder.UPDATED -> append("&lt=1&pp=0") SortOrder.RATING -> append("&lt=0&pp=0")
SortOrder.POPULARITY -> append("&lt=0&pp=1") else -> append("&lt=1&pp=0")
SortOrder.RATING -> append("&lt=0&pp=0")
else -> append("&lt=1&pp=0")
}
} }
} }
null -> { null -> {
append("/search/?lt=1&pp=0&page=") append("&lt=1&pp=0")
append(page)
} }
} }
@ -115,6 +108,10 @@ internal class ImHentai(context: MangaLoaderContext) :
) )
} }
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
Locale.ENGLISH, Locale.JAPANESE, Locale("es"), Locale.FRENCH, Locale("kr"), Locale.GERMAN, Locale("ru"),
)
override suspend fun getDetails(manga: Manga): Manga = coroutineScope { override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain) val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml() val doc = webClient.httpGet(fullUrl).parseHtml()

@ -17,7 +17,7 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST) EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST)
override val configKeyDomain = ConfigKey.Domain("www.mangageko.com") override val configKeyDomain = ConfigKey.Domain("www.mgeko.com", "www.mangageko.com")
override val isMultipleTagsSupported = false override val isMultipleTagsSupported = false

@ -127,10 +127,10 @@ internal abstract class HeanCmsAlt(
} }
} }
private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long { protected open fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
d.startsWith("hace ") -> parseRelativeDate(date) d.startsWith("hace ") || d.endsWith(" antes") -> parseRelativeDate(date)
else -> dateFormat.tryParse(date) else -> dateFormat.tryParse(date)
} }
} }
@ -153,7 +153,7 @@ internal abstract class HeanCmsAlt(
) )
}.timeInMillis }.timeInMillis
WordSet("mes").anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis WordSet("mes", "meses").anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("año").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis WordSet("año").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }

@ -0,0 +1,59 @@
package org.koitharu.kotatsu.parsers.site.heancmsalt.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.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.heancmsalt.HeanCmsAlt
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.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import java.text.SimpleDateFormat
@MangaSourceParser("BRAKEOUT", "Brakeout", "es")
internal class Brakeout(context: MangaLoaderContext) :
HeanCmsAlt(context, MangaSource.BRAKEOUT, "brakeout.xyz", 10) {
override val selectManga = "div.grid.grid-cols-2 figure"
override val selectMangaTitle = "figcaption"
override val selectDesc = "#section-sinopsis p"
override val selectChapter = ".grid-capitulos div.contenedor-capitulo-miniatura"
override val selectChapterTitle = "#name"
override val selectChapterDate = "time"
override val datePattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"
override suspend fun getDetails(manga: Manga): Manga {
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return manga.copy(
altTitle = doc.selectFirst(selectAlt)?.text().orEmpty(),
description = doc.selectFirstOrThrow(selectDesc).html(),
chapters = doc.select(selectChapter)
.mapChapters(reversed = true) { i, div ->
val a = div.selectFirstOrThrow("a")
val dateText = div.selectFirstOrThrow(selectChapterDate).text()
val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain)
MangaChapter(
id = generateUid(url),
name = div.selectFirstOrThrow(selectChapterTitle).text(),
number = i + 1,
url = url,
scanlator = null,
uploadDate = parseChapterDate(
dateFormat,
dateText,
),
branch = null,
source = source,
)
},
)
}
override val selectPage = "section img.readImg"
}

@ -7,6 +7,6 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("RESETSCANS", "ResetScans", "en") @MangaSourceParser("RESETSCANS", "ResetScans", "en")
internal class ResetScans(context: MangaLoaderContext) : internal class ResetScans(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.RESETSCANS, "reset-scans.com", 18) { MadaraParser(context, MangaSource.RESETSCANS, "reset-scans.us", 18) {
override val datePattern = "MMM dd" override val datePattern = "MMM dd"
} }

@ -4,6 +4,7 @@ import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@ -18,40 +19,42 @@ internal class Hentaizone(context: MangaLoaderContext) :
override val datePattern = "MMM d, yyyy" override val datePattern = "MMM d, yyyy"
override val sourceLocale: Locale = Locale.FRENCH override val sourceLocale: Locale = Locale.FRENCH
override suspend fun loadChapters(mangaUrl: String, document: Document): List<MangaChapter> {
val url = mangaUrl.toAbsoluteUrl(domain).removeSuffix('/') + "/ajax/chapters/"
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val doc = webClient.httpPost(url, emptyMap()).parseHtml()
return doc.select("li.wp-manga-chapter").mapChapters(reversed = true) { i, li ->
val a = li.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href") + "?style=list"
// correct parse date missing a "." override suspend fun getChapters(manga: Manga, doc: Document): List<MangaChapter> {
val dateOrg = li.selectFirst("span.chapter-release-date i")?.text() ?: "janv 1, 2000" val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
val dateCorrectParse = dateOrg return doc.body().select(selectChapter).mapChapters(reversed = true) { i, li ->
.replace("Jan", "janv.") val a = li.selectFirst("a")
.replace("Fév", "févr.") val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing")
.replace("Mar", "mars") val link = href + stylePage
.replace("avr", "avr.") val dateText = li.selectFirst("a.c-new-tag")?.attr("title") ?: li.selectFirst(selectDate)?.text()
.replace("juil", "juil.") val dateCorrectParse = dateReplace(dateText ?: "janv 1, 1970")
.replace("Sep", "sept.") val name = a.selectFirst("p")?.text() ?: a.ownText()
.replace("nov", "nov.")
.replace("oct", "oct.")
.replace("déc", "déc.")
MangaChapter( MangaChapter(
id = generateUid(href), id = generateUid(href),
url = href, name = name,
name = a.text(),
number = i + 1, number = i + 1,
branch = null, url = link,
uploadDate = parseChapterDate( uploadDate = parseChapterDate(
dateFormat, dateFormat,
dateCorrectParse, dateCorrectParse,
), ),
scanlator = null,
source = source, source = source,
scanlator = null,
branch = null,
) )
} }
} }
private fun dateReplace(date: String): String {
return date.lowercase()
.replace("jan", "janv.")
.replace("fév", "févr.")
.replace("mar", "mars")
.replace("avr", "avr.")
.replace("juil", "juil.")
.replace("sep", "sept.")
.replace("nov", "nov.")
.replace("oct", "oct.")
.replace("déc", "déc.")
}
} }

@ -26,16 +26,8 @@ internal class ToonFr(context: MangaLoaderContext) :
val a = li.selectFirstOrThrow("a") val a = li.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href") + "?style=list" val href = a.attrAsRelativeUrl("href") + "?style=list"
// correct parse date missing a "." // correct parse date missing a "."
val dateOrg = li.selectFirst("span.chapter-release-date i")?.text() ?: "janv 1, 2000" val dateText = li.selectFirst("span.chapter-release-date i")?.text()
val dateCorrectParse = dateOrg val dateCorrectParse = dateReplace(dateText ?: "janv 1, 1970")
.replace("Jan", "janv.")
.replace("Févr", "févr.")
.replace("Avr", "avr.")
.replace("Juil", "juil.")
.replace("Sept", "sept.")
.replace("Nov", "nov.")
.replace("Oct", "oct.")
.replace("Déc", "déc.")
MangaChapter( MangaChapter(
id = generateUid(href), id = generateUid(href),
url = href, url = href,
@ -51,5 +43,18 @@ internal class ToonFr(context: MangaLoaderContext) :
) )
} }
} }
private fun dateReplace(date: String): String {
return date.lowercase()
.replace("jan", "janv.")
.replace("fév", "févr.")
.replace("mar", "mars")
.replace("avr", "avr.")
.replace("juil", "juil.")
.replace("sep", "sept.")
.replace("nov", "nov.")
.replace("oct", "oct.")
.replace("déc", "déc.")
}
} }

@ -1,4 +1,4 @@
package org.koitharu.kotatsu.parsers.site.madtheme.all package org.koitharu.kotatsu.parsers.site.madtheme.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
@ -7,7 +7,7 @@ import org.koitharu.kotatsu.parsers.site.madtheme.MadthemeParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.util.Locale import java.util.Locale
@MangaSourceParser("MANHUASCAN", "ManhuaScan.io", "") @MangaSourceParser("MANHUASCAN", "ManhuaScan.io", "en")
internal class ManhuaScan(context: MangaLoaderContext) : internal class ManhuaScan(context: MangaLoaderContext) :
MadthemeParser(context, MangaSource.MANHUASCAN, "manhuascan.io") { MadthemeParser(context, MangaSource.MANHUASCAN, "manhuascan.io") {
override val sourceLocale: Locale = Locale.ENGLISH override val sourceLocale: Locale = Locale.ENGLISH

@ -7,6 +7,6 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("LUMINOUSSCANS", "LuminousScans", "en") @MangaSourceParser("LUMINOUSSCANS", "LuminousScans", "en")
internal class LuminousScans(context: MangaLoaderContext) : internal class LuminousScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.LUMINOUSSCANS, "luminousscans.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaSource.LUMINOUSSCANS, "luminousscans.net", pageSize = 20, searchPageSize = 10) {
override val listUrl = "/series" override val listUrl = "/series"
} }

Loading…
Cancel
Save