add source request

devi 3 years ago
parent 7c4bffede2
commit e67beae235

@ -0,0 +1,13 @@
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("HIKARISCAN", "Hikari Scan", "pt")
internal class HikariScan(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.HIKARISCAN, "hikariscan.com.br", pageSize = 10) {
override val datePattern: String = "dd 'de' MMMMM 'de' yyyy"
}

@ -204,7 +204,7 @@ internal abstract class MangaReaderParser(
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }
private fun parseMangaList(docs: Document): List<Manga> { protected open fun parseMangaList(docs: Document): List<Manga> {
return docs.select(".postbody .listupd .bs .bsx").mapNotNull { return docs.select(".postbody .listupd .bs .bsx").mapNotNull {
val a = it.selectFirst("a") ?: return@mapNotNull null val a = it.selectFirst("a") ?: return@mapNotNull null
val relativeUrl = a.attrAsRelativeUrl("href") val relativeUrl = a.attrAsRelativeUrl("href")

@ -0,0 +1,21 @@
package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("MANGAPROTM", "MangaProtm", "ar")
internal class MangaProtm(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.MANGAPROTM, pageSize = 20, searchPageSize = 20) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("mangaprotm.com")
override val listUrl = "/series"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar", "AR"))
}

@ -0,0 +1,20 @@
package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import java.text.SimpleDateFormat
import java.util.Locale
@MangaSourceParser("REALMSCANS", "RealmScans", "en")
internal class RealmScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.REALMSCANS, pageSize = 30, searchPageSize = 50) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("realmscans.xyz")
override val listUrl = "/series"
override val chapterDateFormat: SimpleDateFormat = SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH)
}

@ -0,0 +1,216 @@
package org.koitharu.kotatsu.parsers.site.mangareader.id
import org.json.JSONObject
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
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
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN
import org.koitharu.kotatsu.parsers.model.WordSet
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.attrAsAbsoluteUrlOrNull
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.mapNotNullToSet
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.tryParse
import java.text.DateFormat
import java.util.Calendar
@MangaSourceParser("KOMIKCAST", "Komikcast", "id")
internal class Komikcast(context: MangaLoaderContext) :
MangaReaderParser(context, MangaSource.KOMIKCAST, pageSize = 60, searchPageSize = 28) {
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("komikcast.io")
override val listUrl = "/daftar-komik"
override suspend fun getDetails(manga: Manga): Manga {
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val chapters = docs.select("#chapter-wrapper > li").mapChapters(reversed = true) { index, element ->
val url = element.selectFirst("a")?.attrAsRelativeUrl("href") ?: return@mapChapters null
MangaChapter(
id = generateUid(url),
name = docs.selectFirst("a.chapter-link-item")?.ownText().orEmpty(),
url = url,
number = index + 1,
scanlator = null,
uploadDate = parseChapterDate(
chapterDateFormat,
element.selectFirst("div.chapter-link-time")?.text(),
),
branch = null,
source = source,
)
}
return parseInfo(docs, manga, chapters)
}
override suspend fun parseInfo(docs: Document, manga: Manga, chapters: List<MangaChapter>): Manga {
/// set if is table
val tagMap = getOrCreateTagMap()
val tags = docs.select(".komik_info-content-genre > a").mapNotNullToSet { tagMap[it.text()] }
val state = docs.selectFirst(".komik_info-content-meta span:contains(Status)")?.lastElementChild()
val mangaState = state?.let {
when (it.text()) {
"Ongoing" -> MangaState.ONGOING
"Completed" -> MangaState.FINISHED
else -> null
}
}
val author = docs.selectFirst(".komik_info-content-meta span:contains(Author)")?.lastElementChild()?.text()
val nsfw = docs.selectFirst(".restrictcontainer") != null
|| docs.selectFirst(".info-right .alr") != null
|| docs.selectFirst(".postbody .alr") != null
return manga.copy(
description = docs.selectFirst("div.komik_info-description-sinopsis")?.text(),
state = mangaState,
author = author,
isNsfw = manga.isNsfw || nsfw,
tags = tags,
chapters = chapters,
)
}
override fun parseMangaList(docs: Document): List<Manga> {
return docs.select("div.list-update_item").mapNotNull {
val a = it.selectFirst("a") ?: return@mapNotNull null
val relativeUrl = a.attrAsRelativeUrl("href")
val rating = it.selectFirst(".numscore")?.text()
?.toFloatOrNull()?.div(10) ?: RATING_UNKNOWN
val name = it.selectFirst("h3.title")?.text().orEmpty()
Manga(
id = generateUid(relativeUrl),
url = relativeUrl,
title = name,
altTitle = null,
publicUrl = a.attrAsAbsoluteUrl("href"),
rating = rating,
isNsfw = isNsfwSource,
coverUrl = it.selectFirst("img.ts-post-image")?.imageUrl().orEmpty(),
tags = emptySet(),
state = null,
author = null,
source = source,
)
}
}
private fun Element.imageUrl(): String {
return attrAsAbsoluteUrlOrNull("src")
?: attrAsAbsoluteUrlOrNull("data-src")
?: attrAsAbsoluteUrlOrNull("data-cfsrc")
?: ""
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val chapterUrl = chapter.url.toAbsoluteUrl(domain)
val docs = webClient.httpGet(chapterUrl).parseHtml()
val test = docs.select("script:containsData(ts_reader)")
if (test.isNullOrEmpty()) {
return docs.select("div#chapter_body img").map { img ->
val url = img.imageUrl()
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
} else {
val script = docs.selectFirstOrThrow("script:containsData(ts_reader)")
val images = JSONObject(script.data().substringAfter('(').substringBeforeLast(')'))
.getJSONArray("sources")
.getJSONObject(0)
.getJSONArray("images")
val pages = ArrayList<MangaPage>(images.length())
for (i in 0 until images.length()) {
pages.add(
MangaPage(
id = generateUid(images.getString(i)),
url = images.getString(i),
preview = null,
source = source,
),
)
}
return pages
}
}
protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
date ?: return 0
return when {
date.endsWith(" ago", ignoreCase = true) -> {
parseRelativeDate(date)
}
else -> dateFormat.tryParse(date)
}
}
private fun parseRelativeDate(date: String): Long {
val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0
val cal = Calendar.getInstance()
return when {
WordSet(
"day",
"days",
).anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("hour", "hours").anyWordIn(date) -> cal.apply {
add(
Calendar.HOUR,
-number,
)
}.timeInMillis
WordSet(
"mins",
).anyWordIn(date) -> cal.apply {
add(
Calendar.MINUTE,
-number,
)
}.timeInMillis
WordSet("second").anyWordIn(date) -> cal.apply {
add(
Calendar.SECOND,
-number,
)
}.timeInMillis
WordSet("month", "months").anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0
}
}
}
Loading…
Cancel
Save