Update jsoup (#15321)
This commit is contained in:
parent
7964dc4613
commit
e1f59a845e
|
@ -21,7 +21,7 @@ coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-androi
|
||||||
injekt-core = { module = "com.github.inorichi.injekt:injekt-core", version = "65b0440" }
|
injekt-core = { module = "com.github.inorichi.injekt:injekt-core", version = "65b0440" }
|
||||||
rxandroid = { module = "io.reactivex:rxandroid", version = "1.2.1" }
|
rxandroid = { module = "io.reactivex:rxandroid", version = "1.2.1" }
|
||||||
rxjava = { module = "io.reactivex:rxjava", version = "1.3.8" }
|
rxjava = { module = "io.reactivex:rxjava", version = "1.3.8" }
|
||||||
jsoup = { module = "org.jsoup:jsoup", version = "1.13.1" }
|
jsoup = { module = "org.jsoup:jsoup", version = "1.15.1" }
|
||||||
okhttp = { module = "com.squareup.okhttp3:okhttp", version = "5.0.0-alpha.11" }
|
okhttp = { module = "com.squareup.okhttp3:okhttp", version = "5.0.0-alpha.11" }
|
||||||
quickjs = { module = "app.cash.quickjs:quickjs-android", version = "0.9.2" }
|
quickjs = { module = "app.cash.quickjs:quickjs-android", version = "0.9.2" }
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ class EpikManga : FMReader("Epik Manga", "https://www.epikmanga.com", "tr") {
|
||||||
}
|
}
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/seri-listesi?type=text", headers)
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/seri-listesi?type=text", headers)
|
||||||
private fun searchMangaParse(response: Response, query: String): MangasPage {
|
private fun searchMangaParse(response: Response, query: String): MangasPage {
|
||||||
val mangas = response.asJsoup().select("div.char.col-lg-4 a")
|
val mangas = response.asJsoup().select("div.char.col-lg-4 a").toList()
|
||||||
.filter { it.text().contains(query, ignoreCase = true) }
|
.filter { it.text().contains(query, ignoreCase = true) }
|
||||||
.map {
|
.map {
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
|
@ -40,7 +40,7 @@ class EpikManga : FMReader("Epik Manga", "https://www.epikmanga.com", "tr") {
|
||||||
return MangasPage(mangas, false)
|
return MangasPage(mangas, false)
|
||||||
}
|
}
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val infoElement = document.select("div.col-md-9 div.row").first()
|
val infoElement = document.select("div.col-md-9 div.row").first()!!
|
||||||
|
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
status = parseStatus(infoElement.select("h4:contains(Durum:)").firstOrNull()?.ownText())
|
status = parseStatus(infoElement.select("h4:contains(Durum:)").firstOrNull()?.ownText())
|
||||||
|
|
|
@ -9,7 +9,7 @@ class KSGroupScans : FMReader("KSGroupScans", "https://ksgroupscans.com", "en")
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element, mangaTitle: String): SChapter {
|
override fun chapterFromElement(element: Element, mangaTitle: String): SChapter {
|
||||||
return SChapter.create().apply {
|
return SChapter.create().apply {
|
||||||
element.select(chapterUrlSelector).first().let {
|
element.select(chapterUrlSelector).first()!!.let {
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
name = element.select(".chapter-name").text()
|
name = element.select(".chapter-name").text()
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
val infoElement: Element = document.select("div#tab1").first()
|
val infoElement: Element = document.select("div#tab1").first()!!
|
||||||
|
|
||||||
manga.author = infoElement.select("table + table tr + tr td a").first()?.text()
|
manga.author = infoElement.select("table + table tr + tr td a").first()?.text()
|
||||||
manga.artist = infoElement.select("table + table tr + tr td + td a").first()?.text()
|
manga.artist = infoElement.select("table + table tr + tr td + td a").first()?.text()
|
||||||
|
|
|
@ -10,7 +10,7 @@ import org.jsoup.nodes.Document
|
||||||
|
|
||||||
class SayTruyen : FMReader("Say Truyen", "https://saytruyenvip.com", "vi") {
|
class SayTruyen : FMReader("Say Truyen", "https://saytruyenvip.com", "vi") {
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val info = document.select("div.row").first()
|
val info = document.select("div.row").first()!!
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
author = info.select("div.row li:has(b:contains(Tác giả)) small").text()
|
author = info.select("div.row li:has(b:contains(Tác giả)) small").text()
|
||||||
genre = info.select("div.row li:has(b:contains(Thể loại)) small a").joinToString { it.text() }
|
genre = info.select("div.row li:has(b:contains(Thể loại)) small a").joinToString { it.text() }
|
||||||
|
|
|
@ -24,8 +24,8 @@ class UniversoHentai : Gattsu(
|
||||||
override fun latestUpdatesSelector() = "div.meio div.videos div.video a[href^=$baseUrl]:not(:has(span.selo-hd))"
|
override fun latestUpdatesSelector() = "div.meio div.videos div.video a[href^=$baseUrl]:not(:has(span.selo-hd))"
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
|
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("span.video-titulo").text().trim()
|
title = element.selectFirst("span.video-titulo")!!.text().trim()
|
||||||
thumbnail_url = element.selectFirst("img.wp-post-image").attr("src")
|
thumbnail_url = element.selectFirst("img.wp-post-image")!!.attr("src")
|
||||||
setUrlWithoutDomain(element.attr("href"))
|
setUrlWithoutDomain(element.attr("href"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ class UniversoHentai : Gattsu(
|
||||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||||
name = "Capítulo único"
|
name = "Capítulo único"
|
||||||
scanlator = element.select("ul.paginaPostItens li:contains(Tradutor) a").firstOrNull()?.text()
|
scanlator = element.select("ul.paginaPostItens li:contains(Tradutor) a").firstOrNull()?.text()
|
||||||
date_upload = element.ownerDocument().select("meta[property=article:published_time]").firstOrNull()
|
date_upload = element.ownerDocument()!!.select("meta[property=article:published_time]").firstOrNull()
|
||||||
?.attr("content")
|
?.attr("content")
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
.toDate()
|
.toDate()
|
||||||
setUrlWithoutDomain(element.selectFirst("a[title=Abrir galeria]").attr("href"))
|
setUrlWithoutDomain(element.selectFirst("a[title=Abrir galeria]")!!.attr("href"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListSelector() = "div.meio div.galeria div.galeria-foto a img"
|
override fun pageListSelector() = "div.meio div.galeria div.galeria-foto a img"
|
||||||
|
|
|
@ -8,7 +8,7 @@ class LynxScans : Genkan("LynxScans", "https://lynxscans.com", "en", "/web/comic
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val pages = mutableListOf<Page>()
|
val pages = mutableListOf<Page>()
|
||||||
|
|
||||||
val allImages = document.select("div#pages-container + script").first().data()
|
val allImages = document.select("div#pages-container + script").first()!!.data()
|
||||||
.substringAfter("[").substringBefore("];")
|
.substringAfter("[").substringBefore("];")
|
||||||
.replace(Regex("""["\\]"""), "")
|
.replace(Regex("""["\\]"""), "")
|
||||||
.split(",/")
|
.split(",/")
|
||||||
|
|
|
@ -23,9 +23,9 @@ class ComicGardo : GigaViewer(
|
||||||
override fun popularMangaSelector(): String = "ul.series-section-list li.series-section-item > a"
|
override fun popularMangaSelector(): String = "ul.series-section-list li.series-section-item > a"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("h5.series-title").text()
|
title = element.selectFirst("h5.series-title")!!.text()
|
||||||
thumbnail_url = element.selectFirst("div.thumb img").attr("data-src")
|
thumbnail_url = element.selectFirst("div.thumb img")!!.attr("data-src")
|
||||||
setUrlWithoutDomain(element.attr("href"))
|
setUrlWithoutDomain(element.attr("href")!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCollections(): List<Collection> = listOf(
|
override fun getCollections(): List<Collection> = listOf(
|
||||||
|
|
|
@ -27,8 +27,8 @@ class KurageBunch : GigaViewer(
|
||||||
override fun popularMangaSelector(): String = "ul.page-series-list li div.item-box"
|
override fun popularMangaSelector(): String = "ul.page-series-list li div.item-box"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("a.series-data-container h4").text()
|
title = element.selectFirst("a.series-data-container h4")!!.text()
|
||||||
thumbnail_url = element.selectFirst("a.series-thumb img").attr("data-src")
|
thumbnail_url = element.selectFirst("a.series-thumb img")!!.attr("data-src")
|
||||||
setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
|
setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@ class MagazinePocket : GigaViewer(
|
||||||
override fun popularMangaSelector(): String = "ul.daily-series li.daily-series-item > a"
|
override fun popularMangaSelector(): String = "ul.daily-series li.daily-series-item > a"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("h4.daily-series-title").text()
|
title = element.selectFirst("h4.daily-series-title")!!.text()
|
||||||
thumbnail_url = element.selectFirst("div.daily-series-thumb img").attr("data-src")
|
thumbnail_url = element.selectFirst("div.daily-series-thumb img")!!.attr("data-src")
|
||||||
setUrlWithoutDomain(element.attr("href"))
|
setUrlWithoutDomain(element.attr("href")!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesSelector(): String = "section.daily.$dayOfWeek " + popularMangaSelector()
|
override fun latestUpdatesSelector(): String = "section.daily.$dayOfWeek " + popularMangaSelector()
|
||||||
|
|
|
@ -23,8 +23,8 @@ class TonariNoYoungJump : GigaViewer(
|
||||||
override fun popularMangaSelector(): String = "ul.series-table-list li.subpage-table-list-item > a"
|
override fun popularMangaSelector(): String = "ul.series-table-list li.subpage-table-list-item > a"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("h4.title").text()
|
title = element.selectFirst("h4.title")!!.text()
|
||||||
thumbnail_url = element.selectFirst("div.subpage-image-wrapper img").attr("data-src")
|
thumbnail_url = element.selectFirst("div.subpage-image-wrapper img")!!.attr("data-src")
|
||||||
.replace("{width}", "528")
|
.replace("{width}", "528")
|
||||||
.replace("{height}", "528")
|
.replace("{height}", "528")
|
||||||
setUrlWithoutDomain(element.attr("href"))
|
setUrlWithoutDomain(element.attr("href"))
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Manga18fx : Madara(
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
loadGenres(document)
|
loadGenres(document)
|
||||||
val block = document.selectFirst(Evaluator.Class("trending-block"))
|
val block = document.selectFirst(Evaluator.Class("trending-block"))!!
|
||||||
val mangas = block.select(Evaluator.Tag("a")).map(::mangaFromElement)
|
val mangas = block.select(Evaluator.Tag("a")).map(::mangaFromElement)
|
||||||
return MangasPage(mangas, false)
|
return MangasPage(mangas, false)
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ class Manga18fx : Madara(
|
||||||
private fun mangaFromElement(element: Element) = SManga.create().apply {
|
private fun mangaFromElement(element: Element) = SManga.create().apply {
|
||||||
url = element.attr("href")
|
url = element.attr("href")
|
||||||
title = element.attr("title")
|
title = element.attr("title")
|
||||||
thumbnail_url = element.selectFirst(Evaluator.Tag("img")).attr("data-src")
|
thumbnail_url = element.selectFirst(Evaluator.Tag("img"))!!.attr("data-src")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/page/$page", headers)
|
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/page/$page", headers)
|
||||||
|
@ -54,9 +54,9 @@ class Manga18fx : Madara(
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
loadGenres(document)
|
loadGenres(document)
|
||||||
val mangas = document.select(Evaluator.Class("bsx-item")).map {
|
val mangas = document.select(Evaluator.Class("bsx-item")).map {
|
||||||
mangaFromElement(it.selectFirst(Evaluator.Tag("a")))
|
mangaFromElement(it.selectFirst(Evaluator.Tag("a"))!!)
|
||||||
}
|
}
|
||||||
val nextButton = document.selectFirst(Evaluator.Class("next"))
|
val nextButton = document.selectFirst(Evaluator.Class("next"))!!
|
||||||
val hasNextPage = nextButton != null && nextButton.hasClass("disabled").not()
|
val hasNextPage = nextButton != null && nextButton.hasClass("disabled").not()
|
||||||
return MangasPage(mangas, hasNextPage)
|
return MangasPage(mangas, hasNextPage)
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ class Manga18fx : Madara(
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val container = document.selectFirst(Evaluator.Class("row-content-chapter"))
|
val container = document.selectFirst(Evaluator.Class("row-content-chapter"))!!
|
||||||
return container.children().map(::chapterFromElement)
|
return container.children().map(::chapterFromElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ class MangaLeveling : Madara("Manga Leveling", "https://mangaleveling.com", "en"
|
||||||
chapter.url = urlElement.attr("abs:href").let {
|
chapter.url = urlElement.attr("abs:href").let {
|
||||||
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
|
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
|
||||||
}
|
}
|
||||||
chapter.name = urlElement.selectFirst("span").text()
|
chapter.name = urlElement.selectFirst("span")!!.text()
|
||||||
}
|
}
|
||||||
// Dates can be part of a "new" graphic or plain text
|
// Dates can be part of a "new" graphic or plain text
|
||||||
// Added "title" alternative
|
// Added "title" alternative
|
||||||
|
|
|
@ -16,7 +16,7 @@ class MMScans : Madara("MMScans", "https://mm-scans.org", "en") {
|
||||||
with(element) {
|
with(element) {
|
||||||
select(popularMangaUrlSelector).first()?.let {
|
select(popularMangaUrlSelector).first()?.let {
|
||||||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
manga.title = it.selectFirst("h3").ownText()
|
manga.title = it.selectFirst("h3")!!.ownText()
|
||||||
}
|
}
|
||||||
|
|
||||||
select("img").first()?.let {
|
select("img").first()?.let {
|
||||||
|
@ -35,7 +35,7 @@ class MMScans : Madara("MMScans", "https://mm-scans.org", "en") {
|
||||||
chapter.url = urlElement.attr("abs:href").let {
|
chapter.url = urlElement.attr("abs:href").let {
|
||||||
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
|
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
|
||||||
}
|
}
|
||||||
chapter.name = urlElement.selectFirst(".chapter-title-date p").text()
|
chapter.name = urlElement.selectFirst(".chapter-title-date p")!!.text()
|
||||||
}
|
}
|
||||||
chapter.date_upload = parseChapterDate(select(chapterDateSelector()).firstOrNull()?.text())
|
chapter.date_upload = parseChapterDate(select(chapterDateSelector()).firstOrNull()?.text())
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,16 +62,16 @@ class Vomic : MangabzTheme("vomic", ""), ConfigurableSource {
|
||||||
|
|
||||||
val mangas = buildList {
|
val mangas = buildList {
|
||||||
// ranking sidebar
|
// ranking sidebar
|
||||||
addAll(document.selectFirst(Evaluator.Class("rank-list")).children())
|
addAll(document.selectFirst(Evaluator.Class("rank-list"))!!.children())
|
||||||
// carousel list
|
// carousel list
|
||||||
addAll(document.selectFirst(Evaluator.Class("carousel-right-list")).children())
|
addAll(document.selectFirst(Evaluator.Class("carousel-right-list"))!!.children())
|
||||||
// recommend list
|
// recommend list
|
||||||
addAll(document.select(Evaluator.Class("index-manga-item")))
|
addAll(document.select(Evaluator.Class("index-manga-item"))!!)
|
||||||
}.map { element ->
|
}.map { element ->
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
title = element.selectFirst(paragraph).text()
|
title = element.selectFirst(paragraph)!!.text()
|
||||||
url = element.selectFirst(link).attr("href")
|
url = element.selectFirst(link)!!.attr("href")
|
||||||
thumbnail_url = element.selectFirst(image).attr("src")
|
thumbnail_url = element.selectFirst(image)!!.attr("src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,11 +23,11 @@ class ReadAttackOnTitanShingekiNoKyojinManga : MangaCatalog("Read Attack on Tita
|
||||||
override fun chapterListSelector(): String = "div.w-full div.grid div.col-span-3"
|
override fun chapterListSelector(): String = "div.w-full div.grid div.col-span-3"
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||||
val urlElemnt = element.selectFirst("a")
|
val urlElement = element.selectFirst("a")!!
|
||||||
name = listOfNotNull(
|
name = listOfNotNull(
|
||||||
urlElemnt.text(),
|
urlElement.text(),
|
||||||
element.selectFirst("div.text-xs").text().takeUnless { it.isBlank() },
|
element.selectFirst("div.text-xs")!!.text().takeUnless { it.isBlank() },
|
||||||
).joinToString(" - ") { it.trim() }
|
).joinToString(" - ") { it.trim() }
|
||||||
url = urlElemnt.attr("abs:href")
|
url = urlElement.attr("abs:href")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,10 +58,10 @@ class MangaRaw : MangaRawTheme("MangaRaw", ""), ConfigurableSource {
|
||||||
GET("$baseUrl/?s=$query&page=$page", headers)
|
GET("$baseUrl/?s=$query&page=$page", headers)
|
||||||
|
|
||||||
override fun Document.getSanitizedDetails(): Element =
|
override fun Document.getSanitizedDetails(): Element =
|
||||||
selectFirst(selectors.detailsSelector).apply {
|
selectFirst(selectors.detailsSelector)!!.apply {
|
||||||
val recommendClass = selectors.recommendClass
|
val recommendClass = selectors.recommendClass
|
||||||
children().find { it.hasClass(recommendClass) }?.remove()
|
children().find { it.hasClass(recommendClass) }?.remove()
|
||||||
selectFirst(Evaluator.Class("list-scoll")).remove()
|
selectFirst(Evaluator.Class("list-scoll"))!!.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListSelector() = ".list-scoll a"
|
override fun chapterListSelector() = ".list-scoll a"
|
||||||
|
|
|
@ -28,8 +28,8 @@ class SyoSetu : MangaRawTheme("SyoSetu", "https://syosetu.top") {
|
||||||
GET("$baseUrl/page/$page?s=$query")
|
GET("$baseUrl/page/$page?s=$query")
|
||||||
|
|
||||||
override fun Document.getSanitizedDetails(): Element =
|
override fun Document.getSanitizedDetails(): Element =
|
||||||
selectFirst(Evaluator.Tag("article")).selectFirst(Evaluator.Class("content-wrap-inner")).apply {
|
selectFirst(Evaluator.Tag("article"))!!.selectFirst(Evaluator.Class("content-wrap-inner"))!!.apply {
|
||||||
selectFirst(Evaluator.Class("chaplist")).remove()
|
selectFirst(Evaluator.Class("chaplist"))!!.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListSelector() = ".chaplist a"
|
override fun chapterListSelector() = ".chaplist a"
|
||||||
|
|
|
@ -26,9 +26,9 @@ class Seemangas : MangaSar(
|
||||||
override fun popularMangaSelector() = "ul.sidebar-popular li.popular-treending"
|
override fun popularMangaSelector() = "ul.sidebar-popular li.popular-treending"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("h4.title").text()
|
title = element.selectFirst("h4.title")!!.text()
|
||||||
thumbnail_url = element.selectFirst("div.tumbl img").attr("data-lazy-src")
|
thumbnail_url = element.selectFirst("div.tumbl img")!!.attr("data-lazy-src")
|
||||||
setUrlWithoutDomain(element.selectFirst("a").attr("abs:href"))
|
setUrlWithoutDomain(element.selectFirst("a")!!.attr("abs:href"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
|
@ -58,15 +58,15 @@ class Seemangas : MangaSar(
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val infoElement = document.selectFirst("div.box-single:has(div.mangapage)")
|
val infoElement = document.selectFirst("div.box-single:has(div.mangapage)")!!
|
||||||
|
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
title = infoElement.selectFirst("h1.kw-title").text()
|
title = infoElement.selectFirst("h1.kw-title")!!.text()
|
||||||
author = infoElement.selectFirst("div.mdq.author").text().trim()
|
author = infoElement.selectFirst("div.mdq.author")!!.text().trim()
|
||||||
description = infoElement.selectFirst("div.sinopse-page").text()
|
description = infoElement.selectFirst("div.sinopse-page")!!.text()
|
||||||
genre = infoElement.select("div.generos a.widget-btn").joinToString { it.text() }
|
genre = infoElement.select("div.generos a.widget-btn")!!.joinToString { it.text() }
|
||||||
status = infoElement.selectFirst("span.mdq").text().toStatus()
|
status = infoElement.selectFirst("span.mdq")!!.text().toStatus()
|
||||||
thumbnail_url = infoElement.selectFirst("div.thumb img").attr("abs:data-lazy-src")
|
thumbnail_url = infoElement.selectFirst("div.thumb img")!!.attr("abs:data-lazy-src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun chapterListPaginatedRequest(mangaUrl: String, page: Int): Request {
|
override fun chapterListPaginatedRequest(mangaUrl: String, page: Int): Request {
|
||||||
|
|
|
@ -66,7 +66,7 @@ open class FlameScans(
|
||||||
return super.pageListParse(document)
|
return super.pageListParse(document)
|
||||||
}
|
}
|
||||||
|
|
||||||
return document.select("#readerarea p:has(img), $composedSelector")
|
return document.select("#readerarea p:has(img), $composedSelector").toList()
|
||||||
.filter {
|
.filter {
|
||||||
it.select("img").all { imgEl ->
|
it.select("img").all { imgEl ->
|
||||||
imgEl.attr("abs:src").isNullOrEmpty().not()
|
imgEl.attr("abs:src").isNullOrEmpty().not()
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Kiryuu : MangaThemesia("Kiryuu", "https://kiryuu.id", "id", dateFormat = S
|
||||||
|
|
||||||
// manga details
|
// manga details
|
||||||
override fun mangaDetailsParse(document: Document) = super.mangaDetailsParse(document).apply {
|
override fun mangaDetailsParse(document: Document) = super.mangaDetailsParse(document).apply {
|
||||||
title = document.selectFirst(seriesThumbnailSelector).attr("title")
|
title = document.selectFirst(seriesThumbnailSelector)!!.attr("title")
|
||||||
}
|
}
|
||||||
|
|
||||||
override val hasProjectPage = true
|
override val hasProjectPage = true
|
||||||
|
|
|
@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.jsonArray
|
import kotlinx.serialization.json.jsonArray
|
||||||
import kotlinx.serialization.json.jsonObject
|
import kotlinx.serialization.json.jsonObject
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
|
@ -62,7 +61,7 @@ class KomikCast : MangaThemesia(
|
||||||
override fun searchMangaSelector() = "div.list-update_item"
|
override fun searchMangaSelector() = "div.list-update_item"
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element) = super.searchMangaFromElement(element).apply {
|
override fun searchMangaFromElement(element: Element) = super.searchMangaFromElement(element).apply {
|
||||||
title = element.selectFirst("h3.title").ownText()
|
title = element.selectFirst("h3.title")!!.ownText()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val seriesDetailsSelector = "div.komik_info:has(.komik_info-content)"
|
override val seriesDetailsSelector = "div.komik_info:has(.komik_info-content)"
|
||||||
|
@ -78,7 +77,7 @@ class KomikCast : MangaThemesia(
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
val urlElements = element.select("a")
|
val urlElements = element.select("a")
|
||||||
setUrlWithoutDomain(urlElements.attr("href"))
|
setUrlWithoutDomain(urlElements.attr("href"))
|
||||||
name = element.select(".lch a, .chapternum").text().ifBlank { urlElements.first().text() }
|
name = element.select(".lch a, .chapternum")!!.text().ifBlank { urlElements.first()!!.text() }
|
||||||
date_upload = parseChapterDate2(element.select(".chapter-link-time").text())
|
date_upload = parseChapterDate2(element.select(".chapter-link-time").text())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +129,7 @@ class KomikCast : MangaThemesia(
|
||||||
var imageServer = "cdn"
|
var imageServer = "cdn"
|
||||||
if (!imageList.containsKey(imageServer)) imageServer = imageList.keys.first()
|
if (!imageList.containsKey(imageServer)) imageServer = imageList.keys.first()
|
||||||
val imageElement = imageList[imageServer]!!.jsonArray.joinToString("")
|
val imageElement = imageList[imageServer]!!.jsonArray.joinToString("")
|
||||||
doc = Jsoup.parse(json.decodeFromString(imageElement))
|
doc = Jsoup.parse(imageElement)
|
||||||
cssQuery = "img.size-full"
|
cssQuery = "img.size-full"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ class MangaRawOrg : MangaThemesia("Manga Raw.org", "https://mangaraw.org", "ja")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pageListParse(response: Response, chapterUrl: String): List<Page> {
|
private fun pageListParse(response: Response, chapterUrl: String): List<Page> {
|
||||||
return response.asJsoup().select("span.page-link").first().ownText().substringAfterLast(" ").toInt()
|
return response.asJsoup().select("span.page-link").first()!!.ownText().substringAfterLast(" ").toInt()
|
||||||
.let { lastNum -> IntRange(1, lastNum) }
|
.let { lastNum -> IntRange(1, lastNum) }
|
||||||
.map { num -> Page(num, "$chapterUrl/$num") }
|
.map { num -> Page(num, "$chapterUrl/$num") }
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ class MangaSwat : MangaThemesia(
|
||||||
override val seriesStatusSelector = "span:contains(الحالة)"
|
override val seriesStatusSelector = "span:contains(الحالة)"
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val scriptContent = document.selectFirst("script:containsData(ts_reader)").data()
|
val scriptContent = document.selectFirst("script:containsData(ts_reader)")!!.data()
|
||||||
val jsonString = scriptContent.substringAfter("ts_reader.run(").substringBefore(");")
|
val jsonString = scriptContent.substringAfter("ts_reader.run(").substringBefore(");")
|
||||||
val tsReader = json.decodeFromString<TSReader>(jsonString)
|
val tsReader = json.decodeFromString<TSReader>(jsonString)
|
||||||
val imageUrls = tsReader.sources.firstOrNull()?.images ?: return emptyList()
|
val imageUrls = tsReader.sources.firstOrNull()?.images ?: return emptyList()
|
||||||
|
|
|
@ -10,7 +10,7 @@ class MangKomik : MangaThemesia("MangKomik", "https://mangkomik.net", "id") {
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
// Get external JS for image urls
|
// Get external JS for image urls
|
||||||
val scriptEl = document.selectFirst("script[data-minify]")
|
val scriptEl = document.selectFirst("script[data-minify]")!!
|
||||||
val scriptUrl = scriptEl?.attr("src")
|
val scriptUrl = scriptEl?.attr("src")
|
||||||
if (scriptUrl.isNullOrEmpty()) {
|
if (scriptUrl.isNullOrEmpty()) {
|
||||||
return super.pageListParse(document)
|
return super.pageListParse(document)
|
||||||
|
|
|
@ -51,7 +51,7 @@ class ManhwaFreak : MangaThemesia("Manhwa Freak", "https://manhwafreak.com", "en
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
val urlElements = element.select("a")
|
val urlElements = element.select("a")
|
||||||
setUrlWithoutDomain(urlElements.attr("href"))
|
setUrlWithoutDomain(urlElements.attr("href"))
|
||||||
name = element.select(".chapter-info p:nth-child(1)").text().ifBlank { urlElements.first().text() }
|
name = element.select(".chapter-info p:nth-child(1)")!!.text().ifBlank { urlElements.first()!!.text() }
|
||||||
date_upload = element.selectFirst(".chapter-info p:nth-child(2)")?.text().parseChapterDate()
|
date_upload = element.selectFirst(".chapter-info p:nth-child(2)")?.text().parseChapterDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class xCaliBRScans : MangaThemesia("xCaliBR Scans", "https://xcalibrscans.com",
|
||||||
.forEach { element ->
|
.forEach { element ->
|
||||||
when {
|
when {
|
||||||
element.tagName() == "p" -> {
|
element.tagName() == "p" -> {
|
||||||
val imgUrl = element.selectFirst("img").imgAttr()
|
val imgUrl = element.selectFirst("img")!!.imgAttr()
|
||||||
imgUrls.add(imgUrl)
|
imgUrls.add(imgUrl)
|
||||||
}
|
}
|
||||||
element.tagName() == "div" && element.hasClass("kage") -> {
|
element.tagName() == "div" && element.hasClass("kage") -> {
|
||||||
|
|
|
@ -58,12 +58,12 @@ class AnimaRegia : MMRCMS("AnimaRegia", "https://animaregia.net", "pt-BR") {
|
||||||
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
|
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
|
||||||
title = document.selectFirst("h1.widget-title").text()
|
title = document.selectFirst("h1.widget-title")!!.text()
|
||||||
thumbnail_url = coverGuess(
|
thumbnail_url = coverGuess(
|
||||||
document.select("div.col-sm-5 img.img-thumbnail").firstOrNull()?.attr("abs:src"),
|
document.select("div.col-sm-5 img.img-thumbnail").firstOrNull()?.attr("abs:src"),
|
||||||
document.location(),
|
document.location(),
|
||||||
)
|
)
|
||||||
description = document.select("div.row div.well p").text().trim()
|
description = document.select("div.row div.well p")!!.text().trim()
|
||||||
|
|
||||||
for (element in document.select("div.col-sm-5 ul.list-group li.list-group-item")) {
|
for (element in document.select("div.col-sm-5 ul.list-group li.list-group-item")) {
|
||||||
when (element.text().trim().lowercase(BRAZILIAN_LOCALE).substringBefore(":")) {
|
when (element.text().trim().lowercase(BRAZILIAN_LOCALE).substringBefore(":")) {
|
||||||
|
@ -94,7 +94,7 @@ class AnimaRegia : MMRCMS("AnimaRegia", "https://animaregia.net", "pt-BR") {
|
||||||
.joinToString(" & ") { it.text().trim() }
|
.joinToString(" & ") { it.text().trim() }
|
||||||
date_upload = el.select("div.col-md-4").firstOrNull()
|
date_upload = el.select("div.col-md-4").firstOrNull()
|
||||||
?.text()?.removeSuffix("Download")?.toDate() ?: 0L
|
?.text()?.removeSuffix("Download")?.toDate() ?: 0L
|
||||||
setUrlWithoutDomain(el.select("h5.chapter-title-rtl a").first().attr("href"))
|
setUrlWithoutDomain(el.select("h5.chapter-title-rtl a").first()!!.attr("href"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ class FallenAngels : MMRCMS("Fallen Angels", "https://manga.fascans.com", "en")
|
||||||
override fun nullableChapterFromElement(element: Element): SChapter? {
|
override fun nullableChapterFromElement(element: Element): SChapter? {
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
|
|
||||||
val titleWrapper = element.select("[class^=chapter-title-rtl]").first()
|
val titleWrapper = element.select("[class^=chapter-title-rtl]").first()!!
|
||||||
val chapterElement = titleWrapper.getElementsByTag("a")
|
val chapterElement = titleWrapper.getElementsByTag("a")!!
|
||||||
val url = chapterElement.attr("href")
|
val url = chapterElement.attr("href")
|
||||||
|
|
||||||
chapter.url = getUrlWithoutBaseUrl(url)
|
chapter.url = getUrlWithoutBaseUrl(url)
|
||||||
|
@ -28,7 +28,7 @@ class FallenAngels : MMRCMS("Fallen Angels", "https://manga.fascans.com", "en")
|
||||||
val chapterText = chapterElement.text()
|
val chapterText = chapterElement.text()
|
||||||
val numberRegex = Regex("""[1-9]\d*(\.\d+)*""")
|
val numberRegex = Regex("""[1-9]\d*(\.\d+)*""")
|
||||||
val chapterNumber = numberRegex.find(chapterText)?.value.orEmpty()
|
val chapterNumber = numberRegex.find(chapterText)?.value.orEmpty()
|
||||||
val chapterTitle = titleWrapper.getElementsByTag("em").text()
|
val chapterTitle = titleWrapper.getElementsByTag("em")!!.text()
|
||||||
chapter.name = "Chapter $chapterNumber : $chapterTitle"
|
chapter.name = "Chapter $chapterNumber : $chapterTitle"
|
||||||
|
|
||||||
// Parse date
|
// Parse date
|
||||||
|
|
|
@ -105,7 +105,7 @@ class HenChan : MultiChan("HenChan", "http://y.hchan.live", "ru"), ConfigurableS
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
val manga = super.popularMangaFromElement(element)
|
val manga = super.popularMangaFromElement(element)
|
||||||
manga.thumbnail_url = element.select("img").first().attr("src").getHQThumbnail()
|
manga.thumbnail_url = element.select("img").first()!!.attr("src").getHQThumbnail()
|
||||||
return manga
|
return manga
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,12 +40,12 @@ class WuqiManga : SinMH("57漫画", "http://www.wuqimh.net") {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = super.mangaDetailsParse(document).apply {
|
override fun mangaDetailsParse(document: Document) = super.mangaDetailsParse(document).apply {
|
||||||
val comment = document.selectFirst(".book-title > h2").text()
|
val comment = document.selectFirst(".book-title > h2")!!.text()
|
||||||
if (comment.isNotEmpty()) description = "$comment\n\n$description"
|
if (comment.isNotEmpty()) description = "$comment\n\n$description"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParseDefaultGenre(document: Document, detailsList: Element): String =
|
override fun mangaDetailsParseDefaultGenre(document: Document, detailsList: Element): String =
|
||||||
document.selectFirst("div.crumb").select("a[href^=/list/]")
|
document.selectFirst("div.crumb")!!.select("a[href^=/list/]")
|
||||||
.map { it.text().removeSuffix("年").removeSuffix("漫画") }
|
.map { it.text().removeSuffix("年").removeSuffix("漫画") }
|
||||||
.filter { it.isNotEmpty() }.joinToString(", ")
|
.filter { it.isNotEmpty() }.joinToString(", ")
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ class WuqiManga : SinMH("57漫画", "http://www.wuqimh.net") {
|
||||||
override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url, headers)
|
override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url, headers)
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val script = document.selectFirst("body > script").html()
|
val script = document.selectFirst("body > script")!!.html()
|
||||||
val unpacked = Unpacker.unpack(script, ":[", "]")
|
val unpacked = Unpacker.unpack(script, ":[", "]")
|
||||||
.ifEmpty { return emptyList() }
|
.ifEmpty { return emptyList() }
|
||||||
.replace("\\", "")
|
.replace("\\", "")
|
||||||
|
@ -85,7 +85,7 @@ class WuqiManga : SinMH("57漫画", "http://www.wuqimh.net") {
|
||||||
document.select(Evaluator.Class("filter")).forEach { row ->
|
document.select(Evaluator.Class("filter")).forEach { row ->
|
||||||
val tags = row.select(linkSelector)
|
val tags = row.select(linkSelector)
|
||||||
if (tags.isEmpty()) return@forEach
|
if (tags.isEmpty()) return@forEach
|
||||||
val name = row.selectFirst(labelSelector).text().removeSuffix(":")
|
val name = row.selectFirst(labelSelector)!!.text().removeSuffix(":")
|
||||||
if (!filterMap.containsKey(name)) {
|
if (!filterMap.containsKey(name)) {
|
||||||
filterMap[name] = LinkedHashMap(tags.size * 2)
|
filterMap[name] = LinkedHashMap(tags.size * 2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,14 +27,14 @@ class TruyenChon : WPComics("TruyenChon", "http://truyenchon.com", "vi", SimpleD
|
||||||
title = it.text().replace("Truyện tranh ", "")
|
title = it.text().replace("Truyện tranh ", "")
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
}
|
}
|
||||||
thumbnail_url = imageOrNull(element.select("div.image:first-of-type img").first())
|
thumbnail_url = imageOrNull(element.select("div.image:first-of-type img").first()!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
override fun searchMangaFromElement(element: Element): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
title = element.attr("title").replace("Truyện tranh ", "")
|
title = element.attr("title").replace("Truyện tranh ", "")
|
||||||
setUrlWithoutDomain(element.attr("href"))
|
setUrlWithoutDomain(element.attr("href"))
|
||||||
thumbnail_url = imageOrNull(element.select("img").first())
|
thumbnail_url = imageOrNull(element.select("img").first()!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class DatGarScanlation : ZeistManga("DatGarScanlation", "https://datgarscanlatio
|
||||||
var script = doc.selectFirst(scriptSelector)
|
var script = doc.selectFirst(scriptSelector)
|
||||||
|
|
||||||
if (script == null) {
|
if (script == null) {
|
||||||
script = doc.selectFirst(altScriptSelector)
|
script = doc.selectFirst(altScriptSelector)!!
|
||||||
chapterRegex = altChapterFeedRegex
|
chapterRegex = altChapterFeedRegex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ class MangaAiLand : ZeistManga("Manga Ai Land", "https://manga-ai-land.blogspot.
|
||||||
override val imgSelectorAttr = "href"
|
override val imgSelectorAttr = "href"
|
||||||
|
|
||||||
override fun getChaptersUrl(doc: Document): String {
|
override fun getChaptersUrl(doc: Document): String {
|
||||||
val script = doc.selectFirst(scriptSelector).attr("src")
|
val script = doc.selectFirst(scriptSelector)!!.attr("src")
|
||||||
val feed = chapterFeedRegex
|
val feed = chapterFeedRegex
|
||||||
.find(script)
|
.find(script)
|
||||||
?.groupValues?.get(1)
|
?.groupValues?.get(1)
|
||||||
|
|
|
@ -49,7 +49,7 @@ class SekteKomik : ZManga("Sekte Komik", "https://sektekomik.com", "id") {
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
override fun latestUpdatesFromElement(element: Element): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
setUrlWithoutDomain(element.select("div.flexbox4-content a").attr("href"))
|
setUrlWithoutDomain(element.select("div.flexbox4-content a").attr("href"))
|
||||||
title = element.select("div.flexbox4-side .title").first().text()
|
title = element.select("div.flexbox4-side .title").first()!!.text()
|
||||||
thumbnail_url = element.select("img").attr("abs:src")
|
thumbnail_url = element.select("img").attr("abs:src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ class SekteKomik : ZManga("Sekte Komik", "https://sektekomik.com", "id") {
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
override fun searchMangaFromElement(element: Element): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
setUrlWithoutDomain(element.select("div.flexbox2-content a").attr("href"))
|
setUrlWithoutDomain(element.select("div.flexbox2-content a").attr("href"))
|
||||||
title = element.select("div.flexbox2-title > span").first().text()
|
title = element.select("div.flexbox2-title > span").first()!!.text()
|
||||||
thumbnail_url = element.select("img").attr("abs:src")
|
thumbnail_url = element.select("img").attr("abs:src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,9 +142,9 @@ open class A3Manga(
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
setUrlWithoutDomain(element.select("a").attr("href"))
|
||||||
name = element.select("a .hidden-sm").text()
|
name = element.select("a .hidden-sm").text()
|
||||||
date_upload = kotlin.runCatching {
|
date_upload = runCatching {
|
||||||
dateFormat.parse(element.select("td").last().text())?.time
|
dateFormat.parse(element.select("td").last()!!.text())?.time
|
||||||
}.getOrNull() ?: 0L
|
}.getOrNull() ?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
|
|
|
@ -29,9 +29,9 @@ abstract class BakaManga(
|
||||||
".li_truyen"
|
".li_truyen"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
setUrlWithoutDomain(element.selectFirst("a").absUrl("href"))
|
setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
|
||||||
title = element.selectFirst(".name").text()
|
title = element.selectFirst(".name")!!.text()
|
||||||
thumbnail_url = element.selectFirst("img").absUrl("src")
|
thumbnail_url = element.selectFirst("img")!!.absUrl("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector(): String? =
|
override fun popularMangaNextPageSelector(): String? =
|
||||||
|
@ -47,7 +47,7 @@ abstract class BakaManga(
|
||||||
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
||||||
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
|
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
|
||||||
val url = "$baseUrl/category/${genreFilter.toUriPart()}/page/$page"
|
val url = "$baseUrl/category/${genreFilter.toUriPart()}/page/$page"
|
||||||
GET(url.toString(), headers)
|
GET(url, headers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +75,8 @@ abstract class BakaManga(
|
||||||
|
|
||||||
// Details
|
// Details
|
||||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||||
val info = document.selectFirst(".box_info")
|
val info = document.selectFirst(".box_info")!!
|
||||||
title = info.selectFirst("h1").text()
|
title = info.selectFirst("h1")!!.text()
|
||||||
artist = info.select(".info-item:contains(Artist:) > a").joinToString { it.text() }
|
artist = info.select(".info-item:contains(Artist:) > a").joinToString { it.text() }
|
||||||
|
|
||||||
val descElements = info.select(".story-detail-info:matchText")
|
val descElements = info.select(".story-detail-info:matchText")
|
||||||
|
@ -99,12 +99,12 @@ abstract class BakaManga(
|
||||||
}
|
}
|
||||||
|
|
||||||
genre = info.select(".post-categories > li > a").joinToString { it.text() }
|
genre = info.select(".post-categories > li > a").joinToString { it.text() }
|
||||||
status = info.selectFirst(".info-item:contains(Status:)").text()
|
status = info.selectFirst(".info-item:contains(Status:)")!!.text()
|
||||||
.removePrefix("Status:")
|
.removePrefix("Status:")
|
||||||
.trim()
|
.trim()
|
||||||
.toStatus()
|
.toStatus()
|
||||||
|
|
||||||
thumbnail_url = info.selectFirst(".box_info img").absUrl("src")
|
thumbnail_url = info.selectFirst(".box_info img")!!.absUrl("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chapters
|
// Chapters
|
||||||
|
@ -115,14 +115,14 @@ abstract class BakaManga(
|
||||||
".list-chapters > .list-chapters > .box_list > .chapter-item"
|
".list-chapters > .list-chapters > .box_list > .chapter-item"
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||||
setUrlWithoutDomain(element.selectFirst("a").absUrl("href"))
|
setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
|
||||||
name = element.selectFirst(".chap_name").text()
|
name = element.selectFirst(".chap_name")!!.text()
|
||||||
chapter_number = name
|
chapter_number = name
|
||||||
.substringAfter(' ')
|
.substringAfter(' ')
|
||||||
.substringBefore(' ')
|
.substringBefore(' ')
|
||||||
.toFloatOrNull() ?: -1f
|
.toFloatOrNull() ?: -1f
|
||||||
|
|
||||||
date_upload = parseRelativeDate(element.selectFirst(".chap_update").text())
|
date_upload = parseRelativeDate(element.selectFirst(".chap_update")!!.text())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseRelativeDate(date: String): Long {
|
private fun parseRelativeDate(date: String): Long {
|
||||||
|
|
|
@ -28,16 +28,16 @@ open class ComicGamma(
|
||||||
override fun popularMangaNextPageSelector(): String? = null
|
override fun popularMangaNextPageSelector(): String? = null
|
||||||
override fun popularMangaSelector() = ".tab_panel.active .manga_item"
|
override fun popularMangaSelector() = ".tab_panel.active .manga_item"
|
||||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||||
url = element.selectFirst(Evaluator.Tag("a")).attr("href")
|
url = element.selectFirst(Evaluator.Tag("a"))!!.attr("href")
|
||||||
title = element.selectFirst(Evaluator.Class("manga_title")).text()
|
title = element.selectFirst(Evaluator.Class("manga_title"))!!.text()
|
||||||
author = element.selectFirst(Evaluator.Class("manga_author")).text()
|
author = element.selectFirst(Evaluator.Class("manga_author"))!!.text()
|
||||||
val genreList = element.select(Evaluator.Tag("li")).map { it.text() }
|
val genreList = element.select(Evaluator.Tag("li")).map { it.text() }
|
||||||
genre = genreList.joinToString()
|
genre = genreList.joinToString()
|
||||||
status = when {
|
status = when {
|
||||||
genreList.contains("完結") && !genreList.contains("リピート配信") -> SManga.COMPLETED
|
genreList.contains("完結") && !genreList.contains("リピート配信") -> SManga.COMPLETED
|
||||||
else -> SManga.ONGOING
|
else -> SManga.ONGOING
|
||||||
}
|
}
|
||||||
thumbnail_url = element.selectFirst(Evaluator.Tag("img")).absUrl("src")
|
thumbnail_url = element.selectFirst(Evaluator.Tag("img"))!!.absUrl("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException("Not used.")
|
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException("Not used.")
|
||||||
|
@ -60,7 +60,7 @@ open class ComicGamma(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val titleElement = document.selectFirst(Evaluator.Class("manga__title"))
|
val titleElement = document.selectFirst(Evaluator.Class("manga__title"))!!
|
||||||
val titleName = titleElement.child(0).text()
|
val titleName = titleElement.child(0).text()
|
||||||
val desc = document.selectFirst(".detail__item > p:not(:empty)")?.run {
|
val desc = document.selectFirst(".detail__item > p:not(:empty)")?.run {
|
||||||
select(Evaluator.Tag("br")).prepend("\\n")
|
select(Evaluator.Tag("br")).prepend("\\n")
|
||||||
|
@ -81,7 +81,7 @@ open class ComicGamma(
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
url = element.attr("href").toOldChapterUrl()
|
url = element.attr("href").toOldChapterUrl()
|
||||||
val number = url.removeSuffix("/").substringAfterLast('/').replace('_', '.')
|
val number = url.removeSuffix("/").substringAfterLast('/').replace('_', '.')
|
||||||
val list = element.selectFirst(Evaluator.Class("read__contents")).children()
|
val list = element.selectFirst(Evaluator.Class("read__contents"))!!.children()
|
||||||
name = "[$number] ${list[0].text()}"
|
name = "[$number] ${list[0].text()}"
|
||||||
if (list.size >= 3) {
|
if (list.size >= 3) {
|
||||||
date_upload = dateFormat.parseJST(list[2].text())?.time ?: 0L
|
date_upload = dateFormat.parseJST(list[2].text())?.time ?: 0L
|
||||||
|
@ -98,7 +98,7 @@ open class ComicGamma(
|
||||||
time += 12 * 3600 * 1000 // updates at 12 noon
|
time += 12 * 3600 * 1000 // updates at 12 noon
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getJSTFormat(datePattern: String) =
|
private fun getJSTFormat(datePattern: String) =
|
||||||
SimpleDateFormat(datePattern, Locale.JAPANESE).apply {
|
SimpleDateFormat(datePattern, Locale.JAPANESE).apply {
|
||||||
timeZone = TimeZone.getTimeZone("GMT+09:00")
|
timeZone = TimeZone.getTimeZone("GMT+09:00")
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ open class EroMuse(override val name: String, override val baseUrl: String) : Ht
|
||||||
protected fun parseManga(document: Document): MangasPage {
|
protected fun parseManga(document: Document): MangasPage {
|
||||||
fun internalParse(internalDocument: Document): List<SManga> {
|
fun internalParse(internalDocument: Document): List<SManga> {
|
||||||
val authorDocument = if (stackItem.pageType == VARIOUS_AUTHORS) {
|
val authorDocument = if (stackItem.pageType == VARIOUS_AUTHORS) {
|
||||||
internalDocument.select(albumSelector)?.let {
|
internalDocument.select(albumSelector).let {
|
||||||
elements ->
|
elements ->
|
||||||
elements.reversed().map { pageStack.addLast(StackItem(it.attr("abs:href"), AUTHOR)) }
|
elements.reversed().map { pageStack.addLast(StackItem(it.attr("abs:href"), AUTHOR)) }
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ open class EroMuse(override val name: String, override val baseUrl: String) : Ht
|
||||||
if (stackItem.pageType in listOf(VARIOUS_AUTHORS, SEARCH_RESULTS_OR_BASE)) document.addNextPageToStack()
|
if (stackItem.pageType in listOf(VARIOUS_AUTHORS, SEARCH_RESULTS_OR_BASE)) document.addNextPageToStack()
|
||||||
val mangas = when (stackItem.pageType) {
|
val mangas = when (stackItem.pageType) {
|
||||||
VARIOUS_AUTHORS -> {
|
VARIOUS_AUTHORS -> {
|
||||||
document.select(albumSelector)?.let {
|
document.select(albumSelector).let {
|
||||||
elements ->
|
elements ->
|
||||||
elements.reversed().map { pageStack.addLast(StackItem(it.attr("abs:href"), AUTHOR)) }
|
elements.reversed().map { pageStack.addLast(StackItem(it.attr("abs:href"), AUTHOR)) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ abstract class FMReader(
|
||||||
val mangas = document.select(popularMangaSelector()).map { popularMangaFromElement(it) }
|
val mangas = document.select(popularMangaSelector()).map { popularMangaFromElement(it) }
|
||||||
|
|
||||||
// check if there's a next page
|
// check if there's a next page
|
||||||
val hasNextPage = (document.select(popularMangaNextPageSelector())?.first()?.text() ?: "").let {
|
val hasNextPage = (document.select(popularMangaNextPageSelector()).first()?.text() ?: "").let {
|
||||||
if (it.contains(Regex("""\w*\s\d*\s\w*\s\d*"""))) {
|
if (it.contains(Regex("""\w*\s\d*\s\w*\s\d*"""))) {
|
||||||
it.split(" ").let { pageOf -> pageOf[1] != pageOf[3] } // current page not last page
|
it.split(" ").let { pageOf -> pageOf[1] != pageOf[3] } // current page not last page
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,7 +134,7 @@ abstract class FMReader(
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
element.select("$headerSelector").let {
|
element.select(headerSelector).let {
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
title = it.text()
|
title = it.text()
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ abstract class FMReader(
|
||||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val infoElement = document.select("div.row").first()
|
val infoElement = document.select("div.row").first()!!
|
||||||
|
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
author = infoElement.select("li a.btn-info").eachText().filter {
|
author = infoElement.select("li a.btn-info").eachText().filter {
|
||||||
|
@ -227,7 +227,7 @@ abstract class FMReader(
|
||||||
open fun chapterFromElement(element: Element, mangaTitle: String = ""): SChapter {
|
open fun chapterFromElement(element: Element, mangaTitle: String = ""): SChapter {
|
||||||
return SChapter.create().apply {
|
return SChapter.create().apply {
|
||||||
if (chapterUrlSelector != "") {
|
if (chapterUrlSelector != "") {
|
||||||
element.select(chapterUrlSelector).first().let {
|
element.select(chapterUrlSelector).first()!!.let {
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
name = it.text().substringAfter("$mangaTitle ")
|
name = it.text().substringAfter("$mangaTitle ")
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ abstract class FoolSlide(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||||
element.select("a[title]").first().let {
|
element.select("a[title]").first()!!.let {
|
||||||
setUrlWithoutDomain(it.attr("href"))
|
setUrlWithoutDomain(it.attr("href"))
|
||||||
title = it.text()
|
title = it.text()
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ abstract class FoolSlide(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
|
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
|
||||||
element.select("a[title]").first().let {
|
element.select("a[title]").first()!!.let {
|
||||||
setUrlWithoutDomain(it.attr("href"))
|
setUrlWithoutDomain(it.attr("href"))
|
||||||
title = it.text()
|
title = it.text()
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ abstract class FoolSlide(
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
override fun searchMangaFromElement(element: Element): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
element.select("a[title]").first().let {
|
element.select("a[title]").first()!!.let {
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
manga.setUrlWithoutDomain(it.attr("href"))
|
||||||
manga.title = it.text()
|
manga.title = it.text()
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ abstract class FoolSlide(
|
||||||
// if there's no image on the details page, get the first page of the first chapter
|
// if there's no image on the details page, get the first page of the first chapter
|
||||||
protected fun getDetailsThumbnail(document: Document, urlSelector: String = chapterUrlSelector): String? {
|
protected fun getDetailsThumbnail(document: Document, urlSelector: String = chapterUrlSelector): String? {
|
||||||
return document.select("div.thumbnail img, table.thumb img").firstOrNull()?.attr("abs:src")
|
return document.select("div.thumbnail img, table.thumb img").firstOrNull()?.attr("abs:src")
|
||||||
?: document.select(chapterListSelector()).last().select(urlSelector).attr("abs:href")
|
?: document.select(chapterListSelector()).last()!!.select(urlSelector).attr("abs:href")
|
||||||
.let { url -> client.newCall(allowAdult(GET(url))).execute() }
|
.let { url -> client.newCall(allowAdult(GET(url))).execute() }
|
||||||
.let { response -> pageListParse(response).first().imageUrl }
|
.let { response -> pageListParse(response).first().imageUrl }
|
||||||
}
|
}
|
||||||
|
@ -142,13 +142,11 @@ abstract class FoolSlide(
|
||||||
protected open val chapterUrlSelector = "a[title]"
|
protected open val chapterUrlSelector = "a[title]"
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
val urlElement = element.select(chapterUrlSelector).first()
|
val urlElement = element.select(chapterUrlSelector).first()!!
|
||||||
val dateElement = element.select(chapterDateSelector).first()
|
val dateElement = element.select(chapterDateSelector).first()!!
|
||||||
setUrlWithoutDomain(urlElement.attr("href"))
|
setUrlWithoutDomain(urlElement.attr("href"))
|
||||||
name = urlElement.text()
|
name = urlElement.text()
|
||||||
date_upload = dateElement.text()?.let {
|
date_upload = parseChapterDate(dateElement.text().substringAfter(", ")) ?: 0
|
||||||
parseChapterDate(it.substringAfter(", "))
|
|
||||||
} ?: 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun parseChapterDate(date: String): Long? {
|
protected open fun parseChapterDate(date: String): Long? {
|
||||||
|
|
|
@ -105,11 +105,11 @@ abstract class Gattsu(
|
||||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||||
name = "Capítulo único"
|
name = "Capítulo único"
|
||||||
scanlator = element.select("ul.post-itens li:contains(Tradutor) a").firstOrNull()?.text()
|
scanlator = element.select("ul.post-itens li:contains(Tradutor) a").firstOrNull()?.text()
|
||||||
date_upload = element.ownerDocument().select("meta[property=article:published_time]").firstOrNull()
|
date_upload = element.ownerDocument()!!.select("meta[property=article:published_time]").firstOrNull()
|
||||||
?.attr("content")
|
?.attr("content")
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
.toDate()
|
.toDate()
|
||||||
setUrlWithoutDomain(element.ownerDocument().location())
|
setUrlWithoutDomain(element.ownerDocument()!!.location())
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun pageListSelector(): String =
|
protected open fun pageListSelector(): String =
|
||||||
|
|
|
@ -63,11 +63,11 @@ open class Genkan(
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
element.select("a.list-title").first().let {
|
element.select("a.list-title").first()!!.let {
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
manga.setUrlWithoutDomain(it.attr("href"))
|
||||||
manga.title = it.text()
|
manga.title = it.text()
|
||||||
}
|
}
|
||||||
manga.thumbnail_url = styleToUrl(element.select("a.media-content").first())
|
manga.thumbnail_url = styleToUrl(element.select("a.media-content").first()!!)
|
||||||
return manga
|
return manga
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +98,9 @@ open class Genkan(
|
||||||
|
|
||||||
protected var countryOfOriginSelector = ".card.mt-2 .list-item:contains(Country of Origin) .no-wrap"
|
protected var countryOfOriginSelector = ".card.mt-2 .list-item:contains(Country of Origin) .no-wrap"
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
title = document.select("div#content h5").first().text()
|
title = document.select("div#content h5").first()!!.text()
|
||||||
description = document.select("div.col-lg-9").text().substringAfter("Description ").substringBefore(" Volume")
|
description = document.select("div.col-lg-9").text().substringAfter("Description ").substringBefore(" Volume")
|
||||||
thumbnail_url = styleToUrl(document.select("div.media a").first())
|
thumbnail_url = styleToUrl(document.select("div.media a").first()!!)
|
||||||
genre = listOfNotNull(
|
genre = listOfNotNull(
|
||||||
document.selectFirst(countryOfOriginSelector)?.let { countryOfOriginToSeriesType(it.text()) },
|
document.selectFirst(countryOfOriginSelector)?.let { countryOfOriginToSeriesType(it.text()) },
|
||||||
).joinToString()
|
).joinToString()
|
||||||
|
@ -119,7 +119,7 @@ open class Genkan(
|
||||||
} else {
|
} else {
|
||||||
"Ch. $chapNum: ${urlElement.text()}"
|
"Ch. $chapNum: ${urlElement.text()}"
|
||||||
}
|
}
|
||||||
date_upload = parseChapterDate(element.select("a.item-company").first().text()) ?: 0
|
date_upload = parseChapterDate(element.select("a.item-company").first()!!.text()) ?: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ open class Genkan(
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val pages = mutableListOf<Page>()
|
val pages = mutableListOf<Page>()
|
||||||
|
|
||||||
val allImages = document.select("div#pages-container + script").first().data()
|
val allImages = document.select("div#pages-container + script").first()!!.data()
|
||||||
.substringAfter("[").substringBefore("];")
|
.substringAfter("[").substringBefore("];")
|
||||||
.replace(Regex("""["\\]"""), "")
|
.replace(Regex("""["\\]"""), "")
|
||||||
.split(",")
|
.split(",")
|
||||||
|
|
|
@ -49,7 +49,7 @@ open class GenkanOriginal(
|
||||||
// search the given document for matches
|
// search the given document for matches
|
||||||
private fun getMatchesFrom(document: Document): MutableList<SManga> {
|
private fun getMatchesFrom(document: Document): MutableList<SManga> {
|
||||||
val searchMatches = mutableListOf<SManga>()
|
val searchMatches = mutableListOf<SManga>()
|
||||||
document.select(searchMangaSelector())
|
document.select(searchMangaSelector()).toList()
|
||||||
.filter { it.text().contains(searchQuery, ignoreCase = true) }
|
.filter { it.text().contains(searchQuery, ignoreCase = true) }
|
||||||
.map { searchMatches.add(searchMangaFromElement(it)) }
|
.map { searchMatches.add(searchMangaFromElement(it)) }
|
||||||
|
|
||||||
|
|
|
@ -67,8 +67,8 @@ abstract class GigaViewer(
|
||||||
override fun popularMangaSelector(): String = "ul.series-list li a"
|
override fun popularMangaSelector(): String = "ul.series-list li a"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("h2.series-list-title").text()
|
title = element.selectFirst("h2.series-list-title")!!.text()
|
||||||
thumbnail_url = element.selectFirst("div.series-list-thumb img")
|
thumbnail_url = element.selectFirst("div.series-list-thumb img")!!
|
||||||
.attr("data-src")
|
.attr("data-src")
|
||||||
setUrlWithoutDomain(element.attr("href"))
|
setUrlWithoutDomain(element.attr("href"))
|
||||||
}
|
}
|
||||||
|
@ -114,9 +114,9 @@ abstract class GigaViewer(
|
||||||
override fun searchMangaSelector() = "ul.search-series-list li, ul.series-list li"
|
override fun searchMangaSelector() = "ul.search-series-list li, ul.series-list li"
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("div.title-box p.series-title").text()
|
title = element.selectFirst("div.title-box p.series-title")!!.text()
|
||||||
thumbnail_url = element.selectFirst("div.thmb-container a img").attr("src")
|
thumbnail_url = element.selectFirst("div.thmb-container a img")!!.attr("src")
|
||||||
setUrlWithoutDomain(element.selectFirst("div.thmb-container a").attr("href"))
|
setUrlWithoutDomain(element.selectFirst("div.thmb-container a")!!.attr("href"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector(): String? = null
|
override fun searchMangaNextPageSelector(): String? = null
|
||||||
|
@ -126,11 +126,11 @@ abstract class GigaViewer(
|
||||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||||
val infoElement = document.selectFirst(mangaDetailsInfoSelector())!!
|
val infoElement = document.selectFirst(mangaDetailsInfoSelector())!!
|
||||||
|
|
||||||
title = infoElement.selectFirst("h1.series-header-title").text()
|
title = infoElement.selectFirst("h1.series-header-title")!!.text()
|
||||||
author = infoElement.selectFirst("h2.series-header-author").text()
|
author = infoElement.selectFirst("h2.series-header-author")!!.text()
|
||||||
artist = author
|
artist = author
|
||||||
description = infoElement.selectFirst("p.series-header-description").text()
|
description = infoElement.selectFirst("p.series-header-description")!!.text()
|
||||||
thumbnail_url = infoElement.selectFirst("div.series-header-image-wrapper img")
|
thumbnail_url = infoElement.selectFirst("div.series-header-image-wrapper img")!!
|
||||||
.attr("data-src")
|
.attr("data-src")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,10 +183,10 @@ abstract class GigaViewer(
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
val info = element.selectFirst("a.series-episode-list-container") ?: element
|
val info = element.selectFirst("a.series-episode-list-container") ?: element
|
||||||
val mangaUrl = element.ownerDocument().location()
|
val mangaUrl = element.ownerDocument()!!.location()
|
||||||
|
|
||||||
return SChapter.create().apply {
|
return SChapter.create().apply {
|
||||||
name = info.selectFirst("h4.series-episode-list-title").text()
|
name = info.selectFirst("h4.series-episode-list-title")!!.text()
|
||||||
if (chapterListMode == CHAPTER_LIST_PAID && element.selectFirst("span.series-episode-list-is-free") == null) {
|
if (chapterListMode == CHAPTER_LIST_PAID && element.selectFirst("span.series-episode-list-is-free") == null) {
|
||||||
name = YEN_BANKNOTE + name
|
name = YEN_BANKNOTE + name
|
||||||
} else if (chapterListMode == CHAPTER_LIST_LOCKED && element.hasClass("private")) {
|
} else if (chapterListMode == CHAPTER_LIST_LOCKED && element.hasClass("private")) {
|
||||||
|
@ -201,7 +201,7 @@ abstract class GigaViewer(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val episode = document.selectFirst("script#episode-json")
|
val episode = document.selectFirst("script#episode-json")!!
|
||||||
.attr("data-value")
|
.attr("data-value")
|
||||||
.let {
|
.let {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -74,7 +74,7 @@ abstract class GroupLe(
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.thumbnail_url = element.select("img.lazy").first()?.attr("data-original")?.replace("_p.", ".")
|
manga.thumbnail_url = element.select("img.lazy").first()?.attr("data-original")?.replace("_p.", ".")
|
||||||
element.select("h3 > a").first().let {
|
element.select("h3 > a").first()!!.let {
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
manga.setUrlWithoutDomain(it.attr("href"))
|
||||||
manga.title = it.attr("title")
|
manga.title = it.attr("title")
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,9 @@ abstract class GroupLe(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val infoElement = document.select(".expandable").first()
|
val infoElement = document.select(".expandable").first()!!
|
||||||
val rawCategory = infoElement.select("span.elem_category").text()
|
val rawCategory = infoElement.select("span.elem_category").text()
|
||||||
val category = if (rawCategory.isNotEmpty()) {
|
val category = rawCategory.ifEmpty {
|
||||||
rawCategory
|
|
||||||
} else {
|
|
||||||
"манга"
|
"манга"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +185,8 @@ abstract class GroupLe(
|
||||||
override fun chapterListSelector() = "div.chapters-link > table > tbody > tr:has(td > a):has(td.date:not(.text-info))"
|
override fun chapterListSelector() = "div.chapters-link > table > tbody > tr:has(td > a):has(td.date:not(.text-info))"
|
||||||
|
|
||||||
private fun chapterFromElement(element: Element, manga: SManga): SChapter {
|
private fun chapterFromElement(element: Element, manga: SManga): SChapter {
|
||||||
val urlElement = element.select("a.chapter-link").first()
|
val urlElement = element.select("a.chapter-link").first()!!
|
||||||
val chapterInf = element.select("td.item-title").first()
|
val chapterInf = element.select("td.item-title").first()!!
|
||||||
val urlText = urlElement.text()
|
val urlText = urlElement.text()
|
||||||
|
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
|
|
|
@ -55,10 +55,10 @@ open class Kemono(
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val cardList = document.selectFirst(Evaluator.Class("card-list"))
|
val cardList = document.selectFirst(Evaluator.Class("card-list"))!!
|
||||||
val creators = cardList.select(Evaluator.Tag("article")).map {
|
val creators = cardList.select(Evaluator.Tag("article")).map {
|
||||||
val children = it.children()
|
val children = it.children()
|
||||||
val avatar = children[0].selectFirst(Evaluator.Tag("img")).attr("src")
|
val avatar = children[0].selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||||
val link = children[1].child(0)
|
val link = children[1].child(0)
|
||||||
val service = children[2].ownText()
|
val service = children[2].ownText()
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
|
@ -100,13 +100,13 @@ open class Kemono(
|
||||||
val baseUrl = baseUrl
|
val baseUrl = baseUrl
|
||||||
return if (page == 1) {
|
return if (page == 1) {
|
||||||
val document = client.newCall(GET(baseUrl + path, headers)).execute().asJsoup()
|
val document = client.newCall(GET(baseUrl + path, headers)).execute().asJsoup()
|
||||||
val cardList = document.selectFirst(Evaluator.Class("card-list__items"))
|
val cardList = document.selectFirst(Evaluator.Class("card-list__items"))!!
|
||||||
val creators = cardList.children().map {
|
val creators = cardList.children().map {
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
url = it.attr("href")
|
url = it.attr("href")
|
||||||
title = it.selectFirst(Evaluator.Class("user-card__name")).ownText()
|
title = it.selectFirst(Evaluator.Class("user-card__name"))!!.ownText()
|
||||||
author = it.selectFirst(Evaluator.Class("user-card__service")).ownText()
|
author = it.selectFirst(Evaluator.Class("user-card__service"))!!.ownText()
|
||||||
thumbnail_url = baseUrl + it.selectFirst(Evaluator.Tag("img")).attr("src")
|
thumbnail_url = baseUrl + it.selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||||
description = PROMPT
|
description = PROMPT
|
||||||
initialized = true
|
initialized = true
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ open class Kemono(
|
||||||
private const val POST_PAGES_MAX = 50
|
private const val POST_PAGES_MAX = 50
|
||||||
|
|
||||||
private fun Element.hasNextPage(): Boolean {
|
private fun Element.hasNextPage(): Boolean {
|
||||||
val pagination = selectFirst(Evaluator.Class("paginator"))
|
val pagination = selectFirst(Evaluator.Class("paginator"))!!
|
||||||
return pagination.selectFirst("a[title=Next page]") != null
|
return pagination.selectFirst("a[title=Next page]") != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,7 @@ abstract class LibGroup(
|
||||||
|
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
|
|
||||||
val body = document.select("div.media-info-list").first()
|
val body = document.select("div.media-info-list").first()!!
|
||||||
val rawCategory = document.select(".media-short-info a.media-short-info__item").text()
|
val rawCategory = document.select(".media-short-info a.media-short-info__item").text()
|
||||||
val category = when {
|
val category = when {
|
||||||
rawCategory == "Комикс западный" -> "Комикс"
|
rawCategory == "Комикс западный" -> "Комикс"
|
||||||
|
@ -217,8 +217,8 @@ abstract class LibGroup(
|
||||||
|
|
||||||
val rawAgeStop = document.select(".media-short-info .media-short-info__item[data-caution]").text()
|
val rawAgeStop = document.select(".media-short-info .media-short-info__item[data-caution]").text()
|
||||||
|
|
||||||
val ratingValue = document.select(".media-rating__value").last().text().toFloat() * 2
|
val ratingValue = document.select(".media-rating__value").last()!!.text().toFloat() * 2
|
||||||
val ratingVotes = document.select(".media-rating__votes").last().text()
|
val ratingVotes = document.select(".media-rating__votes").last()!!.text()
|
||||||
val ratingStar = when {
|
val ratingStar = when {
|
||||||
ratingValue > 9.5 -> "★★★★★"
|
ratingValue > 9.5 -> "★★★★★"
|
||||||
ratingValue > 8.5 -> "★★★★✬"
|
ratingValue > 8.5 -> "★★★★✬"
|
||||||
|
@ -242,19 +242,19 @@ abstract class LibGroup(
|
||||||
manga.author = body.select("div.media-info-list__title:contains(Автор) + div a").joinToString { it.text() }
|
manga.author = body.select("div.media-info-list__title:contains(Автор) + div a").joinToString { it.text() }
|
||||||
manga.artist = body.select("div.media-info-list__title:contains(Художник) + div a").joinToString { it.text() }
|
manga.artist = body.select("div.media-info-list__title:contains(Художник) + div a").joinToString { it.text() }
|
||||||
|
|
||||||
val StatusTranslate = body.select("div.media-info-list__title:contains(Статус перевода) + div").text().lowercase(Locale.ROOT)
|
val statusTranslate = body.select("div.media-info-list__title:contains(Статус перевода) + div").text().lowercase(Locale.ROOT)
|
||||||
val StatusTitle = body.select("div.media-info-list__title:contains(Статус тайтла) + div").text().lowercase(Locale.ROOT)
|
val statusTitle = body.select("div.media-info-list__title:contains(Статус тайтла) + div").text().lowercase(Locale.ROOT)
|
||||||
|
|
||||||
manga.status = if (document.html().contains("paper empty section")
|
manga.status = if (document.html().contains("paper empty section")
|
||||||
) {
|
) {
|
||||||
SManga.LICENSED
|
SManga.LICENSED
|
||||||
} else {
|
} else {
|
||||||
when {
|
when {
|
||||||
StatusTranslate.contains("завершен") && StatusTitle.contains("приостановлен") || StatusTranslate.contains("заморожен") || StatusTranslate.contains("заброшен") -> SManga.ON_HIATUS
|
statusTranslate.contains("завершен") && statusTitle.contains("приостановлен") || statusTranslate.contains("заморожен") || statusTranslate.contains("заброшен") -> SManga.ON_HIATUS
|
||||||
StatusTranslate.contains("завершен") && StatusTitle.contains("выпуск прекращён") -> SManga.CANCELLED
|
statusTranslate.contains("завершен") && statusTitle.contains("выпуск прекращён") -> SManga.CANCELLED
|
||||||
StatusTranslate.contains("продолжается") -> SManga.ONGOING
|
statusTranslate.contains("продолжается") -> SManga.ONGOING
|
||||||
StatusTranslate.contains("завершен") -> SManga.COMPLETED
|
statusTranslate.contains("завершен") -> SManga.COMPLETED
|
||||||
else -> when (StatusTitle) {
|
else -> when (statusTitle) {
|
||||||
"онгоинг" -> SManga.ONGOING
|
"онгоинг" -> SManga.ONGOING
|
||||||
"анонс" -> SManga.ONGOING
|
"анонс" -> SManga.ONGOING
|
||||||
"завершён" -> SManga.COMPLETED
|
"завершён" -> SManga.COMPLETED
|
||||||
|
@ -445,7 +445,7 @@ abstract class LibGroup(
|
||||||
|
|
||||||
val chapInfo = document
|
val chapInfo = document
|
||||||
.select("script:containsData(window.__info)")
|
.select("script:containsData(window.__info)")
|
||||||
.first()
|
.first()!!
|
||||||
.html()
|
.html()
|
||||||
.split("window.__info = ")
|
.split("window.__info = ")
|
||||||
.last()
|
.last()
|
||||||
|
@ -468,7 +468,7 @@ abstract class LibGroup(
|
||||||
// Get pages
|
// Get pages
|
||||||
val pagesArr = document
|
val pagesArr = document
|
||||||
.select("script:containsData(window.__pg)")
|
.select("script:containsData(window.__pg)")
|
||||||
.first()
|
.first()!!
|
||||||
.html()
|
.html()
|
||||||
.trim()
|
.trim()
|
||||||
.removePrefix("window.__pg = ")
|
.removePrefix("window.__pg = ")
|
||||||
|
|
|
@ -1156,8 +1156,8 @@ abstract class Madara(
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
.map { li ->
|
.map { li ->
|
||||||
Genre(
|
Genre(
|
||||||
li.selectFirst("label").text(),
|
li.selectFirst("label")!!.text(),
|
||||||
li.selectFirst("input[type=checkbox]").`val`(),
|
li.selectFirst("input[type=checkbox]")!!.`val`(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1196,7 +1196,7 @@ abstract class Madara(
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val customUa = newValue as String
|
val customUa = newValue as String
|
||||||
preferences.edit().putString(PREF_KEY_CUSTOM_UA, customUa).apply()
|
preferences.edit().putString(PREF_KEY_CUSTOM_UA, customUa).apply()
|
||||||
if (customUa.isNullOrBlank()) {
|
if (customUa.isBlank()) {
|
||||||
Toast.makeText(screen.context, RESTART_APP_STRING, Toast.LENGTH_LONG).show()
|
Toast.makeText(screen.context, RESTART_APP_STRING, Toast.LENGTH_LONG).show()
|
||||||
} else {
|
} else {
|
||||||
userAgent = null
|
userAgent = null
|
||||||
|
|
|
@ -176,7 +176,7 @@ abstract class MadTheme(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to show message/error from site
|
// Try to show message/error from site
|
||||||
response.body?.let { body ->
|
response.body.let { body ->
|
||||||
json.decodeFromString<JsonObject>(body.string())["message"]
|
json.decodeFromString<JsonObject>(body.string())["message"]
|
||||||
?.jsonPrimitive
|
?.jsonPrimitive
|
||||||
?.content
|
?.content
|
||||||
|
@ -200,7 +200,7 @@ abstract class MadTheme(
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||||
// Not using setUrlWithoutDomain() to support external chapters
|
// Not using setUrlWithoutDomain() to support external chapters
|
||||||
url = element.selectFirst("a")
|
url = element.selectFirst("a")!!
|
||||||
.absUrl("href")
|
.absUrl("href")
|
||||||
.removePrefix(baseUrl)
|
.removePrefix(baseUrl)
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ abstract class MadTheme(
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val html = document.html()!!
|
val html = document.html()
|
||||||
|
|
||||||
if (!html.contains("var mainServer = \"")) {
|
if (!html.contains("var mainServer = \"")) {
|
||||||
// No fancy CDN, all images are available directly in <img> tags
|
// No fancy CDN, all images are available directly in <img> tags
|
||||||
|
|
|
@ -60,11 +60,11 @@ abstract class MangaBox(
|
||||||
|
|
||||||
protected fun mangaFromElement(element: Element, urlSelector: String = "h3 a"): SManga {
|
protected fun mangaFromElement(element: Element, urlSelector: String = "h3 a"): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
element.select(urlSelector).first().let {
|
element.select(urlSelector).first()!!.let {
|
||||||
url = it.attr("abs:href").substringAfter(baseUrl) // intentionally not using setUrlWithoutDomain
|
url = it.attr("abs:href").substringAfter(baseUrl) // intentionally not using setUrlWithoutDomain
|
||||||
title = it.text()
|
title = it.text()
|
||||||
}
|
}
|
||||||
thumbnail_url = element.select("img").first().attr("abs:src")
|
thumbnail_url = element.select("img").first()!!.attr("abs:src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,14 +145,14 @@ abstract class MangaBox(
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
document.select(mangaDetailsMainSelector).firstOrNull()?.let { infoElement ->
|
document.select(mangaDetailsMainSelector).firstOrNull()?.let { infoElement ->
|
||||||
title = infoElement.select("h1, h2").first().text()
|
title = infoElement.select("h1, h2").first()!!.text()
|
||||||
author = infoElement.select("li:contains(author) a, td:containsOwn(author) + td a").eachText().joinToString()
|
author = infoElement.select("li:contains(author) a, td:containsOwn(author) + td a").eachText().joinToString()
|
||||||
status = parseStatus(infoElement.select("li:contains(status), td:containsOwn(status) + td").text())
|
status = parseStatus(infoElement.select("li:contains(status), td:containsOwn(status) + td").text())
|
||||||
genre = infoElement.select("div.manga-info-top li:contains(genres)").firstOrNull()
|
genre = infoElement.select("div.manga-info-top li:contains(genres)").firstOrNull()
|
||||||
?.select("a")?.joinToString { it.text() } // kakalot
|
?.select("a")?.joinToString { it.text() } // kakalot
|
||||||
?: infoElement.select("td:containsOwn(genres) + td a").joinToString { it.text() } // nelo
|
?: infoElement.select("td:containsOwn(genres) + td a").joinToString { it.text() } // nelo
|
||||||
} ?: checkForRedirectMessage(document)
|
} ?: checkForRedirectMessage(document)
|
||||||
description = document.select(descriptionSelector)?.firstOrNull()?.ownText()
|
description = document.select(descriptionSelector).firstOrNull()?.ownText()
|
||||||
?.replace("""^$title summary:\s""".toRegex(), "")
|
?.replace("""^$title summary:\s""".toRegex(), "")
|
||||||
?.replace("""<\s*br\s*/?>""".toRegex(), "\n")
|
?.replace("""<\s*br\s*/?>""".toRegex(), "\n")
|
||||||
?.replace("<[^>]*>".toRegex(), "")
|
?.replace("<[^>]*>".toRegex(), "")
|
||||||
|
@ -201,7 +201,7 @@ abstract class MangaBox(
|
||||||
|
|
||||||
private fun Element.selectDateFromElement(): Element {
|
private fun Element.selectDateFromElement(): Element {
|
||||||
val defaultChapterDateSelector = "span"
|
val defaultChapterDateSelector = "span"
|
||||||
return this.select(defaultChapterDateSelector).lastOrNull() ?: this.select(alternateChapterDateSelector).last()
|
return this.select(defaultChapterDateSelector).lastOrNull() ?: this.select(alternateChapterDateSelector).last()!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
|
|
|
@ -46,27 +46,27 @@ abstract class MangabzTheme(
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
override fun searchMangaParse(response: Response): MangasPage {
|
||||||
val document = response.asJsoup().also(::parseFilters)
|
val document = response.asJsoup().also(::parseFilters)
|
||||||
val mangas = document.selectFirst(Evaluator.Class("mh-list")).children().map { element ->
|
val mangas = document.selectFirst(Evaluator.Class("mh-list"))!!.children().map { element ->
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
title = element.selectFirst(Evaluator.Tag("h2")).text()
|
title = element.selectFirst(Evaluator.Tag("h2"))!!.text()
|
||||||
url = element.selectFirst(Evaluator.Tag("a")).attr("href")
|
url = element.selectFirst(Evaluator.Tag("a"))!!.attr("href")
|
||||||
thumbnail_url = element.selectFirst(Evaluator.Tag("img")).attr("src")
|
thumbnail_url = element.selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val hasNextPage = document.run {
|
val hasNextPage = document.run {
|
||||||
val pagination = selectFirst(Evaluator.Class("page-pagination"))
|
val pagination = selectFirst(Evaluator.Class("page-pagination"))
|
||||||
pagination != null && pagination.select(Evaluator.Tag("a")).last().text() == ">"
|
pagination != null && pagination.select(Evaluator.Tag("a")).last()!!.text() == ">"
|
||||||
}
|
}
|
||||||
return MangasPage(mangas, hasNextPage)
|
return MangasPage(mangas, hasNextPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val details = document.selectFirst(Evaluator.Class("detail-info-tip")).children()!!
|
val details = document.selectFirst(Evaluator.Class("detail-info-tip"))!!.children()
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
url = document.location().removePrefix(baseUrl)
|
url = document.location().removePrefix(baseUrl)
|
||||||
title = document.selectFirst(Evaluator.Class("detail-info-title")).ownText()
|
title = document.selectFirst(Evaluator.Class("detail-info-title"))!!.ownText()
|
||||||
thumbnail_url = document.selectFirst(Evaluator.Class("detail-info-cover")).attr("src")
|
thumbnail_url = document.selectFirst(Evaluator.Class("detail-info-cover"))!!.attr("src")
|
||||||
status = when (details[1].child(0).ownText()) {
|
status = when (details[1].child(0).ownText()) {
|
||||||
"连载中" -> SManga.ONGOING
|
"连载中" -> SManga.ONGOING
|
||||||
"已完结" -> SManga.COMPLETED
|
"已完结" -> SManga.COMPLETED
|
||||||
|
@ -76,7 +76,7 @@ abstract class MangabzTheme(
|
||||||
}
|
}
|
||||||
author = details[0].children().joinToString { it.ownText() }
|
author = details[0].children().joinToString { it.ownText() }
|
||||||
genre = details[2].children().joinToString { it.ownText() }
|
genre = details[2].children().joinToString { it.ownText() }
|
||||||
description = parseDescription(document.selectFirst(Evaluator.Class("detail-info-content")), title, details)
|
description = parseDescription(document.selectFirst(Evaluator.Class("detail-info-content"))!!, title, details)
|
||||||
initialized = true
|
initialized = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ abstract class MangabzTheme(
|
||||||
}
|
}
|
||||||
if (list.isEmpty()) return emptyList()
|
if (list.isEmpty()) return emptyList()
|
||||||
|
|
||||||
val listTitle = document.selectFirst(Evaluator.Class("detail-list-form-title")).ownText()
|
val listTitle = document.selectFirst(Evaluator.Class("detail-list-form-title"))!!.ownText()
|
||||||
try {
|
try {
|
||||||
list[0].date_upload = parseDate(listTitle)
|
list[0].date_upload = parseDate(listTitle)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
|
@ -113,7 +113,7 @@ abstract class MangabzTheme(
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getChapterElements(document: Document): Elements =
|
protected open fun getChapterElements(document: Document): Elements =
|
||||||
document.selectFirst(Evaluator.Id("chapterlistload")).children()
|
document.selectFirst(Evaluator.Id("chapterlistload"))!!.children()
|
||||||
|
|
||||||
protected open val needPageCount = true
|
protected open val needPageCount = true
|
||||||
|
|
||||||
|
|
|
@ -171,14 +171,14 @@ abstract class MangaHub(
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.title = document.select(".breadcrumb .active span").text()
|
manga.title = document.select(".breadcrumb .active span").text()
|
||||||
manga.author = document.select("div:has(h1) span:contains(Author) + span")?.first()?.text()
|
manga.author = document.select("div:has(h1) span:contains(Author) + span").first()?.text()
|
||||||
manga.artist = document.select("div:has(h1) span:contains(Artist) + span")?.first()?.text()
|
manga.artist = document.select("div:has(h1) span:contains(Artist) + span").first()?.text()
|
||||||
manga.genre = document.select(".row p a")?.joinToString { it.text() }
|
manga.genre = document.select(".row p a").joinToString { it.text() }
|
||||||
manga.description = document.select(".tab-content p")?.first()?.text()
|
manga.description = document.select(".tab-content p").first()?.text()
|
||||||
manga.thumbnail_url = document.select("img.img-responsive")?.first()
|
manga.thumbnail_url = document.select("img.img-responsive").first()
|
||||||
?.attr("src")
|
?.attr("src")
|
||||||
|
|
||||||
document.select("div:has(h1) span:contains(Status) + span")?.first()?.text()?.also { statusText ->
|
document.select("div:has(h1) span:contains(Status) + span").first()?.text()?.also { statusText ->
|
||||||
when {
|
when {
|
||||||
statusText.contains("ongoing", true) -> manga.status = SManga.ONGOING
|
statusText.contains("ongoing", true) -> manga.status = SManga.ONGOING
|
||||||
statusText.contains("completed", true) -> manga.status = SManga.COMPLETED
|
statusText.contains("completed", true) -> manga.status = SManga.COMPLETED
|
||||||
|
|
|
@ -78,7 +78,7 @@ abstract class MangaMainac(
|
||||||
override fun chapterListSelector() = "table.chap_tab tr"
|
override fun chapterListSelector() = "table.chap_tab tr"
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
val urlElement = element.select("a").first()
|
val urlElement = element.select("a").first()!!
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||||
chapter.name = element.select("a").text()
|
chapter.name = element.select("a").text()
|
||||||
|
|
|
@ -22,8 +22,8 @@ abstract class MangaRawTheme(
|
||||||
protected abstract fun String.sanitizeTitle(): String
|
protected abstract fun String.sanitizeTitle(): String
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||||
setUrlWithoutDomain(element.selectFirst(Evaluator.Tag("a")).attr("href"))
|
setUrlWithoutDomain(element.selectFirst(Evaluator.Tag("a"))!!.attr("href"))
|
||||||
title = element.selectFirst(Evaluator.Tag("h3")).text().sanitizeTitle()
|
title = element.selectFirst(Evaluator.Tag("h3"))!!.text().sanitizeTitle()
|
||||||
thumbnail_url = element.selectFirst(Evaluator.Tag("img"))?.absUrl("data-src")
|
thumbnail_url = element.selectFirst(Evaluator.Tag("img"))?.absUrl("data-src")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ abstract class MangaRawTheme(
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val imgSelector = Evaluator.Tag("img")
|
val imgSelector = Evaluator.Tag("img")
|
||||||
return document.select(pageSelector()).mapIndexed { index, element ->
|
return document.select(pageSelector()).mapIndexed { index, element ->
|
||||||
Page(index, imageUrl = element.selectFirst(imgSelector).attr("data-src"))
|
Page(index, imageUrl = element.selectFirst(imgSelector)!!.attr("data-src"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,7 @@ abstract class MangaThemesia(
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
val urlElements = element.select("a")
|
val urlElements = element.select("a")
|
||||||
setUrlWithoutDomain(urlElements.attr("href"))
|
setUrlWithoutDomain(urlElements.attr("href"))
|
||||||
name = element.select(".lch a, .chapternum").text().ifBlank { urlElements.first().text() }
|
name = element.select(".lch a, .chapternum").text().ifBlank { urlElements.first()!!.text() }
|
||||||
date_upload = element.selectFirst(".chapterdate")?.text().parseChapterDate()
|
date_upload = element.selectFirst(".chapterdate")?.text().parseChapterDate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,8 +452,8 @@ abstract class MangaThemesia(
|
||||||
private fun parseGenres(document: Document): List<Genre>? {
|
private fun parseGenres(document: Document): List<Genre>? {
|
||||||
return document.selectFirst("ul.genrez")?.select("li")?.map { li ->
|
return document.selectFirst("ul.genrez")?.select("li")?.map { li ->
|
||||||
Genre(
|
Genre(
|
||||||
li.selectFirst("label").text(),
|
li.selectFirst("label")!!.text(),
|
||||||
li.selectFirst("input[type=checkbox]").attr("value"),
|
li.selectFirst("input[type=checkbox]")!!.attr("value"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,7 @@ abstract class MangaThemesia(
|
||||||
else -> attr("abs:src")
|
else -> attr("abs:src")
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun Elements.imgAttr(): String = this.first().imgAttr()
|
protected open fun Elements.imgAttr(): String = this.first()!!.imgAttr()
|
||||||
|
|
||||||
// Unused
|
// Unused
|
||||||
override fun popularMangaSelector(): String = throw UnsupportedOperationException("Not used")
|
override fun popularMangaSelector(): String = throw UnsupportedOperationException("Not used")
|
||||||
|
|
|
@ -51,7 +51,7 @@ abstract class MangaWorld(
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
override fun searchMangaFromElement(element: Element): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.thumbnail_url = element.select("a.thumb img").attr("src")
|
manga.thumbnail_url = element.select("a.thumb img").attr("src")
|
||||||
element.select("a").first().let {
|
element.select("a").first()!!.let {
|
||||||
manga.setUrlWithoutDomain(it.attr("href").removeSuffix("/"))
|
manga.setUrlWithoutDomain(it.attr("href").removeSuffix("/"))
|
||||||
manga.title = it.attr("title")
|
manga.title = it.attr("title")
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ open class MCCMSNsfw(
|
||||||
GET(baseUrl + chapter.url, headers)
|
GET(baseUrl + chapter.url, headers)
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val container = response.asJsoup().selectFirst(Evaluator.Class("comic-list"))
|
val container = response.asJsoup().selectFirst(Evaluator.Class("comic-list"))!!
|
||||||
return container.select(Evaluator.Tag("img")).mapIndexed { index, img ->
|
return container.select(Evaluator.Tag("img")).mapIndexed { index, img ->
|
||||||
Page(index, imageUrl = img.attr("src"))
|
Page(index, imageUrl = img.attr("src"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,14 +24,14 @@ open class MCCMSWeb(
|
||||||
fun parseListing(document: Document): MangasPage {
|
fun parseListing(document: Document): MangasPage {
|
||||||
val mangas = document.select(Evaluator.Class("common-comic-item")).map {
|
val mangas = document.select(Evaluator.Class("common-comic-item")).map {
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
val titleElement = it.selectFirst(Evaluator.Class("comic__title")).child(0)
|
val titleElement = it.selectFirst(Evaluator.Class("comic__title"))!!.child(0)
|
||||||
url = titleElement.attr("href")
|
url = titleElement.attr("href")
|
||||||
title = titleElement.ownText()
|
title = titleElement.ownText()
|
||||||
thumbnail_url = it.selectFirst(Evaluator.Tag("img")).attr("data-original")
|
thumbnail_url = it.selectFirst(Evaluator.Tag("img"))!!.attr("data-original")
|
||||||
}.cleanup()
|
}.cleanup()
|
||||||
}
|
}
|
||||||
val hasNextPage = run { // default pagination
|
val hasNextPage = run { // default pagination
|
||||||
val buttons = document.selectFirst(Evaluator.Id("Pagination")).select(Evaluator.Tag("a"))
|
val buttons = document.selectFirst(Evaluator.Id("Pagination"))!!.select(Evaluator.Tag("a"))
|
||||||
val count = buttons.size
|
val count = buttons.size
|
||||||
// Next page != Last page
|
// Next page != Last page
|
||||||
buttons[count - 1].attr("href") != buttons[count - 2].attr("href")
|
buttons[count - 1].attr("href") != buttons[count - 2].attr("href")
|
||||||
|
@ -85,12 +85,12 @@ open class MCCMSWeb(
|
||||||
if (manga.url == "/index.php/search") return Observable.just(manga)
|
if (manga.url == "/index.php/search") return Observable.just(manga)
|
||||||
return client.newCall(GET(baseUrl + manga.url, pcHeaders)).asObservableSuccess().map { response ->
|
return client.newCall(GET(baseUrl + manga.url, pcHeaders)).asObservableSuccess().map { response ->
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
val document = response.asJsoup().selectFirst(Evaluator.Class("de-info__box"))
|
val document = response.asJsoup().selectFirst(Evaluator.Class("de-info__box"))!!
|
||||||
title = document.selectFirst(Evaluator.Class("comic-title")).ownText()
|
title = document.selectFirst(Evaluator.Class("comic-title"))!!.ownText()
|
||||||
thumbnail_url = document.selectFirst(Evaluator.Tag("img")).attr("src")
|
thumbnail_url = document.selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||||
author = document.selectFirst(Evaluator.Class("name")).text()
|
author = document.selectFirst(Evaluator.Class("name"))!!.text()
|
||||||
genre = document.selectFirst(Evaluator.Class("comic-status")).select(Evaluator.Tag("a")).joinToString { it.ownText() }
|
genre = document.selectFirst(Evaluator.Class("comic-status"))!!.select(Evaluator.Tag("a")).joinToString { it.ownText() }
|
||||||
description = document.selectFirst(Evaluator.Class("intro-total")).text()
|
description = document.selectFirst(Evaluator.Class("intro-total"))!!.text()
|
||||||
}.cleanup()
|
}.cleanup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ open class MCCMSWeb(
|
||||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||||
if (manga.url == "/index.php/search") return Observable.just(emptyList())
|
if (manga.url == "/index.php/search") return Observable.just(emptyList())
|
||||||
return client.newCall(GET(baseUrl + manga.url, pcHeaders)).asObservableSuccess().map { response ->
|
return client.newCall(GET(baseUrl + manga.url, pcHeaders)).asObservableSuccess().map { response ->
|
||||||
response.asJsoup().selectFirst(Evaluator.Class("chapter__list-box")).children().map {
|
response.asJsoup().selectFirst(Evaluator.Class("chapter__list-box"))!!.children().map {
|
||||||
val link = it.child(0)
|
val link = it.child(0)
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
url = link.attr("href")
|
url = link.attr("href")
|
||||||
|
|
|
@ -35,10 +35,10 @@ abstract class MDB(
|
||||||
override fun popularMangaRequest(page: Int) = GET(listUrl("page-$page"), headers)
|
override fun popularMangaRequest(page: Int) = GET(listUrl("page-$page"), headers)
|
||||||
override fun popularMangaSelector() = "div.comic-main-section > div.comic-book-unit"
|
override fun popularMangaSelector() = "div.comic-main-section > div.comic-book-unit"
|
||||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||||
val link = element.selectFirst("h2 > a")
|
val link = element.selectFirst("h2 > a")!!
|
||||||
setUrlWithoutDomain(link.attr("href"))
|
setUrlWithoutDomain(link.attr("href"))
|
||||||
title = link.text()
|
title = link.text()
|
||||||
thumbnail_url = element.selectFirst(Evaluator.Tag("img")).absUrl("src")
|
thumbnail_url = element.selectFirst(Evaluator.Tag("img"))!!.absUrl("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
|
@ -71,22 +71,22 @@ abstract class MDB(
|
||||||
protected open fun transformDescription(description: String) = description
|
protected open fun transformDescription(description: String) = description
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
title = document.selectFirst(Evaluator.Tag("h1")).text().let { transformTitle(it) }
|
title = transformTitle(document.selectFirst(Evaluator.Tag("h1"))!!.text())
|
||||||
author = document.selectFirst(authorSelector).text()
|
author = document.selectFirst(authorSelector)!!.text()
|
||||||
description = document.selectFirst("p.comic_story").text().let { transformDescription(it) }
|
description = transformDescription(document.selectFirst("p.comic_story")!!.text())
|
||||||
genre = parseGenre(document).joinToString(", ")
|
genre = parseGenre(document).joinToString(", ")
|
||||||
status = when (document.selectFirst("a.comic-pub-state").text()) {
|
status = when (document.selectFirst("a.comic-pub-state")!!.text()) {
|
||||||
"连载中" -> SManga.ONGOING
|
"连载中" -> SManga.ONGOING
|
||||||
"已完结" -> SManga.COMPLETED
|
"已完结" -> SManga.COMPLETED
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
thumbnail_url = document.selectFirst("td.comic-cover > img").absUrl("src")
|
thumbnail_url = document.selectFirst("td.comic-cover > img")!!.absUrl("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun parseGenre(document: Document): List<String> {
|
protected open fun parseGenre(document: Document): List<String> {
|
||||||
val list = mutableListOf<String>()
|
val list = mutableListOf<String>()
|
||||||
list.add(document.selectFirst("th:contains(地区) + td").text())
|
list.add(document.selectFirst("th:contains(地区) + td")!!.text())
|
||||||
list.add(document.selectFirst("th:contains(面向读者) + td").text().removeSuffix("漫画"))
|
list.add(document.selectFirst("th:contains(面向读者) + td")!!.text().removeSuffix("漫画"))
|
||||||
val tags = document.select("ul.tags > li > a")
|
val tags = document.select("ul.tags > li > a")
|
||||||
for (i in 1 until tags.size) { // skip status
|
for (i in 1 until tags.size) { // skip status
|
||||||
list.add(tags[i].text())
|
list.add(tags[i].text())
|
||||||
|
@ -101,12 +101,12 @@ abstract class MDB(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val imgData = document.selectFirst("body > script:containsData(img_data)").data()
|
val imgData = document.selectFirst("body > script:containsData(img_data)")!!.data()
|
||||||
.substringAfter("img_data = ").run {
|
.substringAfter("img_data = ").run {
|
||||||
val endIndex = indexOf(this[0], startIndex = 1) // find end quote
|
val endIndex = indexOf(this[0], startIndex = 1) // find end quote
|
||||||
substring(1, endIndex)
|
substring(1, endIndex)
|
||||||
}
|
}
|
||||||
val readerConfig = document.selectFirst(Evaluator.Class("vg-r-data"))
|
val readerConfig = document.selectFirst(Evaluator.Class("vg-r-data"))!!
|
||||||
return parseImages(imgData, readerConfig).mapIndexed { i, it ->
|
return parseImages(imgData, readerConfig).mapIndexed { i, it ->
|
||||||
Page(i, imageUrl = it)
|
Page(i, imageUrl = it)
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ abstract class MDB(
|
||||||
values.add(link.text())
|
values.add(link.text())
|
||||||
params.add(link.attr("href").let(::extractParams).let(::parseParam))
|
params.add(link.attr("href").let(::extractParams).let(::parseParam))
|
||||||
}
|
}
|
||||||
val name = children[0].selectFirst(Evaluator.Tag("span")).text()
|
val name = children[0].selectFirst(Evaluator.Tag("span"))!!.text()
|
||||||
list.add(Category(name, values.toTypedArray(), params))
|
list.add(Category(name, values.toTypedArray(), params))
|
||||||
} else if (filterContainer.hasClass("form-row")) { // Dropdown filter
|
} else if (filterContainer.hasClass("form-row")) { // Dropdown filter
|
||||||
for (select in filterContainer.select(Evaluator.Tag("select"))) {
|
for (select in filterContainer.select(Evaluator.Tag("select"))) {
|
||||||
|
|
|
@ -134,7 +134,7 @@ abstract class MMRCMS(
|
||||||
return client.newCall(GET("$baseUrl/changeMangaList?type=text", headers))
|
return client.newCall(GET("$baseUrl/changeMangaList?type=text", headers))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { response ->
|
.map { response ->
|
||||||
val mangas = response.asJsoup().select("ul.manga-list a")
|
val mangas = response.asJsoup().select("ul.manga-list a").toList()
|
||||||
.filter { it.text().contains(query, ignoreCase = true) }
|
.filter { it.text().contains(query, ignoreCase = true) }
|
||||||
.map {
|
.map {
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
|
@ -198,7 +198,7 @@ abstract class MMRCMS(
|
||||||
private fun latestUpdatesSelector() = "div.mangalist div.manga-item"
|
private fun latestUpdatesSelector() = "div.mangalist div.manga-item"
|
||||||
private fun latestUpdatesNextPageSelector() = "a[rel=next]"
|
private fun latestUpdatesNextPageSelector() = "a[rel=next]"
|
||||||
protected open fun latestUpdatesFromElement(element: Element, urlSelector: String): SManga? {
|
protected open fun latestUpdatesFromElement(element: Element, urlSelector: String): SManga? {
|
||||||
return element.select(urlSelector).first().let { titleElement ->
|
return element.select(urlSelector).first()!!.let { titleElement ->
|
||||||
if (titleElement.text() in latestTitles) {
|
if (titleElement.text() in latestTitles) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
|
@ -305,12 +305,12 @@ abstract class MMRCMS(
|
||||||
|
|
||||||
for (element in document.select(".row .dl-horizontal dt")) {
|
for (element in document.select(".row .dl-horizontal dt")) {
|
||||||
when (element.text().trim().lowercase().removeSuffix(":")) {
|
when (element.text().trim().lowercase().removeSuffix(":")) {
|
||||||
in detailAuthor -> author = element.nextElementSibling().text()
|
in detailAuthor -> author = element.nextElementSibling()!!.text()
|
||||||
in detailArtist -> artist = element.nextElementSibling().text()
|
in detailArtist -> artist = element.nextElementSibling()!!.text()
|
||||||
in detailGenre -> genre = element.nextElementSibling().select("a").joinToString {
|
in detailGenre -> genre = element.nextElementSibling()!!.select("a").joinToString {
|
||||||
it.text().trim()
|
it.text().trim()
|
||||||
}
|
}
|
||||||
in detailStatus -> status = when (element.nextElementSibling().text().trim().lowercase()) {
|
in detailStatus -> status = when (element.nextElementSibling()!!.text().trim().lowercase()) {
|
||||||
in detailStatusComplete -> SManga.COMPLETED
|
in detailStatusComplete -> SManga.COMPLETED
|
||||||
in detailStatusOngoing -> SManga.ONGOING
|
in detailStatusOngoing -> SManga.ONGOING
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
|
@ -367,7 +367,7 @@ abstract class MMRCMS(
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val titleWrapper = element.select("[class^=chapter-title-rtl]").first()
|
val titleWrapper = element.select("[class^=chapter-title-rtl]").first()!!
|
||||||
// Some websites add characters after "..-rtl" thus the need of checking classes that starts with that
|
// Some websites add characters after "..-rtl" thus the need of checking classes that starts with that
|
||||||
val url = titleWrapper.getElementsByTag("a")
|
val url = titleWrapper.getElementsByTag("a")
|
||||||
.first { it.attr("href").contains(urlRegex) }
|
.first { it.attr("href").contains(urlRegex) }
|
||||||
|
|
|
@ -41,9 +41,9 @@ abstract class MultiChan(
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.thumbnail_url = element.select("img").first().attr("src")
|
manga.thumbnail_url = element.select("img").first()!!.attr("src")
|
||||||
manga.title = element.attr("title")
|
manga.title = element.attr("title")
|
||||||
element.select("h2 > a").first().let {
|
element.select("h2 > a").first()!!.let {
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
manga.setUrlWithoutDomain(it.attr("href"))
|
||||||
}
|
}
|
||||||
return manga
|
return manga
|
||||||
|
@ -72,10 +72,10 @@ abstract class MultiChan(
|
||||||
|
|
||||||
val nextSearchPage = document.select(searchMangaNextPageSelector())
|
val nextSearchPage = document.select(searchMangaNextPageSelector())
|
||||||
if (nextSearchPage.isNotEmpty()) {
|
if (nextSearchPage.isNotEmpty()) {
|
||||||
val query = document.select("input#searchinput").first().attr("value")
|
val query = document.select("input#searchinput").first()!!.attr("value")
|
||||||
val pageNum = nextSearchPage.let { selector ->
|
val pageNum = nextSearchPage.let { selector ->
|
||||||
val onClick = selector.attr("onclick")
|
val onClick = selector.attr("onclick")
|
||||||
onClick?.split("""\\d+""")
|
onClick.split("""\\d+""")
|
||||||
}
|
}
|
||||||
nextSearchPage.attr("href", "$baseUrl/?do=search&subaction=search&story=$query&search_start=$pageNum")
|
nextSearchPage.attr("href", "$baseUrl/?do=search&subaction=search&story=$query&search_start=$pageNum")
|
||||||
hasNextPage = true
|
hasNextPage = true
|
||||||
|
@ -91,7 +91,7 @@ abstract class MultiChan(
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val infoElement = document.select("#info_wrap tr,#info_wrap > div")
|
val infoElement = document.select("#info_wrap tr,#info_wrap > div")
|
||||||
val descElement = document.select("div#description").first()
|
val descElement = document.select("div#description").first()!!
|
||||||
val rawCategory = infoElement.select(":contains(Тип) a").text().lowercase()
|
val rawCategory = infoElement.select(":contains(Тип) a").text().lowercase()
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.title = document.select("title").text().substringBefore(" »")
|
manga.title = document.select("title").text().substringBefore(" »")
|
||||||
|
@ -99,7 +99,7 @@ abstract class MultiChan(
|
||||||
manga.genre = rawCategory + ", " + document.select(".sidetags ul a:last-child").joinToString { it.text() }
|
manga.genre = rawCategory + ", " + document.select(".sidetags ul a:last-child").joinToString { it.text() }
|
||||||
manga.status = parseStatus(infoElement.select(":contains(Загружено)").text())
|
manga.status = parseStatus(infoElement.select(":contains(Загружено)").text())
|
||||||
manga.description = descElement.textNodes().first().text().trim()
|
manga.description = descElement.textNodes().first().text().trim()
|
||||||
manga.thumbnail_url = document.select("img#cover").first().attr("src")
|
manga.thumbnail_url = document.select("img#cover").first()!!.attr("src")
|
||||||
return manga
|
return manga
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,13 +112,13 @@ abstract class MultiChan(
|
||||||
override fun chapterListSelector() = "table.table_cha tr:gt(1)"
|
override fun chapterListSelector() = "table.table_cha tr:gt(1)"
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
val urlElement = element.select("a").first()
|
val urlElement = element.select("a").first()!!
|
||||||
|
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||||
chapter.name = urlElement.text()
|
chapter.name = urlElement.text()
|
||||||
chapter.chapter_number = "(глава\\s|часть\\s)([0-9]+\\.?[0-9]*)".toRegex(RegexOption.IGNORE_CASE).find(chapter.name)?.groupValues?.get(2)?.toFloat() ?: -1F
|
chapter.chapter_number = "(глава\\s|часть\\s)([0-9]+\\.?[0-9]*)".toRegex(RegexOption.IGNORE_CASE).find(chapter.name)?.groupValues?.get(2)?.toFloat() ?: -1F
|
||||||
chapter.date_upload = simpleDateFormat.parse(element.select("div.date").first().text())?.time ?: 0L
|
chapter.date_upload = simpleDateFormat.parse(element.select("div.date").first()!!.text())?.time ?: 0L
|
||||||
return chapter
|
return chapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,9 +86,9 @@ abstract class MyMangaCMS(
|
||||||
"div.pagination_wrap a.paging_item:last-of-type:not(.disabled)"
|
"div.pagination_wrap a.paging_item:last-of-type:not(.disabled)"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
setUrlWithoutDomain(element.select("a").first().attr("abs:href"))
|
setUrlWithoutDomain(element.select("a").first()!!.attr("abs:href"))
|
||||||
title = element.select("div.thumb_attr.series-title a[title]").first().text()
|
title = element.select("div.thumb_attr.series-title a[title]").first()!!.text()
|
||||||
thumbnail_url = element.select("div[data-bg]").first().attr("data-bg")
|
thumbnail_url = element.select("div[data-bg]").first()!!.attr("data-bg")
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
@ -179,10 +179,10 @@ abstract class MyMangaCMS(
|
||||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||||
setUrlWithoutDomain(
|
setUrlWithoutDomain(
|
||||||
document.select(".series-name-group a")
|
document.select(".series-name-group a")
|
||||||
.first()
|
.first()!!
|
||||||
.attr("abs:href"),
|
.attr("abs:href"),
|
||||||
)
|
)
|
||||||
title = document.select(".series-name").first().text().trim()
|
title = document.select(".series-name").first()!!.text().trim()
|
||||||
|
|
||||||
var alternativeNames: String? = null
|
var alternativeNames: String? = null
|
||||||
document.select(".info-item").forEach {
|
document.select(".info-item").forEach {
|
||||||
|
@ -194,7 +194,7 @@ abstract class MyMangaCMS(
|
||||||
"Tác giả:" -> author = value.joinToString(", ") { auth ->
|
"Tác giả:" -> author = value.joinToString(", ") { auth ->
|
||||||
auth.text().trim()
|
auth.text().trim()
|
||||||
}
|
}
|
||||||
"Tình trạng:" -> status = when (value.first().text().lowercase().trim()) {
|
"Tình trạng:" -> status = when (value.first()!!.text().lowercase().trim()) {
|
||||||
"đang tiến hành" -> SManga.ONGOING
|
"đang tiến hành" -> SManga.ONGOING
|
||||||
"tạm ngưng" -> SManga.ON_HIATUS
|
"tạm ngưng" -> SManga.ON_HIATUS
|
||||||
"đã hoàn thành" -> SManga.COMPLETED
|
"đã hoàn thành" -> SManga.COMPLETED
|
||||||
|
@ -226,7 +226,7 @@ abstract class MyMangaCMS(
|
||||||
|
|
||||||
thumbnail_url = document
|
thumbnail_url = document
|
||||||
.select("div.content.img-in-ratio")
|
.select("div.content.img-in-ratio")
|
||||||
.first()
|
.first()!!
|
||||||
.attr("style")
|
.attr("style")
|
||||||
.let { backgroundImageRegex.find(it)?.groups?.get(1)?.value }
|
.let { backgroundImageRegex.find(it)?.groups?.get(1)?.value }
|
||||||
}
|
}
|
||||||
|
@ -243,9 +243,9 @@ abstract class MyMangaCMS(
|
||||||
private fun chapterFromElement(element: Element, scanlator: String?): SChapter =
|
private fun chapterFromElement(element: Element, scanlator: String?): SChapter =
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
setUrlWithoutDomain(element.attr("abs:href"))
|
setUrlWithoutDomain(element.attr("abs:href"))
|
||||||
name = element.select("div.chapter-name").first().text()
|
name = element.select("div.chapter-name").first()!!.text()
|
||||||
date_upload = dateUpdatedParser(
|
date_upload = dateUpdatedParser(
|
||||||
element.select("div.chapter-time").first().text(),
|
element.select("div.chapter-time").first()!!.text(),
|
||||||
)
|
)
|
||||||
|
|
||||||
val match = floatingNumberRegex.find(name)
|
val match = floatingNumberRegex.find(name)
|
||||||
|
@ -262,11 +262,11 @@ abstract class MyMangaCMS(
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val originalScanlator = document.select("div.fantrans-value a")
|
val originalScanlator = document.select("div.fantrans-value a")
|
||||||
val scanlator: String? = if (originalScanlator.isEmpty() ||
|
val scanlator: String? = if (originalScanlator.isEmpty() ||
|
||||||
originalScanlator.first().text().trim().lowercase() == "đang cập nhật"
|
originalScanlator.first()!!.text().trim().lowercase() == "đang cập nhật"
|
||||||
) {
|
) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
originalScanlator.first().text().trim()
|
originalScanlator.first()!!.text().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
return document.select(chapterListSelector()).map { chapterFromElement(it, scanlator) }
|
return document.select(chapterListSelector()).map { chapterFromElement(it, scanlator) }
|
||||||
|
|
|
@ -77,7 +77,7 @@ abstract class NepNep(
|
||||||
|
|
||||||
// don't use ";" for substringBefore() !
|
// don't use ";" for substringBefore() !
|
||||||
private fun directoryFromDocument(document: Document): JsonArray {
|
private fun directoryFromDocument(document: Document): JsonArray {
|
||||||
val str = document.select("script:containsData(MainFunction)").first().data()
|
val str = document.select("script:containsData(MainFunction)").first()!!.data()
|
||||||
.substringAfter("vm.Directory = ").substringBefore("vm.GetIntValue").trim()
|
.substringAfter("vm.Directory = ").substringBefore("vm.GetIntValue").trim()
|
||||||
.replace(";", " ")
|
.replace(";", " ")
|
||||||
return json.parseToJsonElement(str).jsonArray
|
return json.parseToJsonElement(str).jsonArray
|
||||||
|
@ -85,7 +85,7 @@ abstract class NepNep(
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
thumbnailUrl = document.select(".SearchResult > .SearchResultCover img").first().attr("ng-src")
|
thumbnailUrl = document.select(".SearchResult > .SearchResultCover img").first()!!.attr("ng-src")
|
||||||
directory = directoryFromDocument(document).sortedByDescending { it.getString("v") }
|
directory = directoryFromDocument(document).sortedByDescending { it.getString("v") }
|
||||||
return parseDirectory(1)
|
return parseDirectory(1)
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ abstract class NepNep(
|
||||||
private fun getThumbnailUrl(id: String): String {
|
private fun getThumbnailUrl(id: String): String {
|
||||||
if (thumbnailUrl.isNullOrEmpty()) {
|
if (thumbnailUrl.isNullOrEmpty()) {
|
||||||
val response = client.newCall(popularMangaRequest(1)).execute()
|
val response = client.newCall(popularMangaRequest(1)).execute()
|
||||||
thumbnailUrl = response.asJsoup().select(".SearchResult > .SearchResultCover img").first().attr("ng-src")
|
thumbnailUrl = response.asJsoup().select(".SearchResult > .SearchResultCover img").first()!!.attr("ng-src")
|
||||||
}
|
}
|
||||||
|
|
||||||
return thumbnailUrl!!.replace("{{Result.i}}", id)
|
return thumbnailUrl!!.replace("{{Result.i}}", id)
|
||||||
|
@ -308,7 +308,7 @@ abstract class NepNep(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val vmChapters = response.asJsoup().select("script:containsData(MainFunction)").first().data()
|
val vmChapters = response.asJsoup().select("script:containsData(MainFunction)").first()!!.data()
|
||||||
.substringAfter("vm.Chapters = ").substringBefore(";")
|
.substringAfter("vm.Chapters = ").substringBefore(";")
|
||||||
return json.parseToJsonElement(vmChapters).jsonArray.map { json ->
|
return json.parseToJsonElement(vmChapters).jsonArray.map { json ->
|
||||||
val indexChapter = json.getString("Chapter")!!
|
val indexChapter = json.getString("Chapter")!!
|
||||||
|
@ -330,7 +330,7 @@ abstract class NepNep(
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val script = document.selectFirst("script:containsData(MainFunction)")?.data()
|
val script = document.selectFirst("script:containsData(MainFunction)")?.data()
|
||||||
?: client.newCall(GET(document.location().removeSuffix(".html"), headers))
|
?: client.newCall(GET(document.location().removeSuffix(".html"), headers))
|
||||||
.execute().asJsoup().selectFirst("script:containsData(MainFunction)").data()
|
.execute().asJsoup().selectFirst("script:containsData(MainFunction)")!!.data()
|
||||||
val curChapter = json.parseToJsonElement(script!!.substringAfter("vm.CurChapter = ").substringBefore(";")).jsonObject
|
val curChapter = json.parseToJsonElement(script!!.substringAfter("vm.CurChapter = ").substringBefore(";")).jsonObject
|
||||||
|
|
||||||
val pageTotal = curChapter.getString("Page")!!.toInt()
|
val pageTotal = curChapter.getString("Page")!!.toInt()
|
||||||
|
|
|
@ -56,7 +56,7 @@ open class OtakuSanctuary(
|
||||||
val page = emptyList<SManga>().toMutableList()
|
val page = emptyList<SManga>().toMutableList()
|
||||||
|
|
||||||
for (element in elements) {
|
for (element in elements) {
|
||||||
val url = element.select("div.mdl-card__title a").first().attr("abs:href")
|
val url = element.select("div.mdl-card__title a").first()!!.attr("abs:href")
|
||||||
// ignore external chapters
|
// ignore external chapters
|
||||||
if (url.toHttpUrl().host != baseUrl.toHttpUrl().host) {
|
if (url.toHttpUrl().host != baseUrl.toHttpUrl().host) {
|
||||||
continue
|
continue
|
||||||
|
@ -80,7 +80,7 @@ open class OtakuSanctuary(
|
||||||
setUrlWithoutDomain(url)
|
setUrlWithoutDomain(url)
|
||||||
title = element.select("div.mdl-card__supporting-text a[target=_blank]").text()
|
title = element.select("div.mdl-card__supporting-text a[target=_blank]").text()
|
||||||
.replaceFirstChar { it.titlecase() }
|
.replaceFirstChar { it.titlecase() }
|
||||||
thumbnail_url = element.select("div.container-3-4.background-contain img").first().attr("abs:src")
|
thumbnail_url = element.select("div.container-3-4.background-contain img").first()!!.attr("abs:src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return page
|
return page
|
||||||
|
@ -118,7 +118,7 @@ open class OtakuSanctuary(
|
||||||
title = document.select("h1.title.text-lg-left.text-overflow-2-line")
|
title = document.select("h1.title.text-lg-left.text-overflow-2-line")
|
||||||
.text()
|
.text()
|
||||||
.replaceFirstChar { it.titlecase() }
|
.replaceFirstChar { it.titlecase() }
|
||||||
author = document.select("tr:contains(Tác Giả) a.capitalize").first().text()
|
author = document.select("tr:contains(Tác Giả) a.capitalize").first()!!.text()
|
||||||
.replaceFirstChar { it.titlecase() }
|
.replaceFirstChar { it.titlecase() }
|
||||||
description = document.select("div.summary p").joinToString("\n") {
|
description = document.select("div.summary p").joinToString("\n") {
|
||||||
it.run {
|
it.run {
|
||||||
|
@ -129,7 +129,7 @@ open class OtakuSanctuary(
|
||||||
genre = document.select("div.genres a").joinToString { it.text() }
|
genre = document.select("div.genres a").joinToString { it.text() }
|
||||||
thumbnail_url = document.select("div.container-3-4.background-contain img").attr("abs:src")
|
thumbnail_url = document.select("div.container-3-4.background-contain img").attr("abs:src")
|
||||||
|
|
||||||
val statusString = document.select("tr:contains(Tình Trạng) td").first().text().trim()
|
val statusString = document.select("tr:contains(Tình Trạng) td").first()!!.text().trim()
|
||||||
status = when (statusString) {
|
status = when (statusString) {
|
||||||
"Ongoing" -> SManga.ONGOING
|
"Ongoing" -> SManga.ONGOING
|
||||||
"Done" -> SManga.COMPLETED
|
"Done" -> SManga.COMPLETED
|
||||||
|
@ -155,7 +155,7 @@ open class OtakuSanctuary(
|
||||||
else -> 0L
|
else -> 0L
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return kotlin.runCatching { dateFormat.parse(date)?.time }.getOrNull() ?: 0L
|
return runCatching { dateFormat.parse(date)?.time }.getOrNull() ?: 0L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,10 +44,10 @@ abstract class SinMH(
|
||||||
protected open val comicItemSelector = "#contList > li, li.list-comic"
|
protected open val comicItemSelector = "#contList > li, li.list-comic"
|
||||||
protected open val comicItemTitleSelector = "p > a, h3 > a"
|
protected open val comicItemTitleSelector = "p > a, h3 > a"
|
||||||
protected open fun mangaFromElement(element: Element) = SManga.create().apply {
|
protected open fun mangaFromElement(element: Element) = SManga.create().apply {
|
||||||
val titleElement = element.selectFirst(comicItemTitleSelector)
|
val titleElement = element.selectFirst(comicItemTitleSelector)!!
|
||||||
title = titleElement.text()
|
title = titleElement.text()
|
||||||
setUrlWithoutDomain(titleElement.attr("href"))
|
setUrlWithoutDomain(titleElement.attr("href"))
|
||||||
val image = element.selectFirst(Evaluator.Tag("img"))
|
val image = element.selectFirst(Evaluator.Tag("img"))!!
|
||||||
thumbnail_url = image.attr("src").ifEmpty { image.attr("data-src") }
|
thumbnail_url = image.attr("src").ifEmpty { image.attr("data-src") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,24 +102,24 @@ abstract class SinMH(
|
||||||
// Details
|
// Details
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
title = document.selectFirst(".book-title > h1").text()
|
title = document.selectFirst(".book-title > h1")!!.text()
|
||||||
val detailsList = document.selectFirst(Evaluator.Class("detail-list"))
|
val detailsList = document.selectFirst(Evaluator.Class("detail-list"))!!
|
||||||
author = detailsList.select("strong:contains(作者) ~ *").text()
|
author = detailsList.select("strong:contains(作者) ~ *").text()
|
||||||
description = document.selectFirst(Evaluator.Id("intro-all")).text().trim()
|
description = document.selectFirst(Evaluator.Id("intro-all"))!!.text().trim()
|
||||||
.removePrefix("漫画简介:").trim()
|
.removePrefix("漫画简介:").trim()
|
||||||
.removePrefix("漫画简介:").trim() // some sources have double prefix
|
.removePrefix("漫画简介:").trim() // some sources have double prefix
|
||||||
genre = mangaDetailsParseDefaultGenre(document, detailsList)
|
genre = mangaDetailsParseDefaultGenre(document, detailsList)
|
||||||
status = when (detailsList.selectFirst("strong:contains(状态) + *").text()) {
|
status = when (detailsList.selectFirst("strong:contains(状态) + *")!!.text()) {
|
||||||
"连载中" -> SManga.ONGOING
|
"连载中" -> SManga.ONGOING
|
||||||
"已完结" -> SManga.COMPLETED
|
"已完结" -> SManga.COMPLETED
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
thumbnail_url = document.selectFirst("div.book-cover img").attr("src")
|
thumbnail_url = document.selectFirst("div.book-cover img")!!.attr("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun mangaDetailsParseDefaultGenre(document: Document, detailsList: Element): String {
|
protected open fun mangaDetailsParseDefaultGenre(document: Document, detailsList: Element): String {
|
||||||
val category = detailsList.selectFirst("strong:contains(类型) + a")
|
val category = detailsList.selectFirst("strong:contains(类型) + a")!!
|
||||||
val breadcrumbs = document.selectFirst("div.breadcrumb-bar").select("a[href^=/list/]")
|
val breadcrumbs = document.selectFirst("div.breadcrumb-bar")!!.select("a[href^=/list/]")
|
||||||
return buildString {
|
return buildString {
|
||||||
append(category.text())
|
append(category.text())
|
||||||
breadcrumbs.map(Element::text).filter(String::isNotEmpty).joinTo(this, prefix = ", ")
|
breadcrumbs.map(Element::text).filter(String::isNotEmpty).joinTo(this, prefix = ", ")
|
||||||
|
@ -127,23 +127,23 @@ abstract class SinMH(
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun mangaDetailsParseDMZJStyle(document: Document, hasBreadcrumb: Boolean) = SManga.create().apply {
|
protected fun mangaDetailsParseDMZJStyle(document: Document, hasBreadcrumb: Boolean) = SManga.create().apply {
|
||||||
val detailsDiv = document.selectFirst("div.comic_deCon")
|
val detailsDiv = document.selectFirst("div.comic_deCon")!!
|
||||||
title = detailsDiv.selectFirst(Evaluator.Tag("h1")).text()
|
title = detailsDiv.selectFirst(Evaluator.Tag("h1"))!!.text()
|
||||||
val details = detailsDiv.select("> ul > li")
|
val details = detailsDiv.select("> ul > li")
|
||||||
val linkSelector = Evaluator.Tag("a")
|
val linkSelector = Evaluator.Tag("a")
|
||||||
author = details[0].selectFirst(linkSelector).text()
|
author = details[0].selectFirst(linkSelector)!!.text()
|
||||||
status = when (details[1].selectFirst(linkSelector).text()) {
|
status = when (details[1].selectFirst(linkSelector)!!.text()) {
|
||||||
"连载中" -> SManga.ONGOING
|
"连载中" -> SManga.ONGOING
|
||||||
"已完结" -> SManga.COMPLETED
|
"已完结" -> SManga.COMPLETED
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
genre = mutableListOf<Element>().apply {
|
genre = mutableListOf<Element>().apply {
|
||||||
add(details[2].selectFirst(linkSelector)) // 类别
|
add(details[2].selectFirst(linkSelector)!!) // 类别
|
||||||
addAll(details[3].select(linkSelector)) // 类型
|
addAll(details[3].select(linkSelector)) // 类型
|
||||||
if (hasBreadcrumb) addAll(document.selectFirst("div.mianbao").select("a[href^=/list/]"))
|
if (hasBreadcrumb) addAll(document.selectFirst("div.mianbao")!!.select("a[href^=/list/]"))
|
||||||
}.mapTo(mutableSetOf()) { it.text() }.joinToString(", ")
|
}.mapTo(mutableSetOf()) { it.text() }.joinToString(", ")
|
||||||
description = detailsDiv.selectFirst("> p.comic_deCon_d").text()
|
description = detailsDiv.selectFirst("> p.comic_deCon_d")!!.text()
|
||||||
thumbnail_url = document.selectFirst("div.comic_i_img > img").attr("src")
|
thumbnail_url = document.selectFirst("div.comic_i_img > img")!!.attr("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chapters
|
// Chapters
|
||||||
|
@ -167,7 +167,7 @@ abstract class SinMH(
|
||||||
section.select(itemSelector).map { chapterFromElement(it) }.sortedDescending()
|
section.select(itemSelector).map { chapterFromElement(it) }.sortedDescending()
|
||||||
}
|
}
|
||||||
if (isNewDateLogic && list.isNotEmpty()) {
|
if (isNewDateLogic && list.isNotEmpty()) {
|
||||||
val date = document.selectFirst(dateSelector).textNodes().last().text()
|
val date = document.selectFirst(dateSelector)!!.textNodes().last().text()
|
||||||
list[0].date_upload = DATE_FORMAT.parse(date)?.time ?: 0L
|
list[0].date_upload = DATE_FORMAT.parse(date)?.time ?: 0L
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
|
@ -194,7 +194,7 @@ abstract class SinMH(
|
||||||
|
|
||||||
// baseUrl/js/common.js/getChapterImage()
|
// baseUrl/js/common.js/getChapterImage()
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val script = document.selectFirst("body > script").html().let(::ProgressiveParser)
|
val script = document.selectFirst("body > script")!!.html().let(::ProgressiveParser)
|
||||||
val images = script.substringBetween("chapterImages = ", ";")
|
val images = script.substringBetween("chapterImages = ", ";")
|
||||||
if (images.length <= 2) return emptyList() // [] or ""
|
if (images.length <= 2) return emptyList() // [] or ""
|
||||||
val path = script.substringBetween("chapterPath = \"", "\";")
|
val path = script.substringBetween("chapterPath = \"", "\";")
|
||||||
|
@ -237,8 +237,8 @@ abstract class SinMH(
|
||||||
if (categories.isNotEmpty()) return
|
if (categories.isNotEmpty()) return
|
||||||
val labelSelector = Evaluator.Tag("label")
|
val labelSelector = Evaluator.Tag("label")
|
||||||
val linkSelector = Evaluator.Tag("a")
|
val linkSelector = Evaluator.Tag("a")
|
||||||
categories = document.selectFirst(Evaluator.Class("filter-nav")).children().map { element ->
|
categories = document.selectFirst(Evaluator.Class("filter-nav"))!!.children().map { element ->
|
||||||
val name = element.selectFirst(labelSelector).text()
|
val name = element.selectFirst(labelSelector)!!.text()
|
||||||
val tags = element.select(linkSelector)
|
val tags = element.select(linkSelector)
|
||||||
val values = tags.map { it.text() }.toTypedArray()
|
val values = tags.map { it.text() }.toTypedArray()
|
||||||
val uriParts = tags.map { it.attr("href").removePrefix("/list/").removeSuffix("/") }.toTypedArray()
|
val uriParts = tags.map { it.attr("href").removePrefix("/list/").removeSuffix("/") }.toTypedArray()
|
||||||
|
|
|
@ -196,7 +196,7 @@ open class Webtoons(
|
||||||
open fun parseDetailsThumbnail(document: Document): String? {
|
open fun parseDetailsThumbnail(document: Document): String? {
|
||||||
val picElement = document.select("#content > div.cont_box > div.detail_body")
|
val picElement = document.select("#content > div.cont_box > div.detail_body")
|
||||||
val discoverPic = document.select("#content > div.cont_box > div.detail_header > span.thmb")
|
val discoverPic = document.select("#content > div.cont_box > div.detail_header > span.thmb")
|
||||||
return discoverPic.select("img").not("[alt='Representative image']").first()?.attr("src") ?: picElement.attr("style")?.substringAfter("url(")?.substringBeforeLast(")")
|
return discoverPic.select("img").not("[alt='Representative image']").first()?.attr("src") ?: picElement.attr("style").substringAfter("url(")?.substringBeforeLast(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
|
@ -204,7 +204,7 @@ open class Webtoons(
|
||||||
val infoElement = document.select("#_asideDetail")
|
val infoElement = document.select("#_asideDetail")
|
||||||
|
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.title = document.selectFirst("h1.subj, h3.subj").text()
|
manga.title = document.selectFirst("h1.subj, h3.subj")!!.text()
|
||||||
manga.author = detailElement.select(".author:nth-of-type(1)").first()?.ownText()
|
manga.author = detailElement.select(".author:nth-of-type(1)").first()?.ownText()
|
||||||
manga.artist = detailElement.select(".author:nth-of-type(2)").first()?.ownText() ?: manga.author
|
manga.artist = detailElement.select(".author:nth-of-type(2)").first()?.ownText() ?: manga.author
|
||||||
manga.genre = detailElement.select(".genre").joinToString(", ") { it.text() }
|
manga.genre = detailElement.select(".genre").joinToString(", ") { it.text() }
|
||||||
|
@ -220,7 +220,7 @@ open class Webtoons(
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String = document.select("img").first().attr("src")
|
override fun imageUrlParse(document: Document): String = document.select("img").first()!!.attr("src")
|
||||||
|
|
||||||
// Filters
|
// Filters
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ open class Webtoons(
|
||||||
if (element.select(".ico_bgm").isNotEmpty()) {
|
if (element.select(".ico_bgm").isNotEmpty()) {
|
||||||
chapter.name += " ♫"
|
chapter.name += " ♫"
|
||||||
}
|
}
|
||||||
chapter.date_upload = element.select("a > div.row > div.col > div.sub_info > span.date").text()?.let { chapterParseDate(it) } ?: 0
|
chapter.date_upload = element.select("a > div.row > div.col > div.sub_info > span.date").text().let { chapterParseDate(it) } ?: 0
|
||||||
return chapter
|
return chapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ abstract class WPComics(
|
||||||
title = it.text()
|
title = it.text()
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
}
|
}
|
||||||
thumbnail_url = imageOrNull(element.select("div.image:first-of-type img").first())
|
thumbnail_url = imageOrNull(element.select("div.image:first-of-type img").first()!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ abstract class WPComics(
|
||||||
title = it.text()
|
title = it.text()
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
}
|
}
|
||||||
thumbnail_url = imageOrNull(element.select("div.image a img").first())
|
thumbnail_url = imageOrNull(element.select("div.image a img").first()!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ abstract class WPComics(
|
||||||
status = info.select("li.status p.col-xs-8").text().toStatus()
|
status = info.select("li.status p.col-xs-8").text().toStatus()
|
||||||
genre = info.select("li.kind p.col-xs-8 a").joinToString { it.text() }
|
genre = info.select("li.kind p.col-xs-8 a").joinToString { it.text() }
|
||||||
description = info.select("div.detail-content p").text()
|
description = info.select("div.detail-content p").text()
|
||||||
thumbnail_url = imageOrNull(info.select("div.col-image img").first())
|
thumbnail_url = imageOrNull(info.select("div.col-image img").first()!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ abstract class Zbulu(
|
||||||
setUrlWithoutDomain(it.attr("href").addTrailingSlash())
|
setUrlWithoutDomain(it.attr("href").addTrailingSlash())
|
||||||
title = it.text()
|
title = it.text()
|
||||||
}
|
}
|
||||||
thumbnail_url = element.select("img").first().attr("abs:src")
|
thumbnail_url = element.select("img").first()!!.attr("abs:src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,10 +100,10 @@ abstract class Zbulu(
|
||||||
// Manga summary page
|
// Manga summary page
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val infoElement = document.select("div.single-comic").first()
|
val infoElement = document.select("div.single-comic").first()!!
|
||||||
|
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
title = infoElement.select("h1").first().text()
|
title = infoElement.select("h1").first()!!.text()
|
||||||
author = infoElement.select("div.author a").text()
|
author = infoElement.select("div.author a").text()
|
||||||
status = parseStatus(infoElement.select("div.update span[style]").text())
|
status = parseStatus(infoElement.select("div.update span[style]").text())
|
||||||
genre = infoElement.select("div.genre a").joinToString { it.text() }
|
genre = infoElement.select("div.genre a").joinToString { it.text() }
|
||||||
|
@ -141,7 +141,7 @@ abstract class Zbulu(
|
||||||
return SChapter.create().apply {
|
return SChapter.create().apply {
|
||||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
setUrlWithoutDomain(element.select("a").attr("href"))
|
||||||
name = element.select("h2").text()
|
name = element.select("h2").text()
|
||||||
date_upload = element.select("div.chapter-date")?.text().toDate()
|
date_upload = element.select("div.chapter-date").text().toDate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ abstract class ZeistManga(
|
||||||
open val imgSelectorAttr = "src"
|
open val imgSelectorAttr = "src"
|
||||||
|
|
||||||
open fun getChaptersUrl(doc: Document): String {
|
open fun getChaptersUrl(doc: Document): String {
|
||||||
val script = doc.selectFirst(scriptSelector)
|
val script = doc.selectFirst(scriptSelector)!!
|
||||||
val feed = chapterFeedRegex
|
val feed = chapterFeedRegex
|
||||||
.find(script.html())
|
.find(script.html())
|
||||||
?.groupValues?.get(1)
|
?.groupValues?.get(1)
|
||||||
|
@ -109,17 +109,17 @@ abstract class ZeistManga(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val profileManga = document.selectFirst(".grid.gtc-235fr")
|
val profileManga = document.selectFirst(".grid.gtc-235fr")!!
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
title = profileManga.selectFirst("h1.mt-0.mb-6.fs-20").text()
|
title = profileManga.selectFirst("h1.mt-0.mb-6.fs-20")!!.text()
|
||||||
thumbnail_url = profileManga.selectFirst("img").attr("src")
|
thumbnail_url = profileManga.selectFirst("img")!!.attr("src")
|
||||||
description = profileManga.select("#synopsis").text()
|
description = profileManga.select("#synopsis").text()
|
||||||
status = SManga.UNKNOWN
|
status = SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val images = document.selectFirst("div.check-box")
|
val images = document.selectFirst("div.check-box")!!
|
||||||
return images.select(imgSelector).mapIndexed { i, img ->
|
return images.select(imgSelector).mapIndexed { i, img ->
|
||||||
Page(i, "", img.attr(imgSelectorAttr))
|
Page(i, "", img.attr(imgSelectorAttr))
|
||||||
}
|
}
|
||||||
|
@ -153,8 +153,8 @@ abstract class ZeistManga(
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
override fun searchMangaFromElement(element: Element): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
setUrlWithoutDomain(element.select(".block").attr("href"))
|
setUrlWithoutDomain(element.select(".block").attr("href"))
|
||||||
title = element.selectFirst(".clamp.toe.oh.block").text().trim()
|
title = element.selectFirst(".clamp.toe.oh.block")!!.text().trim()
|
||||||
thumbnail_url = element.selectFirst("img").attr("src")
|
thumbnail_url = element.selectFirst("img")!!.attr("src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ data class ZeistMangaEntryDto(
|
||||||
|
|
||||||
private fun getThumbnail(html: ZeistMangaEntryContentDto): String {
|
private fun getThumbnail(html: ZeistMangaEntryContentDto): String {
|
||||||
val document = Jsoup.parse(html.t)
|
val document = Jsoup.parse(html.t)
|
||||||
return document.selectFirst("img").attr("src")
|
return document.selectFirst("img")!!.attr("src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ abstract class ZManga(
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
setUrlWithoutDomain(element.select("div.flexbox2-content a").attr("href"))
|
setUrlWithoutDomain(element.select("div.flexbox2-content a").attr("href"))
|
||||||
title = element.select("div.flexbox2-title > span").first().text()
|
title = element.select("div.flexbox2-title > span").first()!!.text()
|
||||||
thumbnail_url = element.select("img").attr("abs:src")
|
thumbnail_url = element.select("img").attr("abs:src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ abstract class ZManga(
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
return SChapter.create().apply {
|
return SChapter.create().apply {
|
||||||
setUrlWithoutDomain(element.attr("href"))
|
setUrlWithoutDomain(element.attr("href"))
|
||||||
name = element.select("span").first().ownText()
|
name = element.select("span").first()!!.ownText()
|
||||||
date_upload = parseDate(element.select("span.date").text())
|
date_upload = parseDate(element.select("span.date").text())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,9 +361,9 @@ open class BatoTo(
|
||||||
return Jsoup.parse(response.body.string(), response.request.url.toString(), Parser.xmlParser())
|
return Jsoup.parse(response.body.string(), response.request.url.toString(), Parser.xmlParser())
|
||||||
.select("channel > item").map { item ->
|
.select("channel > item").map { item ->
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
url = item.selectFirst("guid").text()
|
url = item.selectFirst("guid")!!.text()
|
||||||
name = item.selectFirst("title").text().substringAfter(title).trim()
|
name = item.selectFirst("title")!!.text().substringAfter(title).trim()
|
||||||
date_upload = SimpleDateFormat("E, dd MMM yyyy H:m:s Z", Locale.US).parse(item.selectFirst("pubDate").text())?.time ?: 0L
|
date_upload = SimpleDateFormat("E, dd MMM yyyy H:m:s Z", Locale.US).parse(item.selectFirst("pubDate")!!.text())?.time ?: 0L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ class BuonDua() : ParsedHttpSource() {
|
||||||
manga.title = document.select(".article-header").text()
|
manga.title = document.select(".article-header").text()
|
||||||
manga.description = document.select(".article-info > strong").text().trim()
|
manga.description = document.select(".article-info > strong").text().trim()
|
||||||
val genres = mutableListOf<String>()
|
val genres = mutableListOf<String>()
|
||||||
document.select(".article-tags").first().select(".tags > .tag").forEach {
|
document.select(".article-tags").first()!!.select(".tags > .tag").forEach {
|
||||||
genres.add(it.text().substringAfter("#"))
|
genres.add(it.text().substringAfter("#"))
|
||||||
}
|
}
|
||||||
manga.genre = genres.joinToString(", ")
|
manga.genre = genres.joinToString(", ")
|
||||||
|
@ -74,7 +74,7 @@ class BuonDua() : ParsedHttpSource() {
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
chapter.setUrlWithoutDomain(element.select(".is-current").first().attr("abs:href"))
|
chapter.setUrlWithoutDomain(element.select(".is-current").first()!!.attr("abs:href"))
|
||||||
chapter.chapter_number = 0F
|
chapter.chapter_number = 0F
|
||||||
chapter.name = element.select(".article-header").text()
|
chapter.name = element.select(".article-header").text()
|
||||||
chapter.date_upload = SimpleDateFormat("H:m DD-MM-yyyy", Locale.US).parse(element.select(".article-info > small").text())?.time ?: 0L
|
chapter.date_upload = SimpleDateFormat("H:m DD-MM-yyyy", Locale.US).parse(element.select(".article-info > small").text())?.time ?: 0L
|
||||||
|
@ -86,7 +86,7 @@ class BuonDua() : ParsedHttpSource() {
|
||||||
// Pages
|
// Pages
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val numpages = document.selectFirst(".pagination-list").select(".pagination-link")
|
val numpages = document.selectFirst(".pagination-list")!!.select(".pagination-link")
|
||||||
val pages = mutableListOf<Page>()
|
val pages = mutableListOf<Page>()
|
||||||
|
|
||||||
numpages.forEachIndexed { index, page ->
|
numpages.forEachIndexed { index, page ->
|
||||||
|
@ -94,7 +94,7 @@ class BuonDua() : ParsedHttpSource() {
|
||||||
0 -> document
|
0 -> document
|
||||||
else -> client.newCall(GET(page.attr("abs:href"))).execute().asJsoup()
|
else -> client.newCall(GET(page.attr("abs:href"))).execute().asJsoup()
|
||||||
}
|
}
|
||||||
doc.select(".article-fulltext img").forEach { it ->
|
doc.select(".article-fulltext img").forEach {
|
||||||
val itUrl = it.attr("abs:src")
|
val itUrl = it.attr("abs:src")
|
||||||
pages.add(Page(pages.size, "", itUrl))
|
pages.add(Page(pages.size, "", itUrl))
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ abstract class EHentai(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get image
|
// Get image
|
||||||
it.parent().select(".glthumb img")?.first().apply {
|
it.parent()?.select(".glthumb img")?.first().apply {
|
||||||
thumbnail_url = this?.attr("data-src")?.nullIfBlank()
|
thumbnail_url = this?.attr("data-src")?.nullIfBlank()
|
||||||
?: this?.attr("src")
|
?: this?.attr("src")
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ class EveriaClub() : ParsedHttpSource() {
|
||||||
// Latest
|
// Latest
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
override fun latestUpdatesFromElement(element: Element): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.thumbnail_url = element.selectFirst("img").imgSrc
|
manga.thumbnail_url = element.selectFirst("img")!!.imgSrc
|
||||||
manga.title = element.select(".entry-title").text()
|
manga.title = element.select(".entry-title").text()
|
||||||
manga.setUrlWithoutDomain(element.select(".entry-title > a").attr("abs:href"))
|
manga.setUrlWithoutDomain(element.select(".entry-title > a").attr("abs:href"))
|
||||||
return manga
|
return manga
|
||||||
|
@ -46,7 +46,7 @@ class EveriaClub() : ParsedHttpSource() {
|
||||||
// Popular
|
// Popular
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.thumbnail_url = element.selectFirst("img").imgSrc
|
manga.thumbnail_url = element.selectFirst("img")!!.imgSrc
|
||||||
manga.title = element.select("h3").text()
|
manga.title = element.select("h3").text()
|
||||||
manga.setUrlWithoutDomain(element.select("h3 > a").attr("abs:href"))
|
manga.setUrlWithoutDomain(element.select("h3 > a").attr("abs:href"))
|
||||||
return manga
|
return manga
|
||||||
|
|
|
@ -46,10 +46,10 @@ class Hennojin(override val lang: String, suffix: String) : ParsedHttpSource() {
|
||||||
override fun popularMangaFromElement(element: Element) =
|
override fun popularMangaFromElement(element: Element) =
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
element.selectFirst(".title_link > a").let {
|
element.selectFirst(".title_link > a").let {
|
||||||
title = it.text()
|
title = it!!.text()
|
||||||
setUrlWithoutDomain(it.attr("href"))
|
setUrlWithoutDomain(it.attr("href"))
|
||||||
}
|
}
|
||||||
thumbnail_url = element.selectFirst("img").attr("src")
|
thumbnail_url = element.selectFirst("img")!!.attr("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaSelector() = popularMangaSelector()
|
override fun searchMangaSelector() = popularMangaSelector()
|
||||||
|
|
|
@ -125,8 +125,7 @@ class IMHentai(override val lang: String, private val imhLang: String) : ParsedH
|
||||||
url.addQueryParameter(pair.second, toBinary(filter.state == index))
|
url.addQueryParameter(pair.second, toBinary(filter.state == index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,9 +140,9 @@ class IMHentai(override val lang: String, private val imhLang: String) : ParsedH
|
||||||
return this.joinToString {
|
return this.joinToString {
|
||||||
listOf(
|
listOf(
|
||||||
it.ownText(),
|
it.ownText(),
|
||||||
it.select(".split_tag")?.text()
|
it.select(".split_tag").text()
|
||||||
?.trim()
|
.trim()
|
||||||
?.removePrefix("| "),
|
.removePrefix("| "),
|
||||||
)
|
)
|
||||||
.filter { s -> !s.isNullOrBlank() }
|
.filter { s -> !s.isNullOrBlank() }
|
||||||
.joinToString(splitTagSeparator)
|
.joinToString(splitTagSeparator)
|
||||||
|
@ -151,16 +150,16 @@ class IMHentai(override val lang: String, private val imhLang: String) : ParsedH
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||||
title = document.selectFirst("div.right_details > h1").text()
|
title = document.selectFirst("div.right_details > h1")!!.text()
|
||||||
|
|
||||||
thumbnail_url = document.selectFirst("div.left_cover img")?.let {
|
thumbnail_url = document.selectFirst("div.left_cover img")?.let {
|
||||||
it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
|
it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
|
||||||
}
|
}
|
||||||
|
|
||||||
val mangaInfoElement = document.select(".galleries_info")
|
val mangaInfoElement = document.select(".galleries_info")
|
||||||
val infoMap = mangaInfoElement.select("li:not(.pages)").map {
|
val infoMap = mangaInfoElement.select("li:not(.pages)").associate {
|
||||||
it.select("span.tags_text").text().removeSuffix(":") to it.select(".tag")
|
it.select("span.tags_text").text().removeSuffix(":") to it.select(".tag")
|
||||||
}.toMap()
|
}
|
||||||
|
|
||||||
artist = infoMap["Artists"]?.csvText(" | ")
|
artist = infoMap["Artists"]?.csvText(" | ")
|
||||||
|
|
||||||
|
@ -206,11 +205,11 @@ class IMHentai(override val lang: String, private val imhLang: String) : ParsedH
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val image_dir = document.select("#image_dir").`val`()
|
val imageDir = document.select("#image_dir").`val`()
|
||||||
val gallery_id = document.select("#gallery_id").`val`()
|
val galleryId = document.select("#gallery_id").`val`()
|
||||||
val u_id = document.select("#u_id").`val`().toInt()
|
val uId = document.select("#u_id").`val`().toInt()
|
||||||
|
|
||||||
val random_server = when (u_id) {
|
val randomServer = when (uId) {
|
||||||
in 1..274825 -> "m1.imhentai.xxx"
|
in 1..274825 -> "m1.imhentai.xxx"
|
||||||
in 274826..403818 -> "m2.imhentai.xxx"
|
in 274826..403818 -> "m2.imhentai.xxx"
|
||||||
in 403819..527143 -> "m3.imhentai.xxx"
|
in 403819..527143 -> "m3.imhentai.xxx"
|
||||||
|
@ -221,20 +220,20 @@ class IMHentai(override val lang: String, private val imhLang: String) : ParsedH
|
||||||
}
|
}
|
||||||
|
|
||||||
val images = json.parseToJsonElement(
|
val images = json.parseToJsonElement(
|
||||||
document.selectFirst("script:containsData(var g_th)").data()
|
document.selectFirst("script:containsData(var g_th)")!!.data()
|
||||||
.substringAfter("$.parseJSON('").substringBefore("');").trim(),
|
.substringAfter("$.parseJSON('").substringBefore("');").trim(),
|
||||||
).jsonObject
|
).jsonObject
|
||||||
val pages = mutableListOf<Page>()
|
val pages = mutableListOf<Page>()
|
||||||
|
|
||||||
for (image in images) {
|
for (image in images) {
|
||||||
val iext = image.value.toString().replace("\"", "").split(",")[0]
|
val iext = image.value.toString().replace("\"", "").split(",")[0]
|
||||||
val iext_pr = when (iext) {
|
val iextPr = when (iext) {
|
||||||
"p" -> "png"
|
"p" -> "png"
|
||||||
"b" -> "bmp"
|
"b" -> "bmp"
|
||||||
"g" -> "gif"
|
"g" -> "gif"
|
||||||
else -> "jpg"
|
else -> "jpg"
|
||||||
}
|
}
|
||||||
pages.add(Page(image.key.toInt() - 1, "", "https://$random_server/$image_dir/$gallery_id/${image.key}.$iext_pr"))
|
pages.add(Page(image.key.toInt() - 1, "", "https://$randomServer/$imageDir/$galleryId/${image.key}.$iextPr"))
|
||||||
}
|
}
|
||||||
return pages
|
return pages
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ class Junmeitu : ParsedHttpSource() {
|
||||||
// Details
|
// Details
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
manga.title = document.selectFirst(".news-title,.title").text()
|
manga.title = document.selectFirst(".news-title,.title")!!.text()
|
||||||
manga.description = document.select(".news-info,.picture-details").text() + "\n" + document.select(".introduce").text()
|
manga.description = document.select(".news-info,.picture-details").text() + "\n" + document.select(".introduce").text()
|
||||||
manga.genre = document.select(".relation_tags > a").joinToString { it.text() }
|
manga.genre = document.select(".relation_tags > a").joinToString { it.text() }
|
||||||
manga.status = SManga.COMPLETED
|
manga.status = SManga.COMPLETED
|
||||||
|
@ -86,7 +86,7 @@ class Junmeitu : ParsedHttpSource() {
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
chapter.setUrlWithoutDomain(element.select(".position a:last-child").first().attr("abs:href"))
|
chapter.setUrlWithoutDomain(element.select(".position a:last-child").first()!!.attr("abs:href"))
|
||||||
chapter.chapter_number = -2f
|
chapter.chapter_number = -2f
|
||||||
chapter.name = "Gallery"
|
chapter.name = "Gallery"
|
||||||
return chapter
|
return chapter
|
||||||
|
@ -104,7 +104,7 @@ class Junmeitu : ParsedHttpSource() {
|
||||||
val index = lastIndexOf('.') // .html
|
val index = lastIndexOf('.') // .html
|
||||||
baseUrl + "/ajax_" + substring(baseUrl.length + 1, index) + '-'
|
baseUrl + "/ajax_" + substring(baseUrl.length + 1, index) + '-'
|
||||||
}
|
}
|
||||||
val postfix = document.selectFirst("body > script").data().run {
|
val postfix = document.selectFirst("body > script")!!.data().run {
|
||||||
val script = substringAfterLast("pc_cid = ")
|
val script = substringAfterLast("pc_cid = ")
|
||||||
val categoryId = script.substringBefore(';')
|
val categoryId = script.substringBefore(';')
|
||||||
val contentId = script.substringAfter("pc_id = ").substringBeforeLast(';')
|
val contentId = script.substringAfter("pc_id = ").substringBeforeLast(';')
|
||||||
|
|
|
@ -1164,16 +1164,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
.execute().use { response ->
|
.execute().use { response ->
|
||||||
|
|
||||||
genresListMeta = try {
|
genresListMeta = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(
|
|
||||||
LOG_TAG,
|
|
||||||
"[Filter] Error decoding JSON for genres filter: response body is null. Response code: ${response.code}",
|
|
||||||
)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(LOG_TAG, "[Filter] Error decoding JSON for genres filter -> ${response.body}", e)
|
Log.e(LOG_TAG, "[Filter] Error decoding JSON for genres filter -> ${response.body}", e)
|
||||||
emptyList()
|
emptyList()
|
||||||
|
@ -1183,16 +1174,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
client.newCall(GET("$apiUrl/Metadata/tags", headersBuilder().build()))
|
client.newCall(GET("$apiUrl/Metadata/tags", headersBuilder().build()))
|
||||||
.execute().use { response ->
|
.execute().use { response ->
|
||||||
tagsListMeta = try {
|
tagsListMeta = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(
|
|
||||||
LOG_TAG,
|
|
||||||
"[Filter] Error decoding JSON for tagsList filter: response body is null. Response code: ${response.code}",
|
|
||||||
)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(LOG_TAG, "[Filter] Error decoding JSON for tagsList filter", e)
|
Log.e(LOG_TAG, "[Filter] Error decoding JSON for tagsList filter", e)
|
||||||
emptyList()
|
emptyList()
|
||||||
|
@ -1202,16 +1184,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
client.newCall(GET("$apiUrl/Metadata/age-ratings", headersBuilder().build()))
|
client.newCall(GET("$apiUrl/Metadata/age-ratings", headersBuilder().build()))
|
||||||
.execute().use { response ->
|
.execute().use { response ->
|
||||||
ageRatingsListMeta = try {
|
ageRatingsListMeta = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(
|
|
||||||
LOG_TAG,
|
|
||||||
"[Filter] Error decoding JSON for age-ratings filter: response body is null. Response code: ${response.code}",
|
|
||||||
)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(
|
Log.e(
|
||||||
LOG_TAG,
|
LOG_TAG,
|
||||||
|
@ -1225,16 +1198,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
client.newCall(GET("$apiUrl/Collection", headersBuilder().build()))
|
client.newCall(GET("$apiUrl/Collection", headersBuilder().build()))
|
||||||
.execute().use { response ->
|
.execute().use { response ->
|
||||||
collectionsListMeta = try {
|
collectionsListMeta = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(
|
|
||||||
LOG_TAG,
|
|
||||||
"[Filter] Error decoding JSON for collectionsListMeta filter: response body is null. Response code: ${response.code}",
|
|
||||||
)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(
|
Log.e(
|
||||||
LOG_TAG,
|
LOG_TAG,
|
||||||
|
@ -1248,16 +1212,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
client.newCall(GET("$apiUrl/Metadata/languages", headersBuilder().build()))
|
client.newCall(GET("$apiUrl/Metadata/languages", headersBuilder().build()))
|
||||||
.execute().use { response ->
|
.execute().use { response ->
|
||||||
languagesListMeta = try {
|
languagesListMeta = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(
|
|
||||||
LOG_TAG,
|
|
||||||
"[Filter] Error decoding JSON for languagesListMeta filter: response body is null. Response code: ${response.code}",
|
|
||||||
)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(
|
Log.e(
|
||||||
LOG_TAG,
|
LOG_TAG,
|
||||||
|
@ -1271,16 +1226,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
client.newCall(GET("$apiUrl/Library", headersBuilder().build()))
|
client.newCall(GET("$apiUrl/Library", headersBuilder().build()))
|
||||||
.execute().use { response ->
|
.execute().use { response ->
|
||||||
libraryListMeta = try {
|
libraryListMeta = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(
|
|
||||||
LOG_TAG,
|
|
||||||
"[Filter] Error decoding JSON for libraries filter: response body is null. Response code: ${response.code}",
|
|
||||||
)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(
|
Log.e(
|
||||||
LOG_TAG,
|
LOG_TAG,
|
||||||
|
@ -1294,16 +1240,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
client.newCall(GET("$apiUrl/Metadata/people", headersBuilder().build()))
|
client.newCall(GET("$apiUrl/Metadata/people", headersBuilder().build()))
|
||||||
.execute().use { response ->
|
.execute().use { response ->
|
||||||
peopleListMeta = try {
|
peopleListMeta = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(
|
|
||||||
LOG_TAG,
|
|
||||||
"error while decoding JSON for peopleListMeta filter: response body is null. Response code: ${response.code}",
|
|
||||||
)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(
|
Log.e(
|
||||||
LOG_TAG,
|
LOG_TAG,
|
||||||
|
@ -1316,16 +1253,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
client.newCall(GET("$apiUrl/Metadata/publication-status", headersBuilder().build()))
|
client.newCall(GET("$apiUrl/Metadata/publication-status", headersBuilder().build()))
|
||||||
.execute().use { response ->
|
.execute().use { response ->
|
||||||
pubStatusListMeta = try {
|
pubStatusListMeta = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(
|
|
||||||
LOG_TAG,
|
|
||||||
"error while decoding JSON for publicationStatusListMeta filter: response body is null. Response code: ${response.code}",
|
|
||||||
)
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(
|
Log.e(
|
||||||
LOG_TAG,
|
LOG_TAG,
|
||||||
|
@ -1345,9 +1273,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||||
.subscribe(
|
.subscribe(
|
||||||
{},
|
{},
|
||||||
{ tr ->
|
{ tr ->
|
||||||
/**
|
// Avoid polluting logs with traces of exception
|
||||||
* Avoid polluting logs with traces of exception
|
|
||||||
* **/
|
|
||||||
if (tr is EmptyRequestBody || tr is LoginErrorException) {
|
if (tr is EmptyRequestBody || tr is LoginErrorException) {
|
||||||
Log.e(LOG_TAG, "error while doing initial calls\n${tr.cause}")
|
Log.e(LOG_TAG, "error while doing initial calls\n${tr.cause}")
|
||||||
return@subscribe
|
return@subscribe
|
||||||
|
|
|
@ -581,13 +581,7 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
|
||||||
try {
|
try {
|
||||||
client.newCall(GET("$baseUrl/api/v1/tags", headers)).execute().use { response ->
|
client.newCall(GET("$baseUrl/api/v1/tags", headers)).execute().use { response ->
|
||||||
tags = try {
|
tags = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(LOG_TAG, "error while decoding JSON for tags filter: response body is null. Response code: ${response.code}")
|
|
||||||
emptySet()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(LOG_TAG, "error while decoding JSON for tags filter", e)
|
Log.e(LOG_TAG, "error while decoding JSON for tags filter", e)
|
||||||
emptySet()
|
emptySet()
|
||||||
|
@ -600,13 +594,7 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
|
||||||
try {
|
try {
|
||||||
client.newCall(GET("$baseUrl/api/v1/publishers", headers)).execute().use { response ->
|
client.newCall(GET("$baseUrl/api/v1/publishers", headers)).execute().use { response ->
|
||||||
publishers = try {
|
publishers = try {
|
||||||
val responseBody = response.body
|
response.body.use { json.decodeFromString(it.string()) }
|
||||||
if (responseBody != null) {
|
|
||||||
responseBody.use { json.decodeFromString(it.string()) }
|
|
||||||
} else {
|
|
||||||
Log.e(LOG_TAG, "error while decoding JSON for publishers filter: response body is null. Response code: ${response.code}")
|
|
||||||
emptySet()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(LOG_TAG, "error while decoding JSON for publishers filter", e)
|
Log.e(LOG_TAG, "error while decoding JSON for publishers filter", e)
|
||||||
emptySet()
|
emptySet()
|
||||||
|
@ -619,14 +607,9 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
|
||||||
try {
|
try {
|
||||||
client.newCall(GET("$baseUrl/api/v1/authors", headers)).execute().use { response ->
|
client.newCall(GET("$baseUrl/api/v1/authors", headers)).execute().use { response ->
|
||||||
authors = try {
|
authors = try {
|
||||||
val responseBody = response.body
|
response.body
|
||||||
if (responseBody != null) {
|
.use { json.decodeFromString<List<AuthorDto>>(it.string()) }
|
||||||
val list: List<AuthorDto> = responseBody.use { json.decodeFromString(it.string()) }
|
.groupBy { it.role }
|
||||||
list.groupBy { it.role }
|
|
||||||
} else {
|
|
||||||
Log.e(LOG_TAG, "error while decoding JSON for authors filter: response body is null. Response code: ${response.code}")
|
|
||||||
emptyMap()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(LOG_TAG, "error while decoding JSON for authors filter", e)
|
Log.e(LOG_TAG, "error while decoding JSON for authors filter", e)
|
||||||
emptyMap()
|
emptyMap()
|
||||||
|
|
|
@ -50,7 +50,7 @@ class LittleGarden : ParsedHttpSource() {
|
||||||
override fun latestUpdatesSelector() = ".d-sm-block.col-sm-6.col-lg-6.col-xl-3.col-12"
|
override fun latestUpdatesSelector() = ".d-sm-block.col-sm-6.col-lg-6.col-xl-3.col-12"
|
||||||
override fun latestUpdatesNextPageSelector(): String? = null
|
override fun latestUpdatesNextPageSelector(): String? = null
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
|
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.selectFirst("h3").text().trim()
|
title = element.selectFirst("h3")!!.text().trim()
|
||||||
setUrlWithoutDomain(element.select("a").attr("href").substringBeforeLast("/"))
|
setUrlWithoutDomain(element.select("a").attr("href").substringBeforeLast("/"))
|
||||||
thumbnail_url = element.select(".img.image-item").attr("style").substringAfter("(").substringBefore(")")
|
thumbnail_url = element.select(".img.image-item").attr("style").substringAfter("(").substringBefore(")")
|
||||||
}
|
}
|
||||||
|
@ -172,9 +172,9 @@ class LittleGarden : ParsedHttpSource() {
|
||||||
// Pages
|
// Pages
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val pages = mutableListOf<Page>()
|
val pages = mutableListOf<Page>()
|
||||||
val chapNb = document.selectFirst("div.chapter-number").text().trim().toInt()
|
val chapNb = document.selectFirst("div.chapter-number")!!.text().trim().toInt()
|
||||||
val engChaps: IntArray = intArrayOf(970, 987, 992)
|
val engChaps: IntArray = intArrayOf(970, 987, 992)
|
||||||
if (document.selectFirst("div.manga-name").text().trim() == "One Piece" && (engChaps.contains(chapNb) || chapNb > 1004)) { // Permits to get French pages rather than English pages for some chapters
|
if (document.selectFirst("div.manga-name")!!.text().trim() == "One Piece" && (engChaps.contains(chapNb) || chapNb > 1004)) { // Permits to get French pages rather than English pages for some chapters
|
||||||
oricolPageRegex.findAll(document.select("script:containsData(pages)").toString()).asIterable().mapIndexed { i, it ->
|
oricolPageRegex.findAll(document.select("script:containsData(pages)").toString()).asIterable().mapIndexed { i, it ->
|
||||||
if (it.groups["colored"]?.value?.contains("\"") == true) { // Their JS dict has " " around the link only when available. Also uses colored pages rather than B&W as it's the main strength of this site
|
if (it.groups["colored"]?.value?.contains("\"") == true) { // Their JS dict has " " around the link only when available. Also uses colored pages rather than B&W as it's the main strength of this site
|
||||||
pages.add(Page(i, "", cdnUrl + it.groups["colored"]?.value?.replace("\"", "") + ".webp"))
|
pages.add(Page(i, "", cdnUrl + it.groups["colored"]?.value?.replace("\"", "") + ".webp"))
|
||||||
|
|
|
@ -106,21 +106,21 @@ class MangaPlusCreators(override val lang: String) : HttpSource() {
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val result = response.asJsoup()
|
val result = response.asJsoup()
|
||||||
val bookBox = result.selectFirst(".book-box")
|
val bookBox = result.selectFirst(".book-box")!!
|
||||||
|
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
title = bookBox.selectFirst("div.title").text()
|
title = bookBox.selectFirst("div.title")!!.text()
|
||||||
author = bookBox.selectFirst("div.mod-btn-profile div.name").text()
|
author = bookBox.selectFirst("div.mod-btn-profile div.name")!!.text()
|
||||||
description = bookBox.select("div.summary p")
|
description = bookBox.select("div.summary p")
|
||||||
.joinToString("\n\n") { it.text() }
|
.joinToString("\n\n") { it.text() }
|
||||||
status = when (bookBox.selectFirst("div.book-submit-type").text()) {
|
status = when (bookBox.selectFirst("div.book-submit-type")!!.text()) {
|
||||||
"Series" -> SManga.ONGOING
|
"Series" -> SManga.ONGOING
|
||||||
"One-shot" -> SManga.COMPLETED
|
"One-shot" -> SManga.COMPLETED
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
genre = bookBox.select("div.genre-area div.tag-genre")
|
genre = bookBox.select("div.genre-area div.tag-genre")
|
||||||
.joinToString { it.text() }
|
.joinToString { it.text() }
|
||||||
thumbnail_url = bookBox.selectFirst("div.cover img").attr("data-src")
|
thumbnail_url = bookBox.selectFirst("div.cover img")!!.attr("data-src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ open class MangaReader(
|
||||||
override fun searchMangaFromElement(element: Element) =
|
override fun searchMangaFromElement(element: Element) =
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
url = element.attr("href")
|
url = element.attr("href")
|
||||||
element.selectFirst(Evaluator.Tag("img")).let {
|
element.selectFirst(Evaluator.Tag("img"))!!.let {
|
||||||
title = it.attr("alt")
|
title = it.attr("alt")
|
||||||
thumbnail_url = it.attr("src")
|
thumbnail_url = it.attr("src")
|
||||||
}
|
}
|
||||||
|
@ -146,23 +146,23 @@ open class MangaReader(
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
url = document.location().removePrefix(baseUrl)
|
url = document.location().removePrefix(baseUrl)
|
||||||
val root = document.selectFirst(Evaluator.Id("ani_detail"))
|
val root = document.selectFirst(Evaluator.Id("ani_detail"))!!
|
||||||
val mangaTitle = root.selectFirst(Evaluator.Tag("h2")).ownText()
|
val mangaTitle = root.selectFirst(Evaluator.Tag("h2"))!!.ownText()
|
||||||
title = if (url.endsWith(VOLUME_URL_SUFFIX)) VOLUME_TITLE_PREFIX + mangaTitle else mangaTitle
|
title = if (url.endsWith(VOLUME_URL_SUFFIX)) VOLUME_TITLE_PREFIX + mangaTitle else mangaTitle
|
||||||
description = root.run {
|
description = root.run {
|
||||||
val description = selectFirst(Evaluator.Class("description")).ownText()
|
val description = selectFirst(Evaluator.Class("description"))!!.ownText()
|
||||||
when (val altTitle = selectFirst(Evaluator.Class("manga-name-or")).ownText()) {
|
when (val altTitle = selectFirst(Evaluator.Class("manga-name-or"))!!.ownText()) {
|
||||||
"", mangaTitle -> description
|
"", mangaTitle -> description
|
||||||
else -> "$description\n\nAlternative Title: $altTitle"
|
else -> "$description\n\nAlternative Title: $altTitle"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thumbnail_url = root.selectFirst(Evaluator.Tag("img")).attr("src")
|
thumbnail_url = root.selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||||
genre = root.selectFirst(Evaluator.Class("genres")).children().joinToString { it.ownText() }
|
genre = root.selectFirst(Evaluator.Class("genres"))!!.children().joinToString { it.ownText() }
|
||||||
for (item in root.selectFirst(Evaluator.Class("anisc-info")).children()) {
|
for (item in root.selectFirst(Evaluator.Class("anisc-info"))!!.children()) {
|
||||||
if (item.hasClass("item").not()) continue
|
if (item.hasClass("item").not()) continue
|
||||||
when (item.selectFirst(Evaluator.Class("item-head")).ownText()) {
|
when (item.selectFirst(Evaluator.Class("item-head"))!!.ownText()) {
|
||||||
"Authors:" -> item.parseAuthorsTo(this)
|
"Authors:" -> item.parseAuthorsTo(this)
|
||||||
"Status:" -> status = when (item.selectFirst(Evaluator.Class("name")).ownText()) {
|
"Status:" -> status = when (item.selectFirst(Evaluator.Class("name"))!!.ownText()) {
|
||||||
"Finished" -> SManga.COMPLETED
|
"Finished" -> SManga.COMPLETED
|
||||||
"Publishing" -> SManga.ONGOING
|
"Publishing" -> SManga.ONGOING
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
|
@ -198,7 +198,7 @@ open class MangaReader(
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
val number = element.attr("data-number")
|
val number = element.attr("data-number")
|
||||||
chapter_number = number.toFloatOrNull() ?: -1f
|
chapter_number = number.toFloatOrNull() ?: -1f
|
||||||
element.selectFirst(Evaluator.Tag("a")).let {
|
element.selectFirst(Evaluator.Tag("a"))!!.let {
|
||||||
url = it.attr("href")
|
url = it.attr("href")
|
||||||
name = run {
|
name = run {
|
||||||
val name = it.attr("title")
|
val name = it.attr("title")
|
||||||
|
@ -211,7 +211,7 @@ open class MangaReader(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val ajaxUrl = document.selectFirst(Evaluator.Id("wrapper")).run {
|
val ajaxUrl = document.selectFirst(Evaluator.Id("wrapper"))!!.run {
|
||||||
val readingBy = attr("data-reading-by")
|
val readingBy = attr("data-reading-by")
|
||||||
val readingId = attr("data-reading-id")
|
val readingId = attr("data-reading-id")
|
||||||
"$baseUrl/ajax/image/list/$readingBy/$readingId?quality=${preferences.quality}"
|
"$baseUrl/ajax/image/list/$readingBy/$readingId?quality=${preferences.quality}"
|
||||||
|
|
|
@ -60,7 +60,7 @@ open class MangaToon(
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.select("div.content-title").text().trim()
|
title = element.select("div.content-title").text().trim()
|
||||||
thumbnail_url = element.select("img").attr("abs:src").toNormalPosterUrl()
|
thumbnail_url = element.select("img").attr("abs:src").toNormalPosterUrl()
|
||||||
url = element.selectFirst("a").attr("href")
|
url = element.selectFirst("a")!!.attr("href")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "span.next"
|
override fun popularMangaNextPageSelector() = "span.next"
|
||||||
|
@ -88,7 +88,7 @@ open class MangaToon(
|
||||||
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.select("div.recommend-comics-title").text().trim()
|
title = element.select("div.recommend-comics-title").text().trim()
|
||||||
thumbnail_url = element.select("img").attr("abs:src").toNormalPosterUrl()
|
thumbnail_url = element.select("img").attr("abs:src").toNormalPosterUrl()
|
||||||
url = element.selectFirst("a").attr("href")
|
url = element.selectFirst("a")!!.attr("href")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
|
@ -29,13 +29,13 @@ class MeituaTop : HttpSource() {
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val mangas = document.selectFirst(Evaluator.Class("thumbnail-group")).children().map {
|
val mangas = document.selectFirst(Evaluator.Class("thumbnail-group"))!!.children().map {
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
url = it.selectFirst(Evaluator.Tag("a")).attr("href")
|
url = it.selectFirst(Evaluator.Tag("a"))!!.attr("href")
|
||||||
val image = it.selectFirst(Evaluator.Tag("img"))
|
val image = it.selectFirst(Evaluator.Tag("img"))!!
|
||||||
title = image.attr("alt")
|
title = image.attr("alt")
|
||||||
thumbnail_url = image.attr("src")
|
thumbnail_url = image.attr("src")
|
||||||
val info = it.selectFirst(Evaluator.Tag("p")).ownText().split(" - ")
|
val info = it.selectFirst(Evaluator.Tag("p"))!!.ownText().split(" - ")
|
||||||
genre = info[0]
|
genre = info[0]
|
||||||
description = info[1]
|
description = info[1]
|
||||||
status = SManga.COMPLETED
|
status = SManga.COMPLETED
|
||||||
|
@ -86,8 +86,8 @@ class MeituaTop : HttpSource() {
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val images = document.selectFirst(Evaluator.Class("ttnr")).select(Evaluator.Tag("img"))
|
val images = document.selectFirst(Evaluator.Class("ttnr"))!!.select(Evaluator.Tag("img"))
|
||||||
.map { it.attr("src")!! }.distinct()
|
.map { it.attr("src") }.distinct()
|
||||||
return images.mapIndexed { index, imageUrl -> Page(index, imageUrl = imageUrl) }
|
return images.mapIndexed { index, imageUrl -> Page(index, imageUrl = imageUrl) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = "li.pagination-next"
|
override fun latestUpdatesNextPageSelector() = "li.pagination-next"
|
||||||
override fun latestUpdatesSelector() = "article"
|
override fun latestUpdatesSelector() = "article"
|
||||||
override fun latestUpdatesFromElement(element: Element) = buildManga(element.select("a[rel]").first(), element.select("a.entry-image-link img").first())
|
override fun latestUpdatesFromElement(element: Element) = buildManga(element.select("a[rel]").first()!!, element.select("a.entry-image-link img").first())
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||||
cacheAssistant()
|
cacheAssistant()
|
||||||
return super.latestUpdatesParse(response)
|
return super.latestUpdatesParse(response)
|
||||||
|
@ -94,7 +94,7 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
|
||||||
val totalResults = Regex("""(\d+)""").find(document.select("div.res_info").text())?.groupValues?.get(1)?.toIntOrNull() ?: 0
|
val totalResults = Regex("""(\d+)""").find(document.select("div.res_info").text())?.groupValues?.get(1)?.toIntOrNull() ?: 0
|
||||||
return MangasPage(mangas, mangaParsedSoFar < totalResults)
|
return MangasPage(mangas, mangaParsedSoFar < totalResults)
|
||||||
}
|
}
|
||||||
override fun searchMangaFromElement(element: Element) = buildManga(element.select("a").first(), element.select("img")?.first())
|
override fun searchMangaFromElement(element: Element) = buildManga(element.select("a").first()!!, element.select("img").first())
|
||||||
|
|
||||||
// Build Manga From Element
|
// Build Manga From Element
|
||||||
private fun buildManga(titleElement: Element, thumbnailElement: Element?): SManga {
|
private fun buildManga(titleElement: Element, thumbnailElement: Element?): SManga {
|
||||||
|
@ -150,9 +150,9 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
|
||||||
// too troublesome to achieve 100% accuracy assigning scanlator group during chapterListParse
|
// too troublesome to achieve 100% accuracy assigning scanlator group during chapterListParse
|
||||||
val scanlatedBy = document.select(".entry-terms:has(a[href*=group])").firstOrNull()
|
val scanlatedBy = document.select(".entry-terms:has(a[href*=group])").firstOrNull()
|
||||||
?.select("a[href*=group]")?.joinToString(prefix = "Scanlated by: ") { it.text() }
|
?.select("a[href*=group]")?.joinToString(prefix = "Scanlated by: ") { it.text() }
|
||||||
val extendedDescription = document.select(".entry-content p:not(p:containsOwn(|)):not(.chapter-class + p)")?.joinToString("\n") { it.text() }
|
val extendedDescription = document.select(".entry-content p:not(p:containsOwn(|)):not(.chapter-class + p)").joinToString("\n") { it.text() }
|
||||||
description = listOfNotNull(basicDescription, scanlatedBy, extendedDescription).joinToString("\n")
|
description = listOfNotNull(basicDescription, scanlatedBy, extendedDescription).joinToString("\n")
|
||||||
status = when (document.select("a[href*=status]")?.first()?.text()) {
|
status = when (document.select("a[href*=status]").first()?.text()) {
|
||||||
"Ongoing" -> SManga.ONGOING
|
"Ongoing" -> SManga.ONGOING
|
||||||
"Completed" -> SManga.COMPLETED
|
"Completed" -> SManga.COMPLETED
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
|
@ -162,7 +162,7 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
|
||||||
thumbnail_url = getThumbnail(
|
thumbnail_url = getThumbnail(
|
||||||
getImage(
|
getImage(
|
||||||
client.newCall(GET("$baseUrl/search/?search=${document.location()}", headers))
|
client.newCall(GET("$baseUrl/search/?search=${document.location()}", headers))
|
||||||
.execute().asJsoup().select("div.wdm_results div.p_content img").first(),
|
.execute().asJsoup().select("div.wdm_results div.p_content img").first()!!,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -181,16 +181,16 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
|
||||||
|
|
||||||
val date = parseDate(document.select(".entry-time").text())
|
val date = parseDate(document.select(".entry-time").text())
|
||||||
val mangaUrl = document.baseUri()
|
val mangaUrl = document.baseUri()
|
||||||
val chfirstname = document.select(".chapter-class a[href*=$mangaUrl]")?.first()?.text()?.ifEmpty { "Ch. 1" }?.replaceFirstChar { it.titlecase() }
|
val chfirstname = document.select(".chapter-class a[href*=$mangaUrl]").first()?.text()?.ifEmpty { "Ch. 1" }?.replaceFirstChar { it.titlecase() }
|
||||||
?: "Ch. 1"
|
?: "Ch. 1"
|
||||||
// create first chapter since its on main manga page
|
// create first chapter since its on main manga page
|
||||||
chapters.add(createChapter("1", document.baseUri(), date, chfirstname))
|
chapters.add(createChapter("1", document.baseUri(), date, chfirstname))
|
||||||
// see if there are multiple chapters or not
|
// see if there are multiple chapters or not
|
||||||
document.select(chapterListSelector())?.let { it ->
|
document.select(chapterListSelector()).let { it ->
|
||||||
it.forEach {
|
it.forEach {
|
||||||
if (!it.text().contains("Next »", true)) {
|
if (!it.text().contains("Next »", true)) {
|
||||||
val pageNumber = it.text()
|
val pageNumber = it.text()
|
||||||
val chname = document.select(".chapter-class a[href$=/$pageNumber/]")?.text()?.ifEmpty { "Ch. $pageNumber" }?.replaceFirstChar { it.titlecase() }
|
val chname = document.select(".chapter-class a[href$=/$pageNumber/]").text().ifEmpty { "Ch. $pageNumber" }?.replaceFirstChar { it.titlecase() }
|
||||||
?: "Ch. $pageNumber"
|
?: "Ch. $pageNumber"
|
||||||
chapters.add(createChapter(it.text(), document.baseUri(), date, chname))
|
chapters.add(createChapter(it.text(), document.baseUri(), date, chname))
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ data class Title(
|
||||||
get() = "$title_slug|$title_id"
|
get() = "$title_slug|$title_id"
|
||||||
|
|
||||||
val description: String?
|
val description: String?
|
||||||
get() = Jsoup.parse(story)?.text()
|
get() = Jsoup.parse(story).text()
|
||||||
|
|
||||||
val thumbnail: String
|
val thumbnail: String
|
||||||
get() = CDN_URL + v_cover_img
|
get() = CDN_URL + v_cover_img
|
||||||
|
|
|
@ -51,7 +51,7 @@ object NHUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNumPages(document: Document): String {
|
fun getNumPages(document: Document): String {
|
||||||
return document.select("#tags > div:nth-child(8) > span > a .name").first().cleanTag()
|
return document.select("#tags > div:nth-child(8) > span > a .name").first()!!.cleanTag()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTime(document: Document): Long {
|
fun getTime(document: Document): Long {
|
||||||
|
|
|
@ -98,7 +98,7 @@ open class NHentai(
|
||||||
title = element.select("a > div").text().replace("\"", "").let {
|
title = element.select("a > div").text().replace("\"", "").let {
|
||||||
if (displayFullTitle) it.trim() else it.shortenTitle()
|
if (displayFullTitle) it.trim() else it.shortenTitle()
|
||||||
}
|
}
|
||||||
thumbnail_url = element.select(".cover img").first().let { img ->
|
thumbnail_url = element.select(".cover img").first()!!.let { img ->
|
||||||
if (img.hasAttr("data-src")) img.attr("abs:data-src") else img.attr("abs:src")
|
if (img.hasAttr("data-src")) img.attr("abs:data-src") else img.attr("abs:src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,11 +247,11 @@ open class NHentai(
|
||||||
override fun chapterListSelector() = throw UnsupportedOperationException("Not used")
|
override fun chapterListSelector() = throw UnsupportedOperationException("Not used")
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val script = document.select("script:containsData(media_server)").first().data()
|
val script = document.select("script:containsData(media_server)").first()!!.data()
|
||||||
val media_server = Regex("""media_server\s*:\s*(\d+)""").find(script)?.groupValues!!.get(1)
|
val mediaServer = Regex("""media_server\s*:\s*(\d+)""").find(script)?.groupValues!![1]
|
||||||
|
|
||||||
return document.select("div.thumbs a > img").mapIndexed { i, img ->
|
return document.select("div.thumbs a > img").mapIndexed { i, img ->
|
||||||
Page(i, "", img.attr("abs:data-src").replace("t.nh", "i.nh").replace("t\\d+.nh".toRegex(), "i$media_server.nh").replace("t.", "."))
|
Page(i, "", img.attr("abs:data-src").replace("t.nh", "i.nh").replace("t\\d+.nh".toRegex(), "i$mediaServer.nh").replace("t.", "."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ open class NineManga(
|
||||||
title = it.select("li > span:not([class])").text().removeSuffix(" Manga")
|
title = it.select("li > span:not([class])").text().removeSuffix(" Manga")
|
||||||
genre = it.select("li[itemprop=genre] a").joinToString { e -> e.text() }
|
genre = it.select("li[itemprop=genre] a").joinToString { e -> e.text() }
|
||||||
author = it.select("li a[itemprop=author]").text()
|
author = it.select("li a[itemprop=author]").text()
|
||||||
status = parseStatus(it.select("li a.red").first().text())
|
status = parseStatus(it.select("li a.red").first()!!.text())
|
||||||
description = it.select("p[itemprop=description]").text()
|
description = it.select("p[itemprop=description]").text()
|
||||||
thumbnail_url = it.select("img[itemprop=image]").attr("abs:src")
|
thumbnail_url = it.select("img[itemprop=image]").attr("abs:src")
|
||||||
|
|
||||||
|
@ -114,12 +114,12 @@ open class NineManga(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
||||||
document.select("select#page").first().select("option").forEach {
|
document.select("select#page").first()!!.select("option").forEach {
|
||||||
add(Page(size, baseUrl + it.attr("value")))
|
add(Page(size, baseUrl + it.attr("value")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document) = document.select("div.pic_box img.manga_pic").first().attr("src").orEmpty()
|
override fun imageUrlParse(document: Document) = document.select("div.pic_box img.manga_pic").first()!!.attr("src").orEmpty()
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
val url = "$baseUrl/search/".toHttpUrlOrNull()!!.newBuilder()
|
val url = "$baseUrl/search/".toHttpUrlOrNull()!!.newBuilder()
|
||||||
|
|
|
@ -68,8 +68,8 @@ abstract class NoiseManga(override val lang: String) : ParsedHttpSource() {
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request = GET(baseUrl + manga.url, headers)
|
override fun mangaDetailsRequest(manga: SManga): Request = GET(baseUrl + manga.url, headers)
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
val mainContent = document.select("div.main-content-page").first()
|
val mainContent = document.select("div.main-content-page").first()!!
|
||||||
val entryContent = mainContent.select("div.entry-content").first()
|
val entryContent = mainContent.select("div.entry-content").first()!!
|
||||||
val descriptionSelector = if (lang == "en") "h4 + h4, h4 + div h4" else "h1 + h4"
|
val descriptionSelector = if (lang == "en") "h4 + h4, h4 + div h4" else "h1 + h4"
|
||||||
val mangaSlug = document.location().replace(baseUrl, "")
|
val mangaSlug = document.location().replace(baseUrl, "")
|
||||||
|
|
||||||
|
|
|
@ -145,15 +145,15 @@ class PepperCarrot : HttpSource(), ConfigurableSource {
|
||||||
|
|
||||||
return translatedChapters.map { (number, it) ->
|
return translatedChapters.map { (number, it) ->
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
url = it.selectFirst(Evaluator.Tag("a")).attr("href").removePrefix(BASE_URL)
|
url = it.selectFirst(Evaluator.Tag("a"))!!.attr("href").removePrefix(BASE_URL)
|
||||||
name = it.selectFirst(Evaluator.Tag("img")).attr("title").run {
|
name = it.selectFirst(Evaluator.Tag("img"))!!.attr("title").run {
|
||||||
val index = lastIndexOf('(')
|
val index = lastIndexOf('(')
|
||||||
when {
|
when {
|
||||||
index >= 0 -> substring(0, index).trimEnd()
|
index >= 0 -> substring(0, index).trimEnd()
|
||||||
else -> substringBeforeLast('(').trimEnd()
|
else -> substringBeforeLast('(').trimEnd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
date_upload = it.selectFirst(Evaluator.Tag("figcaption")).ownText().let {
|
date_upload = it.selectFirst(Evaluator.Tag("figcaption"))!!.ownText().let {
|
||||||
val date = dateRegex.find(it)!!.value
|
val date = dateRegex.find(it)!!.value
|
||||||
dateFormat.parse(date)!!.time
|
dateFormat.parse(date)!!.time
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,8 +99,8 @@ private fun fetchTitles(client: OkHttpClient, headers: Headers): Map<String, Str
|
||||||
val url = "https://framagit.org/search?project_id=76196&search=core/mod-header.php:4"
|
val url = "https://framagit.org/search?project_id=76196&search=core/mod-header.php:4"
|
||||||
val document = client.newCall(GET(url, headers)).execute().asJsoup()
|
val document = client.newCall(GET(url, headers)).execute().asJsoup()
|
||||||
val result = hashMapOf<String, String>()
|
val result = hashMapOf<String, String>()
|
||||||
for (file in document.selectFirst(Evaluator.Class("search-results")).children()) {
|
for (file in document.selectFirst(Evaluator.Class("search-results"))!!.children()) {
|
||||||
val filename = file.selectFirst(Evaluator.Tag("strong")).ownText()
|
val filename = file.selectFirst(Evaluator.Tag("strong"))!!.ownText()
|
||||||
if (!filename.endsWith(".po") || !filename.startsWith("po/")) continue
|
if (!filename.endsWith(".po") || !filename.startsWith("po/")) continue
|
||||||
val lang = filename.substring(3, filename.length - 3)
|
val lang = filename.substring(3, filename.length - 3)
|
||||||
|
|
||||||
|
|
|
@ -45,14 +45,14 @@ class Photos18 : HttpSource(), ConfigurableSource {
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
parseCategories(document)
|
parseCategories(document)
|
||||||
val mangas = document.selectFirst(Evaluator.Id("videos")).children().map {
|
val mangas = document.selectFirst(Evaluator.Id("videos"))!!.children().map {
|
||||||
val cardBody = it.selectFirst(Evaluator.Class("card-body"))
|
val cardBody = it.selectFirst(Evaluator.Class("card-body"))!!
|
||||||
val link = cardBody.selectFirst(Evaluator.Tag("a"))
|
val link = cardBody.selectFirst(Evaluator.Tag("a"))!!
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
url = link.attr("href").stripLang()
|
url = link.attr("href").stripLang()
|
||||||
title = link.ownText()
|
title = link.ownText()
|
||||||
thumbnail_url = baseUrl + it.selectFirst(Evaluator.Tag("img")).attr("data-src")
|
thumbnail_url = baseUrl + it.selectFirst(Evaluator.Tag("img"))!!.attr("data-src")
|
||||||
genre = cardBody.selectFirst(Evaluator.Tag("label")).ownText()
|
genre = cardBody.selectFirst(Evaluator.Tag("label"))!!.ownText()
|
||||||
status = SManga.COMPLETED
|
status = SManga.COMPLETED
|
||||||
initialized = true
|
initialized = true
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ class Photos18 : HttpSource(), ConfigurableSource {
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val images = document.selectFirst(Evaluator.Id("content")).select(Evaluator.Tag("img"))
|
val images = document.selectFirst(Evaluator.Id("content"))!!.select(Evaluator.Tag("img"))
|
||||||
return images.mapIndexed { index, image ->
|
return images.mapIndexed { index, image ->
|
||||||
Page(index, imageUrl = image.attr("data-src"))
|
Page(index, imageUrl = image.attr("data-src"))
|
||||||
}
|
}
|
||||||
|
@ -145,12 +145,12 @@ class Photos18 : HttpSource(), ConfigurableSource {
|
||||||
|
|
||||||
private fun parseCategories(document: Document) {
|
private fun parseCategories(document: Document) {
|
||||||
if (categories.isNotEmpty()) return
|
if (categories.isNotEmpty()) return
|
||||||
val items = document.selectFirst(Evaluator.Id("w3")).children()
|
val items = document.selectFirst(Evaluator.Id("w3"))!!.children()
|
||||||
categories = buildList(items.size + 1) {
|
categories = buildList(items.size + 1) {
|
||||||
add(Pair("All", ""))
|
add(Pair("All", ""))
|
||||||
items.mapTo(this) {
|
items.mapTo(this) {
|
||||||
val value = it.text().substringBefore(" (")
|
val value = it.text().substringBefore(" (")
|
||||||
val queryValue = it.selectFirst(Evaluator.Tag("a")).attr("href").substringAfterLast('/')
|
val queryValue = it.selectFirst(Evaluator.Tag("a"))!!.attr("href").substringAfterLast('/')
|
||||||
Pair(value, queryValue)
|
Pair(value, queryValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ abstract class SandraAndWoo(
|
||||||
private fun pageImageSelector() = "#comic img"
|
private fun pageImageSelector() = "#comic img"
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val img = document.selectFirst(pageImageSelector())
|
val img = document.selectFirst(pageImageSelector())!!
|
||||||
val path = img.attr("src")
|
val path = img.attr("src")
|
||||||
|
|
||||||
return listOf(Page(0, "", "${baseUrl}$path"))
|
return listOf(Page(0, "", "${baseUrl}$path"))
|
||||||
|
|
|
@ -58,7 +58,7 @@ class Tappytoon(override val lang: String) : HttpSource() {
|
||||||
|
|
||||||
private val apiHeaders by lazy {
|
private val apiHeaders by lazy {
|
||||||
val res = client.newCall(GET(baseUrl, headers)).execute()
|
val res = client.newCall(GET(baseUrl, headers)).execute()
|
||||||
val data = res.asJsoup().getElementById("__NEXT_DATA__")
|
val data = res.asJsoup().getElementById("__NEXT_DATA__")!!
|
||||||
val obj = json.parseToJsonElement(data.data())
|
val obj = json.parseToJsonElement(data.data())
|
||||||
.jsonObject["props"]!!.jsonObject["initialState"]!!
|
.jsonObject["props"]!!.jsonObject["initialState"]!!
|
||||||
.jsonObject["axios"]!!.jsonObject["headers"]!!.jsonObject
|
.jsonObject["axios"]!!.jsonObject["headers"]!!.jsonObject
|
||||||
|
|
|
@ -50,7 +50,7 @@ abstract class ToomicsGlobal(
|
||||||
override fun popularMangaSelector(): String = "li > div.visual"
|
override fun popularMangaSelector(): String = "li > div.visual"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||||
title = element.select("h4[class$=title]").first().ownText()
|
title = element.select("h4[class$=title]").first()!!.ownText()
|
||||||
// sometimes href contains "/ab/on" at the end and redirects to a chapter instead of manga
|
// sometimes href contains "/ab/on" at the end and redirects to a chapter instead of manga
|
||||||
setUrlWithoutDomain(element.select("a").attr("href").removeSuffix("/ab/on"))
|
setUrlWithoutDomain(element.select("a").attr("href").removeSuffix("/ab/on"))
|
||||||
thumbnail_url = element.select("img").attr("src")
|
thumbnail_url = element.select("img").attr("src")
|
||||||
|
@ -125,9 +125,9 @@ abstract class ToomicsGlobal(
|
||||||
val num = element.select("div.cell-num").text()
|
val num = element.select("div.cell-num").text()
|
||||||
val numText = if (num.isNotEmpty()) "$num - " else ""
|
val numText = if (num.isNotEmpty()) "$num - " else ""
|
||||||
|
|
||||||
name = numText + element.select("div.cell-title strong")?.first()?.ownText()
|
name = numText + element.select("div.cell-title strong").first()?.ownText()
|
||||||
chapter_number = num.toFloatOrNull() ?: -1f
|
chapter_number = num.toFloatOrNull() ?: -1f
|
||||||
date_upload = parseChapterDate(element.select("div.cell-time time").text()!!)
|
date_upload = parseChapterDate(element.select("div.cell-time time").text())
|
||||||
scanlator = "Toomics"
|
scanlator = "Toomics"
|
||||||
url = element.select("a").attr("onclick")
|
url = element.select("a").attr("onclick")
|
||||||
.substringAfter("href='")
|
.substringAfter("href='")
|
||||||
|
|
|
@ -65,11 +65,11 @@ class Xinmeitulu : ParsedHttpSource() {
|
||||||
// Details
|
// Details
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
setUrlWithoutDomain(document.selectFirst("link[rel=canonical]").attr("abs:href"))
|
setUrlWithoutDomain(document.selectFirst("link[rel=canonical]")!!.attr("abs:href"))
|
||||||
title = document.select(".container > h1").text()
|
title = document.select(".container > h1").text()
|
||||||
description = document.select(".container > *:not(div)").text()
|
description = document.select(".container > *:not(div)").text()
|
||||||
status = SManga.COMPLETED
|
status = SManga.COMPLETED
|
||||||
thumbnail_url = document.selectFirst("figure img").attr("abs:data-original")
|
thumbnail_url = document.selectFirst("figure img")!!.attr("abs:data-original")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chapters
|
// Chapters
|
||||||
|
@ -77,7 +77,7 @@ class Xinmeitulu : ParsedHttpSource() {
|
||||||
override fun chapterListSelector() = "html"
|
override fun chapterListSelector() = "html"
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
setUrlWithoutDomain(element.selectFirst("link[rel=canonical]").attr("abs:href"))
|
setUrlWithoutDomain(element.selectFirst("link[rel=canonical]")!!.attr("abs:href"))
|
||||||
name = element.select(".container > h1").text()
|
name = element.select(".container > h1").text()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class XkcdFR : Xkcd("https://xkcd.lapin.org", "fr") {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(response: Response) =
|
override fun pageListParse(response: Response) =
|
||||||
response.asJsoup().selectFirst(imageSelector).let {
|
response.asJsoup().selectFirst(imageSelector)!!.let {
|
||||||
// no interactive comics here
|
// no interactive comics here
|
||||||
val img = it.child(2).child(0).child(0)
|
val img = it.child(2).child(0).child(0)
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue