Update jsoup (#15321)
This commit is contained in:
parent
7964dc4613
commit
e1f59a845e
gradle
multisrc
overrides
fmreader
epikmanga/src
ksgroupscans/src
mangatr/src
saytruyen/src
gattsu/universohentai/src
genkan/lynxscans/src
gigaviewer
comicgardo/src
kuragebunch/src
magazinepocket/src
tonarinoyoungjump/src
madara
mangabz/vomic/src
mangacatalog/readattackontitanshingekinokyojinmanga/src
mangaraw
mangasar/seemangas/src
mangathemesia
flamescans/src
kiryuu/src
komikcast/src
mangaraworg/src
mangaswat/src
mangkomik/src
manhwafreak/src
xcalibrscans/src
mmrcms
multichan/henchan/src
sinmh/wuqimanga/src
wpcomics/truyenchon/src
zeistmanga
zmanga/sektekomik/src
src/main/java/eu/kanade/tachiyomi/multisrc
a3manga
bakamanga
comicgamma
eromuse
fmreader
foolslide
gattsu
genkan
gigaviewer
grouple
kemono
libgroup
madara
madtheme
mangabox
mangabz
mangahub
mangamainac
mangaraw
mangathemesia
mangaworld
mccms
mdb
mmrcms
multichan
mymangacms
nepnep
otakusanctuary
sinmh
webtoons
wpcomics
zbulu
zeistmanga
zmanga
src/all
batoto/src/eu/kanade/tachiyomi/extension/all/batoto
buondua/src/eu/kanade/tachiyomi/extension/all/buondua
ehentai/src/eu/kanade/tachiyomi/extension/all/ehentai
everiaclub/src/eu/kanade/tachiyomi/extension/all/everiaclub
hennojin/src/eu/kanade/tachiyomi/extension/all/hennojin
imhentai/src/eu/kanade/tachiyomi/extension/all/imhentai
junmeitu/src/eu/kanade/tachiyomi/extension/all/junmeitu
kavita/src/eu/kanade/tachiyomi/extension/all/kavita
komga/src/eu/kanade/tachiyomi/extension/all/komga
littlegarden/src/eu/kanade/tachiyomi/extension/all/littlegarden
mangapluscreators/src/eu/kanade/tachiyomi/extension/all/mangapluscreators
mangareaderto/src/eu/kanade/tachiyomi/extension/all/mangareaderto
mangatoon/src/eu/kanade/tachiyomi/extension/all/mangatoon
meituatop/src/eu/kanade/tachiyomi/extension/all/meituatop
myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga
netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics
nhentai/src/eu/kanade/tachiyomi/extension/all/nhentai
ninemanga/src/eu/kanade/tachiyomi/extension/all/ninemanga
noisemanga/src/eu/kanade/tachiyomi/extension/all/noisemanga
peppercarrot/src/eu/kanade/tachiyomi/extension/all/peppercarrot
photos18/src/eu/kanade/tachiyomi/extension/all/photos18
sandraandwoo/src/eu/kanade/tachiyomi/extension/all/sandraandwoo
tappytoon/src/eu/kanade/tachiyomi/extension/all/tappytoon
toomics/src/eu/kanade/tachiyomi/extension/all/toomics
xinmeitulu/src/eu/kanade/tachiyomi/extension/all/xinmeitulu
xkcd/src/eu/kanade/tachiyomi/extension/all/xkcd/translations
@ -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…
x
Reference in New Issue
Block a user