Add DatgarScanlation, HyoManga, HeckScans, MerlinScans, TraduccionesMoonlight, NinjaScan, Mi2MangaEs, ScanVfOrg
Url InariManga Fix chapters MangaGekopull/418/head
parent
42ecf8a958
commit
0208f5be97
@ -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"
|
||||||
|
}
|
||||||
@ -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)
|
||||||
@ -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…
Reference in New Issue