Add DatgarScanlation, HyoManga, HeckScans, MerlinScans, TraduccionesMoonlight, NinjaScan, Mi2MangaEs, ScanVfOrg

Url InariManga
Fix chapters MangaGeko
pull/418/head
devi 2 years ago
parent 42ecf8a958
commit 0208f5be97

@ -1,5 +1,7 @@
package org.koitharu.kotatsu.parsers.site.en
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import okhttp3.Headers
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
@ -98,10 +100,10 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
}
}
override suspend fun getDetails(manga: Manga): Manga {
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("MMM dd, yyyy", sourceLocale)
return manga.copy(
val chaptersDeferred = async { loadChapters(manga.url) }
manga.copy(
altTitle = doc.selectFirstOrThrow(".alternative-title").text(),
state = when (doc.selectFirstOrThrow(".header-stats span:contains(Status) strong").text()) {
"Ongoing" -> MangaState.ONGOING
@ -117,27 +119,34 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
},
author = doc.selectFirstOrThrow(".author").text(),
description = doc.selectFirstOrThrow(".description").html(),
chapters = doc.requireElementById("chapters").select("ul.chapter-list li")
.mapChapters(reversed = true) { i, li ->
val a = li.selectFirstOrThrow("a")
val url = a.attrAsRelativeUrl("href")
val name = li.selectFirstOrThrow(".chapter-title").text()
val dateText = li.select(".chapter-update").attr("datetime").substringBeforeLast(',')
.replace(".", "").replace("Sept", "Sep")
MangaChapter(
id = generateUid(url),
name = name,
number = i + 1,
url = url,
scanlator = null,
uploadDate = dateFormat.tryParse(dateText),
branch = null,
source = source,
)
},
chapters = chaptersDeferred.await(),
)
}
private suspend fun loadChapters(mangaUrl: String): List<MangaChapter> {
val urlChapter = mangaUrl + "all-chapters/"
val doc = webClient.httpGet(urlChapter.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("MMM dd, yyyy", sourceLocale)
return doc.requireElementById("chapters").select("ul.chapter-list li")
.mapChapters(reversed = true) { i, li ->
val a = li.selectFirstOrThrow("a")
val url = a.attrAsRelativeUrl("href")
val name = li.selectFirstOrThrow(".chapter-title").text()
val dateText = li.select(".chapter-update").attr("datetime").substringBeforeLast(',')
.replace(".", "").replace("Sept", "Sep")
MangaChapter(
id = generateUid(url),
name = name,
number = i + 1,
url = url,
scanlator = null,
uploadDate = dateFormat.tryParse(dateText),
branch = null,
source = source,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()

@ -0,0 +1,157 @@
package org.koitharu.kotatsu.parsers.site.fr
import androidx.collection.ArrayMap
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.koitharu.kotatsu.parsers.ErrorMessages
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("SCANVFORG", "ScanVfOrg", "fr")
internal class ScanVfOrg(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.SCANVFORG, 0) {
override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING)
override val configKeyDomain = ConfigKey.Domain("scanvf.org")
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
val url = buildString {
append("https://")
append(domain)
when (filter) {
is MangaListFilter.Search -> {
throw IllegalArgumentException(ErrorMessages.SEARCH_NOT_SUPPORTED) // TODO
}
is MangaListFilter.Advanced -> {
append("/manga")
append("?q=")
append(
when (filter.sortOrder) {
SortOrder.UPDATED -> "u"
SortOrder.ALPHABETICAL -> "a"
SortOrder.POPULARITY -> "p"
SortOrder.RATING -> "r"
else -> "u"
},
)
filter.tags.forEach {
append("&search[tags][]=")
append(it.key)
}
append("&page=")
append(page.toString())
}
null -> {
append("/manga?page=")
append(page.toString())
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return doc.select(".series-paginated .series").map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
title = div.selectFirstOrThrow(".link-series h3").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,
state = null,
source = source,
isNsfw = isNsfwSource,
)
}
}
private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex()
override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet()
}
private suspend fun getOrCreateTagMap(): Map<String, MangaTag> = mutex.withLock {
tagCache?.let { return@withLock it }
val tagMap = ArrayMap<String, MangaTag>()
val tagElements = webClient.httpGet("https://$domain/manga").parseHtml()
.requireElementById("filter-wrapper").select(".form-filters div.form-check")
for (el in tagElements) {
val name = el.selectFirstOrThrow("label").text()
if (name.isEmpty()) continue
tagMap[name] = MangaTag(
key = el.selectFirstOrThrow("input").attr("value"),
title = name,
source = source,
)
}
tagCache = tagMap
return@withLock tagMap
}
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("MM-dd-yyyy", sourceLocale)
val tagMap = getOrCreateTagMap()
val selectTag = doc.select(".card-series-detail .col-6:contains(Categories) div")
val tags = selectTag.mapNotNullToSet { tagMap[it.text()] }
return manga.copy(
rating = doc.selectFirst(".card-series-detail .rate-value span")?.ownText()?.toFloatOrNull()?.div(5f)
?: RATING_UNKNOWN,
tags = tags,
author = doc.selectFirst(".card-series-detail .col-6:contains(Auteur) div")?.text(),
altTitle = doc.selectFirst(".card div.col-12.mb-4 h2")?.text().orEmpty(),
description = doc.selectFirst(".card div.col-12.mb-4 p")?.html().orEmpty(),
chapters = doc.select(".list-books .col-chapter").mapChapters(reversed = true) { i, div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
MangaChapter(
id = generateUid(href),
name = div.selectFirstOrThrow("h5").html().substringBefore("<div").substringAfter("</span>"),
number = i + 1,
url = href,
scanlator = null,
uploadDate = dateFormat.tryParse(doc.selectFirstOrThrow("h5 div").text()),
branch = null,
source = source,
)
},
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val pages = ArrayList<MangaPage>()
var n = 0
while (true) {
++n
val img = webClient.httpGet("$fullUrl/$n").parseHtml().selectFirst(".book-page .img-fluid")?.src() ?: break
pages.add(
MangaPage(
id = generateUid(img),
url = img,
preview = null,
source = source,
),
)
}
return pages
}
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.madara.es
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("MI2MANGAES", "Mi2MangaEs", "es")
internal class Mi2MangaEs(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.MI2MANGAES, "es.mi2manga.com", 10)

@ -0,0 +1,12 @@
package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("NINJASCAN", "NinjaScan", "pt")
internal class NinjaScan(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.NINJASCAN, "ninjascan.site") {
override val datePattern: String = "dd 'de' MMMMM 'de' yyyy"
}

@ -4,10 +4,7 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.util.Locale
@MangaSourceParser("INARIMANGA", "InariManga", "es")
internal class InariManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.INARIMANGA, "inarimanga.com", pageSize = 20, searchPageSize = 10) {
override val sourceLocale: Locale = Locale.ENGLISH
}
MangaReaderParser(context, MangaSource.INARIMANGA, "inarimanga.net", pageSize = 20, searchPageSize = 10)

@ -0,0 +1,14 @@
package org.koitharu.kotatsu.parsers.site.mangareader.es
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.util.Locale
@MangaSourceParser("TRADUCCIONESMOONLIGHT", "TraduccionesMoonlight", "es", ContentType.HENTAI)
internal class TraduccionesMoonlight(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.TRADUCCIONESMOONLIGHT, "tenkaiscan.net", 20, 10) {
override val sourceLocale: Locale = Locale.ENGLISH
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.mangareader.tr
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("MERLINSCANS", "MerlinScans", "tr")
internal class MerlinScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MERLINSCANS, "merlinscans.com", pageSize = 25, searchPageSize = 20)

@ -43,6 +43,7 @@ internal abstract class ZeistMangaParser(
"مستمر",
"devam ediyor",
"güncel",
"en emisión",
)
@JvmField
@ -50,6 +51,7 @@ internal abstract class ZeistMangaParser(
"completed",
"completo",
"tamamlandı",
"finalizado",
)
@JvmField
@ -59,6 +61,7 @@ internal abstract class ZeistMangaParser(
"dropado",
"abandonado",
"cancelado",
"suspendido",
)
@JvmField

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.zeistmanga.es
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.zeistmanga.ZeistMangaParser
@MangaSourceParser("DATGARSCANLATION", "DatgarScanlation", "es")
internal class DatgarScanlation(context: MangaLoaderContext) :
ZeistMangaParser(context, MangaSource.DATGARSCANLATION, "datgarscanlation.blogspot.com")

@ -0,0 +1,12 @@
package org.koitharu.kotatsu.parsers.site.zeistmanga.id
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.zeistmanga.ZeistMangaParser
@MangaSourceParser("HYOMANGA", "HyoManga", "id")
internal class HyoManga(context: MangaLoaderContext) :
ZeistMangaParser(context, MangaSource.HYOMANGA, "www.hyomanga.my.id") {
override val mangaCategory = "Manga"
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.zeistmanga.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.zeistmanga.ZeistMangaParser
@MangaSourceParser("HECKSCANS", "HeckScans", "pt")
internal class HeckScans(context: MangaLoaderContext) :
ZeistMangaParser(context, MangaSource.HECKSCANS, "heckscans.blogspot.com")
Loading…
Cancel
Save