Rm duniakomik close #952
Fix DoujinKu close #951 Fix DoujinDesu.tv close Add, fix some sources #963 change url close #965 ( the copy was added anyway )master
parent
5f771973a8
commit
50194df24d
@ -1,10 +1,98 @@
|
|||||||
package org.koitharu.kotatsu.parsers.site.madara.es
|
package org.koitharu.kotatsu.parsers.site.madara.es
|
||||||
|
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
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.exception.ParseException
|
||||||
|
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.MangaParserSource
|
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
|
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
|
||||||
|
import org.koitharu.kotatsu.parsers.util.*
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
|
||||||
@MangaSourceParser("MANGASNOSEKAI", "MangasNoSekai", "es")
|
@MangaSourceParser("MANGASNOSEKAI", "MangasNoSekai", "es")
|
||||||
internal class MangasNoSekai(context: MangaLoaderContext) :
|
internal class MangasNoSekai(context: MangaLoaderContext) :
|
||||||
MadaraParser(context, MangaParserSource.MANGASNOSEKAI, "mangasnosekai.com")
|
MadaraParser(context, MangaParserSource.MANGASNOSEKAI, "mangasnosekai.com") {
|
||||||
|
|
||||||
|
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
|
||||||
|
val fullUrl = manga.url.toAbsoluteUrl(domain)
|
||||||
|
val doc = webClient.httpGet(fullUrl).parseHtml()
|
||||||
|
val body = doc.body()
|
||||||
|
val chaptersDeferred = async { loadChapters(manga.url, doc) }
|
||||||
|
manga.copy(
|
||||||
|
tags = doc.body().select("#section-sinopsis a[href*=genre]").mapNotNullToSet { a ->
|
||||||
|
MangaTag(
|
||||||
|
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
|
||||||
|
title = a.text().toTitleCase(),
|
||||||
|
source = source,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
author = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Autor)) p a")?.text()
|
||||||
|
.orEmpty(),
|
||||||
|
description = body.selectFirst("#section-sinopsis p")?.text().orEmpty(),
|
||||||
|
altTitle = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Otros nombres)) p")?.text()
|
||||||
|
.orEmpty(),
|
||||||
|
state = body.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Estado)) p")
|
||||||
|
?.let {
|
||||||
|
when (it.text()) {
|
||||||
|
in ongoing -> MangaState.ONGOING
|
||||||
|
in finished -> MangaState.FINISHED
|
||||||
|
in abandoned -> MangaState.ABANDONED
|
||||||
|
in paused -> MangaState.PAUSED
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
chapters = chaptersDeferred.await(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo take other pages
|
||||||
|
override suspend fun loadChapters(mangaUrl: String, document: Document): List<MangaChapter> {
|
||||||
|
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
|
||||||
|
return document.select("div.container-capitulos div.contenedor-capitulo-miniatura")
|
||||||
|
.mapChapters(reversed = true) { i, div ->
|
||||||
|
val a = div.selectFirst("a")
|
||||||
|
val href = a?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link is missing")
|
||||||
|
val link = href + stylePage
|
||||||
|
val dateText = div.selectFirst("a div.chapter-text")?.text()
|
||||||
|
val name = div.selectFirst("a div.text-sm")?.text() ?: a.ownText()
|
||||||
|
MangaChapter(
|
||||||
|
id = generateUid(href),
|
||||||
|
url = link,
|
||||||
|
name = name,
|
||||||
|
number = i + 1f,
|
||||||
|
volume = 0,
|
||||||
|
branch = null,
|
||||||
|
uploadDate = parseChapterDate(
|
||||||
|
dateFormat,
|
||||||
|
dateText,
|
||||||
|
),
|
||||||
|
scanlator = null,
|
||||||
|
source = source,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||||
|
val fullUrl = chapter.url.toAbsoluteUrl(domain)
|
||||||
|
val doc = webClient.httpGet(fullUrl).parseHtml()
|
||||||
|
val root = doc.body().selectFirst("div.reading-content")
|
||||||
|
?: throw ParseException("No image found, try to log in", fullUrl)
|
||||||
|
return root.select(selectPage).map { div ->
|
||||||
|
val img = div.selectFirstOrThrow("img")
|
||||||
|
val url = img.src()?.toRelativeUrl(domain) ?: div.parseFailed("Image src not found")
|
||||||
|
MangaPage(
|
||||||
|
id = generateUid(url),
|
||||||
|
url = url,
|
||||||
|
preview = null,
|
||||||
|
source = source,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.site.madara.id
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@MangaSourceParser("LUMOSKOMIK", "LumosKomik", "id")
|
||||||
|
internal class LumosKomik(context: MangaLoaderContext) :
|
||||||
|
MadaraParser(context, MangaParserSource.LUMOSKOMIK, "lumoskomik.com") {
|
||||||
|
override val tagPrefix = "genre/"
|
||||||
|
override val listUrl = "komik/"
|
||||||
|
override val datePattern = "dd MMMM yyyy"
|
||||||
|
override val sourceLocale: Locale = Locale.ENGLISH
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
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.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
|
||||||
|
|
||||||
|
@MangaSourceParser("LIMITEDTIMEPOJECT", "LimitedTimePoject", "pt")
|
||||||
|
internal class LimitedTimePoject(context: MangaLoaderContext) :
|
||||||
|
MadaraParser(context, MangaParserSource.LIMITEDTIMEPOJECT, "limitedtimeproject.com", 10) {
|
||||||
|
override val listUrl = "manhwa/"
|
||||||
|
override val tagPrefix = "manhwa-genero/"
|
||||||
|
override val datePattern = "dd 'de' MMMMM 'de' yyyy"
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.site.madara.tr
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
|
||||||
|
|
||||||
|
@MangaSourceParser("MANGAOKUSANA", "MangaOkusana", "tr")
|
||||||
|
internal class MangaOkusana(context: MangaLoaderContext) :
|
||||||
|
MadaraParser(context, MangaParserSource.MANGAOKUSANA, "mangaokusana.com") {
|
||||||
|
override val datePattern = "dd MMMM yyyy"
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
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.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
|
||||||
|
|
||||||
|
@MangaSourceParser("ALTAYSCANS", "AltayScans", "en")
|
||||||
|
internal class AltayScans(context: MangaLoaderContext) :
|
||||||
|
MangaReaderParser(context, MangaParserSource.ALTAYSCANS, "altayscans.com", pageSize = 20, searchPageSize = 10) {
|
||||||
|
override val isTagsExclusionSupported = false
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
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.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
|
||||||
|
|
||||||
|
@MangaSourceParser("LUACOMIC_COM", "luaComic.com", "en")
|
||||||
|
internal class LuaComicCom(context: MangaLoaderContext) :
|
||||||
|
MangaReaderParser(context, MangaParserSource.LUACOMIC_COM, "luacomic.com", pageSize = 20, searchPageSize = 10) {
|
||||||
|
override val isTagsExclusionSupported = false
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.site.mangareader.id
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
@MangaSourceParser("KOMIKINDO_MOE", "KomikIndo.moe", "id")
|
||||||
|
internal class KomikIndo(context: MangaLoaderContext) :
|
||||||
|
MangaReaderParser(context, MangaParserSource.KOMIKINDO_MOE, "komikindo.moe", pageSize = 20, searchPageSize = 10) {
|
||||||
|
override val sourceLocale: Locale = Locale.ENGLISH
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.site.mangareader.id
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
|
||||||
|
|
||||||
|
@MangaSourceParser("MANHWAKU", "Manhwaku", "id")
|
||||||
|
internal class Manhwaku(context: MangaLoaderContext) :
|
||||||
|
MangaReaderParser(context, MangaParserSource.MANHWAKU, "manhwaku.id", pageSize = 20, searchPageSize = 10)
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.site.mangareader.pt
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
|
||||||
|
|
||||||
|
@MangaSourceParser("DEMONSECT", "DemonSect", "pt")
|
||||||
|
internal class DemonSect(context: MangaLoaderContext) :
|
||||||
|
MangaReaderParser(context, MangaParserSource.DEMONSECT, "dsectcomics.org", pageSize = 20, searchPageSize = 10) {
|
||||||
|
override val listUrl = "/comics"
|
||||||
|
override val isTagsExclusionSupported = false
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
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.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
|
||||||
|
|
||||||
|
@MangaSourceParser("CULTURESUBS", "CultureSubs", "tr")
|
||||||
|
internal class CultureSubs(context: MangaLoaderContext) :
|
||||||
|
MangaReaderParser(context, MangaParserSource.CULTURESUBS, "culturesubs.com", pageSize = 20, searchPageSize = 10) {
|
||||||
|
override val isMultipleTagsSupported = false
|
||||||
|
}
|
||||||
@ -1,14 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.parsers.site.mmrcms.fr
|
|
||||||
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
|
||||||
import org.koitharu.kotatsu.parsers.site.mmrcms.MmrcmsParser
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@MangaSourceParser("MANGASCANFR", "MangaScanFr", "fr")
|
|
||||||
internal class MangaScanFr(context: MangaLoaderContext) :
|
|
||||||
MmrcmsParser(context, MangaParserSource.MANGASCANFR, "mangascan-fr.net") {
|
|
||||||
override val sourceLocale: Locale = Locale.ENGLISH
|
|
||||||
override val imgUpdated = ".jpg"
|
|
||||||
}
|
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.site.wpcomics.vi
|
||||||
|
|
||||||
|
import androidx.collection.ArrayMap
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
|
import org.koitharu.kotatsu.parsers.exception.NotFoundException
|
||||||
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
|
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||||
|
import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser
|
||||||
|
import org.koitharu.kotatsu.parsers.util.*
|
||||||
|
import java.util.EnumSet
|
||||||
|
|
||||||
|
@MangaSourceParser("NETTRUYENSSR", "NetTruyenSSR", "vi")
|
||||||
|
internal class NetTruyenSSR(context: MangaLoaderContext) :
|
||||||
|
WpComicsParser(context, MangaParserSource.NETTRUYENSSR, "nettruyenssr.com", 20) {
|
||||||
|
|
||||||
|
override val isMultipleTagsSupported = true
|
||||||
|
override val isTagsExclusionSupported = true
|
||||||
|
override val listUrl = "/tim-kiem-nang-cao"
|
||||||
|
override val availableStates: Set<MangaState> =
|
||||||
|
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED)
|
||||||
|
override val availableSortOrders: Set<SortOrder> = EnumSet.allOf(SortOrder::class.java)
|
||||||
|
|
||||||
|
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
|
||||||
|
val response =
|
||||||
|
when (filter) {
|
||||||
|
is MangaListFilter.Search -> {
|
||||||
|
val url = buildString {
|
||||||
|
append("https://")
|
||||||
|
append(domain)
|
||||||
|
append("/search")
|
||||||
|
append('/')
|
||||||
|
append(page.toString())
|
||||||
|
append('/')
|
||||||
|
append("?keyword=")
|
||||||
|
append(filter.query.urlEncoded())
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = runCatchingCancellable { webClient.httpGet(url) }
|
||||||
|
val exception = result.exceptionOrNull()
|
||||||
|
if (exception is NotFoundException) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
result.getOrThrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
is MangaListFilter.Advanced -> {
|
||||||
|
val url = buildString {
|
||||||
|
append("https://")
|
||||||
|
append(domain)
|
||||||
|
append(listUrl)
|
||||||
|
|
||||||
|
append('/')
|
||||||
|
append(page.toString())
|
||||||
|
append('/')
|
||||||
|
|
||||||
|
val tagQuery = filter.tags.joinToString(",") { it.key }
|
||||||
|
append("?genres=")
|
||||||
|
append(tagQuery)
|
||||||
|
|
||||||
|
val tagQueryExclude = filter.tagsExclude.joinToString(",") { it.key }
|
||||||
|
append("¬Genres=")
|
||||||
|
append(tagQueryExclude)
|
||||||
|
|
||||||
|
append("&sex=All")
|
||||||
|
|
||||||
|
filter.states.oneOrThrowIfMany()?.let {
|
||||||
|
append("&status=")
|
||||||
|
append(
|
||||||
|
when (it) {
|
||||||
|
MangaState.ONGOING -> "on-going"
|
||||||
|
MangaState.FINISHED -> "completed"
|
||||||
|
MangaState.PAUSED -> "on-hold"
|
||||||
|
MangaState.ABANDONED -> "canceled"
|
||||||
|
else -> "-1"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
append("&chapter_count=0")
|
||||||
|
|
||||||
|
append("&sort=")
|
||||||
|
append(
|
||||||
|
when (filter.sortOrder) {
|
||||||
|
SortOrder.UPDATED -> "latest-updated"
|
||||||
|
SortOrder.POPULARITY -> "views"
|
||||||
|
SortOrder.NEWEST -> "new"
|
||||||
|
SortOrder.RATING -> "score"
|
||||||
|
SortOrder.ALPHABETICAL -> "az"
|
||||||
|
SortOrder.ALPHABETICAL_DESC -> "za"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
webClient.httpGet(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
null -> {
|
||||||
|
val url = buildString {
|
||||||
|
append("https://")
|
||||||
|
append(domain)
|
||||||
|
append(listUrl)
|
||||||
|
append('/')
|
||||||
|
append(page.toString())
|
||||||
|
append('/')
|
||||||
|
append("?genres=¬Genres=&sex=All&status=&chapter_count=0&sort=latest-updated")
|
||||||
|
}
|
||||||
|
webClient.httpGet(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val tagMap = getOrCreateTagMap()
|
||||||
|
return parseMangaList(response.parseHtml(), tagMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getOrCreateTagMap(): ArrayMap<String, MangaTag> = mutex.withLock {
|
||||||
|
tagCache?.let { return@withLock it }
|
||||||
|
val doc = webClient.httpGet(listUrl.toAbsoluteUrl(domain)).parseHtml()
|
||||||
|
val tagItems = doc.select("div.genre-item")
|
||||||
|
val result = ArrayMap<String, MangaTag>(tagItems.size)
|
||||||
|
for (item in tagItems) {
|
||||||
|
val title = item.text()
|
||||||
|
val key = item.selectFirstOrThrow("span").attr("data-id")
|
||||||
|
if (key.isNotEmpty() && title.isNotEmpty()) {
|
||||||
|
result[title] = MangaTag(title = title, key = key, source = source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tagCache = result
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
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.MangaParserSource
|
||||||
|
import org.koitharu.kotatsu.parsers.site.zeistmanga.ZeistMangaParser
|
||||||
|
|
||||||
|
|
||||||
|
@MangaSourceParser("MAGERIN", "Magerin", "id")
|
||||||
|
internal class Magerin(context: MangaLoaderContext) :
|
||||||
|
ZeistMangaParser(context, MangaParserSource.MAGERIN, "www.magerin.com")
|
||||||
Loading…
Reference in New Issue