Add DatgarScanlation, HyoManga, HeckScans, MerlinScans, TraduccionesMoonlight, NinjaScan, Mi2MangaEs, ScanVfOrg
Url InariManga Fix chapters MangaGeko
This commit is contained in:
@@ -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")
|
||||
Reference in New Issue
Block a user