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" }
|
||||
rxandroid = { module = "io.reactivex:rxandroid", version = "1.2.1" }
|
||||
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" }
|
||||
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)
|
||||
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) }
|
||||
.map {
|
||||
SManga.create().apply {
|
||||
@ -40,7 +40,7 @@ class EpikManga : FMReader("Epik Manga", "https://www.epikmanga.com", "tr") {
|
||||
return MangasPage(mangas, false)
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
return SChapter.create().apply {
|
||||
element.select(chapterUrlSelector).first().let {
|
||||
element.select(chapterUrlSelector).first()!!.let {
|
||||
setUrlWithoutDomain(it.attr("abs:href"))
|
||||
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 {
|
||||
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.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") {
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val info = document.select("div.row").first()
|
||||
val info = document.select("div.row").first()!!
|
||||
return SManga.create().apply {
|
||||
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() }
|
||||
|
@ -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 latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst("span.video-titulo").text().trim()
|
||||
thumbnail_url = element.selectFirst("img.wp-post-image").attr("src")
|
||||
title = element.selectFirst("span.video-titulo")!!.text().trim()
|
||||
thumbnail_url = element.selectFirst("img.wp-post-image")!!.attr("src")
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
}
|
||||
|
||||
@ -54,11 +54,11 @@ class UniversoHentai : Gattsu(
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
name = "Capítulo único"
|
||||
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")
|
||||
.orEmpty()
|
||||
.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"
|
||||
|
@ -8,7 +8,7 @@ class LynxScans : Genkan("LynxScans", "https://lynxscans.com", "en", "/web/comic
|
||||
override fun pageListParse(document: Document): List<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("];")
|
||||
.replace(Regex("""["\\]"""), "")
|
||||
.split(",/")
|
||||
|
@ -23,9 +23,9 @@ class ComicGardo : GigaViewer(
|
||||
override fun popularMangaSelector(): String = "ul.series-section-list li.series-section-item > a"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst("h5.series-title").text()
|
||||
thumbnail_url = element.selectFirst("div.thumb img").attr("data-src")
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
title = element.selectFirst("h5.series-title")!!.text()
|
||||
thumbnail_url = element.selectFirst("div.thumb img")!!.attr("data-src")
|
||||
setUrlWithoutDomain(element.attr("href")!!)
|
||||
}
|
||||
|
||||
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 popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst("a.series-data-container h4").text()
|
||||
thumbnail_url = element.selectFirst("a.series-thumb img").attr("data-src")
|
||||
title = element.selectFirst("a.series-data-container h4")!!.text()
|
||||
thumbnail_url = element.selectFirst("a.series-thumb img")!!.attr("data-src")
|
||||
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 popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst("h4.daily-series-title").text()
|
||||
thumbnail_url = element.selectFirst("div.daily-series-thumb img").attr("data-src")
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
title = element.selectFirst("h4.daily-series-title")!!.text()
|
||||
thumbnail_url = element.selectFirst("div.daily-series-thumb img")!!.attr("data-src")
|
||||
setUrlWithoutDomain(element.attr("href")!!)
|
||||
}
|
||||
|
||||
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 popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst("h4.title").text()
|
||||
thumbnail_url = element.selectFirst("div.subpage-image-wrapper img").attr("data-src")
|
||||
title = element.selectFirst("h4.title")!!.text()
|
||||
thumbnail_url = element.selectFirst("div.subpage-image-wrapper img")!!.attr("data-src")
|
||||
.replace("{width}", "528")
|
||||
.replace("{height}", "528")
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
|
@ -37,7 +37,7 @@ class Manga18fx : Madara(
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val document = response.asJsoup()
|
||||
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)
|
||||
return MangasPage(mangas, false)
|
||||
}
|
||||
@ -45,7 +45,7 @@ class Manga18fx : Madara(
|
||||
private fun mangaFromElement(element: Element) = SManga.create().apply {
|
||||
url = element.attr("href")
|
||||
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)
|
||||
@ -54,9 +54,9 @@ class Manga18fx : Madara(
|
||||
val document = response.asJsoup()
|
||||
loadGenres(document)
|
||||
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()
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
}
|
||||
@ -91,7 +91,7 @@ class Manga18fx : Madara(
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ class MangaLeveling : Madara("Manga Leveling", "https://mangaleveling.com", "en"
|
||||
chapter.url = urlElement.attr("abs:href").let {
|
||||
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
|
||||
// Added "title" alternative
|
||||
|
@ -16,7 +16,7 @@ class MMScans : Madara("MMScans", "https://mm-scans.org", "en") {
|
||||
with(element) {
|
||||
select(popularMangaUrlSelector).first()?.let {
|
||||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
manga.title = it.selectFirst("h3").ownText()
|
||||
manga.title = it.selectFirst("h3")!!.ownText()
|
||||
}
|
||||
|
||||
select("img").first()?.let {
|
||||
@ -35,7 +35,7 @@ class MMScans : Madara("MMScans", "https://mm-scans.org", "en") {
|
||||
chapter.url = urlElement.attr("abs:href").let {
|
||||
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())
|
||||
}
|
||||
|
@ -62,16 +62,16 @@ class Vomic : MangabzTheme("vomic", ""), ConfigurableSource {
|
||||
|
||||
val mangas = buildList {
|
||||
// ranking sidebar
|
||||
addAll(document.selectFirst(Evaluator.Class("rank-list")).children())
|
||||
addAll(document.selectFirst(Evaluator.Class("rank-list"))!!.children())
|
||||
// carousel list
|
||||
addAll(document.selectFirst(Evaluator.Class("carousel-right-list")).children())
|
||||
addAll(document.selectFirst(Evaluator.Class("carousel-right-list"))!!.children())
|
||||
// recommend list
|
||||
addAll(document.select(Evaluator.Class("index-manga-item")))
|
||||
addAll(document.select(Evaluator.Class("index-manga-item"))!!)
|
||||
}.map { element ->
|
||||
SManga.create().apply {
|
||||
title = element.selectFirst(paragraph).text()
|
||||
url = element.selectFirst(link).attr("href")
|
||||
thumbnail_url = element.selectFirst(image).attr("src")
|
||||
title = element.selectFirst(paragraph)!!.text()
|
||||
url = element.selectFirst(link)!!.attr("href")
|
||||
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 chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
val urlElemnt = element.selectFirst("a")
|
||||
val urlElement = element.selectFirst("a")!!
|
||||
name = listOfNotNull(
|
||||
urlElemnt.text(),
|
||||
element.selectFirst("div.text-xs").text().takeUnless { it.isBlank() },
|
||||
urlElement.text(),
|
||||
element.selectFirst("div.text-xs")!!.text().takeUnless { it.isBlank() },
|
||||
).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)
|
||||
|
||||
override fun Document.getSanitizedDetails(): Element =
|
||||
selectFirst(selectors.detailsSelector).apply {
|
||||
selectFirst(selectors.detailsSelector)!!.apply {
|
||||
val recommendClass = selectors.recommendClass
|
||||
children().find { it.hasClass(recommendClass) }?.remove()
|
||||
selectFirst(Evaluator.Class("list-scoll")).remove()
|
||||
selectFirst(Evaluator.Class("list-scoll"))!!.remove()
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = ".list-scoll a"
|
||||
|
@ -28,8 +28,8 @@ class SyoSetu : MangaRawTheme("SyoSetu", "https://syosetu.top") {
|
||||
GET("$baseUrl/page/$page?s=$query")
|
||||
|
||||
override fun Document.getSanitizedDetails(): Element =
|
||||
selectFirst(Evaluator.Tag("article")).selectFirst(Evaluator.Class("content-wrap-inner")).apply {
|
||||
selectFirst(Evaluator.Class("chaplist")).remove()
|
||||
selectFirst(Evaluator.Tag("article"))!!.selectFirst(Evaluator.Class("content-wrap-inner"))!!.apply {
|
||||
selectFirst(Evaluator.Class("chaplist"))!!.remove()
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = ".chaplist a"
|
||||
|
@ -26,9 +26,9 @@ class Seemangas : MangaSar(
|
||||
override fun popularMangaSelector() = "ul.sidebar-popular li.popular-treending"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst("h4.title").text()
|
||||
thumbnail_url = element.selectFirst("div.tumbl img").attr("data-lazy-src")
|
||||
setUrlWithoutDomain(element.selectFirst("a").attr("abs:href"))
|
||||
title = element.selectFirst("h4.title")!!.text()
|
||||
thumbnail_url = element.selectFirst("div.tumbl img")!!.attr("data-lazy-src")
|
||||
setUrlWithoutDomain(element.selectFirst("a")!!.attr("abs:href"))
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
@ -58,15 +58,15 @@ class Seemangas : MangaSar(
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
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 {
|
||||
title = infoElement.selectFirst("h1.kw-title").text()
|
||||
author = infoElement.selectFirst("div.mdq.author").text().trim()
|
||||
description = infoElement.selectFirst("div.sinopse-page").text()
|
||||
genre = infoElement.select("div.generos a.widget-btn").joinToString { it.text() }
|
||||
status = infoElement.selectFirst("span.mdq").text().toStatus()
|
||||
thumbnail_url = infoElement.selectFirst("div.thumb img").attr("abs:data-lazy-src")
|
||||
title = infoElement.selectFirst("h1.kw-title")!!.text()
|
||||
author = infoElement.selectFirst("div.mdq.author")!!.text().trim()
|
||||
description = infoElement.selectFirst("div.sinopse-page")!!.text()
|
||||
genre = infoElement.select("div.generos a.widget-btn")!!.joinToString { it.text() }
|
||||
status = infoElement.selectFirst("span.mdq")!!.text().toStatus()
|
||||
thumbnail_url = infoElement.selectFirst("div.thumb img")!!.attr("abs:data-lazy-src")
|
||||
}
|
||||
}
|
||||
override fun chapterListPaginatedRequest(mangaUrl: String, page: Int): Request {
|
||||
|
@ -66,7 +66,7 @@ open class FlameScans(
|
||||
return super.pageListParse(document)
|
||||
}
|
||||
|
||||
return document.select("#readerarea p:has(img), $composedSelector")
|
||||
return document.select("#readerarea p:has(img), $composedSelector").toList()
|
||||
.filter {
|
||||
it.select("img").all { imgEl ->
|
||||
imgEl.attr("abs:src").isNullOrEmpty().not()
|
||||
|
@ -20,7 +20,7 @@ class Kiryuu : MangaThemesia("Kiryuu", "https://kiryuu.id", "id", dateFormat = S
|
||||
|
||||
// manga details
|
||||
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
|
||||
|
@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import okhttp3.Headers
|
||||
@ -62,7 +61,7 @@ class KomikCast : MangaThemesia(
|
||||
override fun searchMangaSelector() = "div.list-update_item"
|
||||
|
||||
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)"
|
||||
@ -78,7 +77,7 @@ class KomikCast : MangaThemesia(
|
||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||
val urlElements = element.select("a")
|
||||
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())
|
||||
}
|
||||
|
||||
@ -130,7 +129,7 @@ class KomikCast : MangaThemesia(
|
||||
var imageServer = "cdn"
|
||||
if (!imageList.containsKey(imageServer)) imageServer = imageList.keys.first()
|
||||
val imageElement = imageList[imageServer]!!.jsonArray.joinToString("")
|
||||
doc = Jsoup.parse(json.decodeFromString(imageElement))
|
||||
doc = Jsoup.parse(imageElement)
|
||||
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> {
|
||||
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) }
|
||||
.map { num -> Page(num, "$chapterUrl/$num") }
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class MangaSwat : MangaThemesia(
|
||||
override val seriesStatusSelector = "span:contains(الحالة)"
|
||||
|
||||
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 tsReader = json.decodeFromString<TSReader>(jsonString)
|
||||
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> {
|
||||
// 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")
|
||||
if (scriptUrl.isNullOrEmpty()) {
|
||||
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 {
|
||||
val urlElements = element.select("a")
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ class xCaliBRScans : MangaThemesia("xCaliBR Scans", "https://xcalibrscans.com",
|
||||
.forEach { element ->
|
||||
when {
|
||||
element.tagName() == "p" -> {
|
||||
val imgUrl = element.selectFirst("img").imgAttr()
|
||||
val imgUrl = element.selectFirst("img")!!.imgAttr()
|
||||
imgUrls.add(imgUrl)
|
||||
}
|
||||
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 {
|
||||
val document = response.asJsoup()
|
||||
|
||||
title = document.selectFirst("h1.widget-title").text()
|
||||
title = document.selectFirst("h1.widget-title")!!.text()
|
||||
thumbnail_url = coverGuess(
|
||||
document.select("div.col-sm-5 img.img-thumbnail").firstOrNull()?.attr("abs:src"),
|
||||
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")) {
|
||||
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() }
|
||||
date_upload = el.select("div.col-md-4").firstOrNull()
|
||||
?.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? {
|
||||
val chapter = SChapter.create()
|
||||
|
||||
val titleWrapper = element.select("[class^=chapter-title-rtl]").first()
|
||||
val chapterElement = titleWrapper.getElementsByTag("a")
|
||||
val titleWrapper = element.select("[class^=chapter-title-rtl]").first()!!
|
||||
val chapterElement = titleWrapper.getElementsByTag("a")!!
|
||||
val url = chapterElement.attr("href")
|
||||
|
||||
chapter.url = getUrlWithoutBaseUrl(url)
|
||||
@ -28,7 +28,7 @@ class FallenAngels : MMRCMS("Fallen Angels", "https://manga.fascans.com", "en")
|
||||
val chapterText = chapterElement.text()
|
||||
val numberRegex = Regex("""[1-9]\d*(\.\d+)*""")
|
||||
val chapterNumber = numberRegex.find(chapterText)?.value.orEmpty()
|
||||
val chapterTitle = titleWrapper.getElementsByTag("em").text()
|
||||
val chapterTitle = titleWrapper.getElementsByTag("em")!!.text()
|
||||
chapter.name = "Chapter $chapterNumber : $chapterTitle"
|
||||
|
||||
// Parse date
|
||||
|
@ -105,7 +105,7 @@ class HenChan : MultiChan("HenChan", "http://y.hchan.live", "ru"), ConfigurableS
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -40,12 +40,12 @@ class WuqiManga : SinMH("57漫画", "http://www.wuqimh.net") {
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
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("漫画") }
|
||||
.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 pageListParse(document: Document): List<Page> {
|
||||
val script = document.selectFirst("body > script").html()
|
||||
val script = document.selectFirst("body > script")!!.html()
|
||||
val unpacked = Unpacker.unpack(script, ":[", "]")
|
||||
.ifEmpty { return emptyList() }
|
||||
.replace("\\", "")
|
||||
@ -85,7 +85,7 @@ class WuqiManga : SinMH("57漫画", "http://www.wuqimh.net") {
|
||||
document.select(Evaluator.Class("filter")).forEach { row ->
|
||||
val tags = row.select(linkSelector)
|
||||
if (tags.isEmpty()) return@forEach
|
||||
val name = row.selectFirst(labelSelector).text().removeSuffix(":")
|
||||
val name = row.selectFirst(labelSelector)!!.text().removeSuffix(":")
|
||||
if (!filterMap.containsKey(name)) {
|
||||
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 ", "")
|
||||
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 {
|
||||
return SManga.create().apply {
|
||||
title = element.attr("title").replace("Truyện tranh ", "")
|
||||
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)
|
||||
|
||||
if (script == null) {
|
||||
script = doc.selectFirst(altScriptSelector)
|
||||
script = doc.selectFirst(altScriptSelector)!!
|
||||
chapterRegex = altChapterFeedRegex
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ class MangaAiLand : ZeistManga("Manga Ai Land", "https://manga-ai-land.blogspot.
|
||||
override val imgSelectorAttr = "href"
|
||||
|
||||
override fun getChaptersUrl(doc: Document): String {
|
||||
val script = doc.selectFirst(scriptSelector).attr("src")
|
||||
val script = doc.selectFirst(scriptSelector)!!.attr("src")
|
||||
val feed = chapterFeedRegex
|
||||
.find(script)
|
||||
?.groupValues?.get(1)
|
||||
|
@ -49,7 +49,7 @@ class SekteKomik : ZManga("Sekte Komik", "https://sektekomik.com", "id") {
|
||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
||||
return SManga.create().apply {
|
||||
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")
|
||||
}
|
||||
}
|
||||
@ -79,7 +79,7 @@ class SekteKomik : ZManga("Sekte Komik", "https://sektekomik.com", "id") {
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
return SManga.create().apply {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
@ -142,9 +142,9 @@ open class A3Manga(
|
||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
||||
name = element.select("a .hidden-sm").text()
|
||||
date_upload = kotlin.runCatching {
|
||||
dateFormat.parse(element.select("td").last().text())?.time
|
||||
}.getOrNull() ?: 0L
|
||||
date_upload = runCatching {
|
||||
dateFormat.parse(element.select("td").last()!!.text())?.time
|
||||
}.getOrNull() ?: 0
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
|
@ -29,9 +29,9 @@ abstract class BakaManga(
|
||||
".li_truyen"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
setUrlWithoutDomain(element.selectFirst("a").absUrl("href"))
|
||||
title = element.selectFirst(".name").text()
|
||||
thumbnail_url = element.selectFirst("img").absUrl("src")
|
||||
setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
|
||||
title = element.selectFirst(".name")!!.text()
|
||||
thumbnail_url = element.selectFirst("img")!!.absUrl("src")
|
||||
}
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? =
|
||||
@ -47,7 +47,7 @@ abstract class BakaManga(
|
||||
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
||||
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
|
||||
val url = "$baseUrl/category/${genreFilter.toUriPart()}/page/$page"
|
||||
GET(url.toString(), headers)
|
||||
GET(url, headers)
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,8 +75,8 @@ abstract class BakaManga(
|
||||
|
||||
// Details
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
val info = document.selectFirst(".box_info")
|
||||
title = info.selectFirst("h1").text()
|
||||
val info = document.selectFirst(".box_info")!!
|
||||
title = info.selectFirst("h1")!!.text()
|
||||
artist = info.select(".info-item:contains(Artist:) > a").joinToString { it.text() }
|
||||
|
||||
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() }
|
||||
status = info.selectFirst(".info-item:contains(Status:)").text()
|
||||
status = info.selectFirst(".info-item:contains(Status:)")!!.text()
|
||||
.removePrefix("Status:")
|
||||
.trim()
|
||||
.toStatus()
|
||||
|
||||
thumbnail_url = info.selectFirst(".box_info img").absUrl("src")
|
||||
thumbnail_url = info.selectFirst(".box_info img")!!.absUrl("src")
|
||||
}
|
||||
|
||||
// Chapters
|
||||
@ -115,14 +115,14 @@ abstract class BakaManga(
|
||||
".list-chapters > .list-chapters > .box_list > .chapter-item"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.selectFirst("a").absUrl("href"))
|
||||
name = element.selectFirst(".chap_name").text()
|
||||
setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
|
||||
name = element.selectFirst(".chap_name")!!.text()
|
||||
chapter_number = name
|
||||
.substringAfter(' ')
|
||||
.substringBefore(' ')
|
||||
.toFloatOrNull() ?: -1f
|
||||
|
||||
date_upload = parseRelativeDate(element.selectFirst(".chap_update").text())
|
||||
date_upload = parseRelativeDate(element.selectFirst(".chap_update")!!.text())
|
||||
}
|
||||
|
||||
private fun parseRelativeDate(date: String): Long {
|
||||
|
@ -28,16 +28,16 @@ open class ComicGamma(
|
||||
override fun popularMangaNextPageSelector(): String? = null
|
||||
override fun popularMangaSelector() = ".tab_panel.active .manga_item"
|
||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||
url = element.selectFirst(Evaluator.Tag("a")).attr("href")
|
||||
title = element.selectFirst(Evaluator.Class("manga_title")).text()
|
||||
author = element.selectFirst(Evaluator.Class("manga_author")).text()
|
||||
url = element.selectFirst(Evaluator.Tag("a"))!!.attr("href")
|
||||
title = element.selectFirst(Evaluator.Class("manga_title"))!!.text()
|
||||
author = element.selectFirst(Evaluator.Class("manga_author"))!!.text()
|
||||
val genreList = element.select(Evaluator.Tag("li")).map { it.text() }
|
||||
genre = genreList.joinToString()
|
||||
status = when {
|
||||
genreList.contains("完結") && !genreList.contains("リピート配信") -> SManga.COMPLETED
|
||||
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.")
|
||||
@ -60,7 +60,7 @@ open class ComicGamma(
|
||||
}
|
||||
|
||||
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 desc = document.selectFirst(".detail__item > p:not(:empty)")?.run {
|
||||
select(Evaluator.Tag("br")).prepend("\\n")
|
||||
@ -81,7 +81,7 @@ open class ComicGamma(
|
||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||
url = element.attr("href").toOldChapterUrl()
|
||||
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()}"
|
||||
if (list.size >= 3) {
|
||||
date_upload = dateFormat.parseJST(list[2].text())?.time ?: 0L
|
||||
@ -98,7 +98,7 @@ open class ComicGamma(
|
||||
time += 12 * 3600 * 1000 // updates at 12 noon
|
||||
}
|
||||
|
||||
internal fun getJSTFormat(datePattern: String) =
|
||||
private fun getJSTFormat(datePattern: String) =
|
||||
SimpleDateFormat(datePattern, Locale.JAPANESE).apply {
|
||||
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 {
|
||||
fun internalParse(internalDocument: Document): List<SManga> {
|
||||
val authorDocument = if (stackItem.pageType == VARIOUS_AUTHORS) {
|
||||
internalDocument.select(albumSelector)?.let {
|
||||
internalDocument.select(albumSelector).let {
|
||||
elements ->
|
||||
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()
|
||||
val mangas = when (stackItem.pageType) {
|
||||
VARIOUS_AUTHORS -> {
|
||||
document.select(albumSelector)?.let {
|
||||
document.select(albumSelector).let {
|
||||
elements ->
|
||||
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) }
|
||||
|
||||
// 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*"""))) {
|
||||
it.split(" ").let { pageOf -> pageOf[1] != pageOf[3] } // current page not last page
|
||||
} else {
|
||||
@ -134,7 +134,7 @@ abstract class FMReader(
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
return SManga.create().apply {
|
||||
element.select("$headerSelector").let {
|
||||
element.select(headerSelector).let {
|
||||
setUrlWithoutDomain(it.attr("abs:href"))
|
||||
title = it.text()
|
||||
}
|
||||
@ -158,7 +158,7 @@ abstract class FMReader(
|
||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val infoElement = document.select("div.row").first()
|
||||
val infoElement = document.select("div.row").first()!!
|
||||
|
||||
return SManga.create().apply {
|
||||
author = infoElement.select("li a.btn-info").eachText().filter {
|
||||
@ -227,7 +227,7 @@ abstract class FMReader(
|
||||
open fun chapterFromElement(element: Element, mangaTitle: String = ""): SChapter {
|
||||
return SChapter.create().apply {
|
||||
if (chapterUrlSelector != "") {
|
||||
element.select(chapterUrlSelector).first().let {
|
||||
element.select(chapterUrlSelector).first()!!.let {
|
||||
setUrlWithoutDomain(it.attr("abs:href"))
|
||||
name = it.text().substringAfter("$mangaTitle ")
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ abstract class FoolSlide(
|
||||
}
|
||||
|
||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||
element.select("a[title]").first().let {
|
||||
element.select("a[title]").first()!!.let {
|
||||
setUrlWithoutDomain(it.attr("href"))
|
||||
title = it.text()
|
||||
}
|
||||
@ -75,7 +75,7 @@ abstract class FoolSlide(
|
||||
}
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
|
||||
element.select("a[title]").first().let {
|
||||
element.select("a[title]").first()!!.let {
|
||||
setUrlWithoutDomain(it.attr("href"))
|
||||
title = it.text()
|
||||
}
|
||||
@ -95,7 +95,7 @@ abstract class FoolSlide(
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
element.select("a[title]").first().let {
|
||||
element.select("a[title]").first()!!.let {
|
||||
manga.setUrlWithoutDomain(it.attr("href"))
|
||||
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
|
||||
protected fun getDetailsThumbnail(document: Document, urlSelector: String = chapterUrlSelector): String? {
|
||||
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 { response -> pageListParse(response).first().imageUrl }
|
||||
}
|
||||
@ -142,13 +142,11 @@ abstract class FoolSlide(
|
||||
protected open val chapterUrlSelector = "a[title]"
|
||||
|
||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||
val urlElement = element.select(chapterUrlSelector).first()
|
||||
val dateElement = element.select(chapterDateSelector).first()
|
||||
val urlElement = element.select(chapterUrlSelector).first()!!
|
||||
val dateElement = element.select(chapterDateSelector).first()!!
|
||||
setUrlWithoutDomain(urlElement.attr("href"))
|
||||
name = urlElement.text()
|
||||
date_upload = dateElement.text()?.let {
|
||||
parseChapterDate(it.substringAfter(", "))
|
||||
} ?: 0
|
||||
date_upload = parseChapterDate(dateElement.text().substringAfter(", ")) ?: 0
|
||||
}
|
||||
|
||||
protected open fun parseChapterDate(date: String): Long? {
|
||||
|
@ -105,11 +105,11 @@ abstract class Gattsu(
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
name = "Capítulo único"
|
||||
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")
|
||||
.orEmpty()
|
||||
.toDate()
|
||||
setUrlWithoutDomain(element.ownerDocument().location())
|
||||
setUrlWithoutDomain(element.ownerDocument()!!.location())
|
||||
}
|
||||
|
||||
protected open fun pageListSelector(): String =
|
||||
|
@ -63,11 +63,11 @@ open class Genkan(
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
element.select("a.list-title").first().let {
|
||||
element.select("a.list-title").first()!!.let {
|
||||
manga.setUrlWithoutDomain(it.attr("href"))
|
||||
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
|
||||
}
|
||||
|
||||
@ -98,9 +98,9 @@ open class Genkan(
|
||||
|
||||
protected var countryOfOriginSelector = ".card.mt-2 .list-item:contains(Country of Origin) .no-wrap"
|
||||
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")
|
||||
thumbnail_url = styleToUrl(document.select("div.media a").first())
|
||||
thumbnail_url = styleToUrl(document.select("div.media a").first()!!)
|
||||
genre = listOfNotNull(
|
||||
document.selectFirst(countryOfOriginSelector)?.let { countryOfOriginToSeriesType(it.text()) },
|
||||
).joinToString()
|
||||
@ -119,7 +119,7 @@ open class Genkan(
|
||||
} else {
|
||||
"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> {
|
||||
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("];")
|
||||
.replace(Regex("""["\\]"""), "")
|
||||
.split(",")
|
||||
|
@ -49,7 +49,7 @@ open class GenkanOriginal(
|
||||
// search the given document for matches
|
||||
private fun getMatchesFrom(document: Document): MutableList<SManga> {
|
||||
val searchMatches = mutableListOf<SManga>()
|
||||
document.select(searchMangaSelector())
|
||||
document.select(searchMangaSelector()).toList()
|
||||
.filter { it.text().contains(searchQuery, ignoreCase = true) }
|
||||
.map { searchMatches.add(searchMangaFromElement(it)) }
|
||||
|
||||
|
@ -67,8 +67,8 @@ abstract class GigaViewer(
|
||||
override fun popularMangaSelector(): String = "ul.series-list li a"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst("h2.series-list-title").text()
|
||||
thumbnail_url = element.selectFirst("div.series-list-thumb img")
|
||||
title = element.selectFirst("h2.series-list-title")!!.text()
|
||||
thumbnail_url = element.selectFirst("div.series-list-thumb img")!!
|
||||
.attr("data-src")
|
||||
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 searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst("div.title-box p.series-title").text()
|
||||
thumbnail_url = element.selectFirst("div.thmb-container a img").attr("src")
|
||||
setUrlWithoutDomain(element.selectFirst("div.thmb-container a").attr("href"))
|
||||
title = element.selectFirst("div.title-box p.series-title")!!.text()
|
||||
thumbnail_url = element.selectFirst("div.thmb-container a img")!!.attr("src")
|
||||
setUrlWithoutDomain(element.selectFirst("div.thmb-container a")!!.attr("href"))
|
||||
}
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = null
|
||||
@ -126,11 +126,11 @@ abstract class GigaViewer(
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
val infoElement = document.selectFirst(mangaDetailsInfoSelector())!!
|
||||
|
||||
title = infoElement.selectFirst("h1.series-header-title").text()
|
||||
author = infoElement.selectFirst("h2.series-header-author").text()
|
||||
title = infoElement.selectFirst("h1.series-header-title")!!.text()
|
||||
author = infoElement.selectFirst("h2.series-header-author")!!.text()
|
||||
artist = author
|
||||
description = infoElement.selectFirst("p.series-header-description").text()
|
||||
thumbnail_url = infoElement.selectFirst("div.series-header-image-wrapper img")
|
||||
description = infoElement.selectFirst("p.series-header-description")!!.text()
|
||||
thumbnail_url = infoElement.selectFirst("div.series-header-image-wrapper img")!!
|
||||
.attr("data-src")
|
||||
}
|
||||
|
||||
@ -183,10 +183,10 @@ abstract class GigaViewer(
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val info = element.selectFirst("a.series-episode-list-container") ?: element
|
||||
val mangaUrl = element.ownerDocument().location()
|
||||
val mangaUrl = element.ownerDocument()!!.location()
|
||||
|
||||
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) {
|
||||
name = YEN_BANKNOTE + name
|
||||
} else if (chapterListMode == CHAPTER_LIST_LOCKED && element.hasClass("private")) {
|
||||
@ -201,7 +201,7 @@ abstract class GigaViewer(
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val episode = document.selectFirst("script#episode-json")
|
||||
val episode = document.selectFirst("script#episode-json")!!
|
||||
.attr("data-value")
|
||||
.let {
|
||||
try {
|
||||
|
@ -74,7 +74,7 @@ abstract class GroupLe(
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
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.title = it.attr("title")
|
||||
}
|
||||
@ -103,11 +103,9 @@ abstract class GroupLe(
|
||||
}
|
||||
|
||||
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 category = if (rawCategory.isNotEmpty()) {
|
||||
rawCategory
|
||||
} else {
|
||||
val category = rawCategory.ifEmpty {
|
||||
"манга"
|
||||
}
|
||||
|
||||
@ -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))"
|
||||
|
||||
private fun chapterFromElement(element: Element, manga: SManga): SChapter {
|
||||
val urlElement = element.select("a.chapter-link").first()
|
||||
val chapterInf = element.select("td.item-title").first()
|
||||
val urlElement = element.select("a.chapter-link").first()!!
|
||||
val chapterInf = element.select("td.item-title").first()!!
|
||||
val urlText = urlElement.text()
|
||||
|
||||
val chapter = SChapter.create()
|
||||
|
@ -55,10 +55,10 @@ open class Kemono(
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
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 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 service = children[2].ownText()
|
||||
SManga.create().apply {
|
||||
@ -100,13 +100,13 @@ open class Kemono(
|
||||
val baseUrl = baseUrl
|
||||
return if (page == 1) {
|
||||
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 {
|
||||
SManga.create().apply {
|
||||
url = it.attr("href")
|
||||
title = it.selectFirst(Evaluator.Class("user-card__name")).ownText()
|
||||
author = it.selectFirst(Evaluator.Class("user-card__service")).ownText()
|
||||
thumbnail_url = baseUrl + it.selectFirst(Evaluator.Tag("img")).attr("src")
|
||||
title = it.selectFirst(Evaluator.Class("user-card__name"))!!.ownText()
|
||||
author = it.selectFirst(Evaluator.Class("user-card__service"))!!.ownText()
|
||||
thumbnail_url = baseUrl + it.selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||
description = PROMPT
|
||||
initialized = true
|
||||
}
|
||||
@ -227,7 +227,7 @@ open class Kemono(
|
||||
private const val POST_PAGES_MAX = 50
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ abstract class LibGroup(
|
||||
|
||||
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 category = when {
|
||||
rawCategory == "Комикс западный" -> "Комикс"
|
||||
@ -217,8 +217,8 @@ abstract class LibGroup(
|
||||
|
||||
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 ratingVotes = document.select(".media-rating__votes").last().text()
|
||||
val ratingValue = document.select(".media-rating__value").last()!!.text().toFloat() * 2
|
||||
val ratingVotes = document.select(".media-rating__votes").last()!!.text()
|
||||
val ratingStar = when {
|
||||
ratingValue > 9.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.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 StatusTitle = 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)
|
||||
|
||||
manga.status = if (document.html().contains("paper empty section")
|
||||
) {
|
||||
SManga.LICENSED
|
||||
} else {
|
||||
when {
|
||||
StatusTranslate.contains("завершен") && StatusTitle.contains("приостановлен") || StatusTranslate.contains("заморожен") || StatusTranslate.contains("заброшен") -> SManga.ON_HIATUS
|
||||
StatusTranslate.contains("завершен") && StatusTitle.contains("выпуск прекращён") -> SManga.CANCELLED
|
||||
StatusTranslate.contains("продолжается") -> SManga.ONGOING
|
||||
StatusTranslate.contains("завершен") -> SManga.COMPLETED
|
||||
else -> when (StatusTitle) {
|
||||
statusTranslate.contains("завершен") && statusTitle.contains("приостановлен") || statusTranslate.contains("заморожен") || statusTranslate.contains("заброшен") -> SManga.ON_HIATUS
|
||||
statusTranslate.contains("завершен") && statusTitle.contains("выпуск прекращён") -> SManga.CANCELLED
|
||||
statusTranslate.contains("продолжается") -> SManga.ONGOING
|
||||
statusTranslate.contains("завершен") -> SManga.COMPLETED
|
||||
else -> when (statusTitle) {
|
||||
"онгоинг" -> SManga.ONGOING
|
||||
"анонс" -> SManga.ONGOING
|
||||
"завершён" -> SManga.COMPLETED
|
||||
@ -445,7 +445,7 @@ abstract class LibGroup(
|
||||
|
||||
val chapInfo = document
|
||||
.select("script:containsData(window.__info)")
|
||||
.first()
|
||||
.first()!!
|
||||
.html()
|
||||
.split("window.__info = ")
|
||||
.last()
|
||||
@ -468,7 +468,7 @@ abstract class LibGroup(
|
||||
// Get pages
|
||||
val pagesArr = document
|
||||
.select("script:containsData(window.__pg)")
|
||||
.first()
|
||||
.first()!!
|
||||
.html()
|
||||
.trim()
|
||||
.removePrefix("window.__pg = ")
|
||||
|
@ -1156,8 +1156,8 @@ abstract class Madara(
|
||||
.orEmpty()
|
||||
.map { li ->
|
||||
Genre(
|
||||
li.selectFirst("label").text(),
|
||||
li.selectFirst("input[type=checkbox]").`val`(),
|
||||
li.selectFirst("label")!!.text(),
|
||||
li.selectFirst("input[type=checkbox]")!!.`val`(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1196,7 +1196,7 @@ abstract class Madara(
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val customUa = newValue as String
|
||||
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()
|
||||
} else {
|
||||
userAgent = null
|
||||
|
@ -176,7 +176,7 @@ abstract class MadTheme(
|
||||
}
|
||||
|
||||
// Try to show message/error from site
|
||||
response.body?.let { body ->
|
||||
response.body.let { body ->
|
||||
json.decodeFromString<JsonObject>(body.string())["message"]
|
||||
?.jsonPrimitive
|
||||
?.content
|
||||
@ -200,7 +200,7 @@ abstract class MadTheme(
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
// Not using setUrlWithoutDomain() to support external chapters
|
||||
url = element.selectFirst("a")
|
||||
url = element.selectFirst("a")!!
|
||||
.absUrl("href")
|
||||
.removePrefix(baseUrl)
|
||||
|
||||
@ -211,7 +211,7 @@ abstract class MadTheme(
|
||||
|
||||
// Pages
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val html = document.html()!!
|
||||
val html = document.html()
|
||||
|
||||
if (!html.contains("var mainServer = \"")) {
|
||||
// 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 {
|
||||
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
|
||||
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 {
|
||||
return SManga.create().apply {
|
||||
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()
|
||||
status = parseStatus(infoElement.select("li:contains(status), td:containsOwn(status) + td").text())
|
||||
genre = infoElement.select("div.manga-info-top li:contains(genres)").firstOrNull()
|
||||
?.select("a")?.joinToString { it.text() } // kakalot
|
||||
?: infoElement.select("td:containsOwn(genres) + td a").joinToString { it.text() } // nelo
|
||||
} ?: checkForRedirectMessage(document)
|
||||
description = document.select(descriptionSelector)?.firstOrNull()?.ownText()
|
||||
description = document.select(descriptionSelector).firstOrNull()?.ownText()
|
||||
?.replace("""^$title summary:\s""".toRegex(), "")
|
||||
?.replace("""<\s*br\s*/?>""".toRegex(), "\n")
|
||||
?.replace("<[^>]*>".toRegex(), "")
|
||||
@ -201,7 +201,7 @@ abstract class MangaBox(
|
||||
|
||||
private fun Element.selectDateFromElement(): Element {
|
||||
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 {
|
||||
|
@ -46,27 +46,27 @@ abstract class MangabzTheme(
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
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 {
|
||||
title = element.selectFirst(Evaluator.Tag("h2")).text()
|
||||
url = element.selectFirst(Evaluator.Tag("a")).attr("href")
|
||||
thumbnail_url = element.selectFirst(Evaluator.Tag("img")).attr("src")
|
||||
title = element.selectFirst(Evaluator.Tag("h2"))!!.text()
|
||||
url = element.selectFirst(Evaluator.Tag("a"))!!.attr("href")
|
||||
thumbnail_url = element.selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||
}
|
||||
}
|
||||
val hasNextPage = document.run {
|
||||
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)
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
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 {
|
||||
url = document.location().removePrefix(baseUrl)
|
||||
title = document.selectFirst(Evaluator.Class("detail-info-title")).ownText()
|
||||
thumbnail_url = document.selectFirst(Evaluator.Class("detail-info-cover")).attr("src")
|
||||
title = document.selectFirst(Evaluator.Class("detail-info-title"))!!.ownText()
|
||||
thumbnail_url = document.selectFirst(Evaluator.Class("detail-info-cover"))!!.attr("src")
|
||||
status = when (details[1].child(0).ownText()) {
|
||||
"连载中" -> SManga.ONGOING
|
||||
"已完结" -> SManga.COMPLETED
|
||||
@ -76,7 +76,7 @@ abstract class MangabzTheme(
|
||||
}
|
||||
author = details[0].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
|
||||
}
|
||||
}
|
||||
@ -103,7 +103,7 @@ abstract class MangabzTheme(
|
||||
}
|
||||
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 {
|
||||
list[0].date_upload = parseDate(listTitle)
|
||||
} catch (e: Throwable) {
|
||||
@ -113,7 +113,7 @@ abstract class MangabzTheme(
|
||||
}
|
||||
|
||||
protected open fun getChapterElements(document: Document): Elements =
|
||||
document.selectFirst(Evaluator.Id("chapterlistload")).children()
|
||||
document.selectFirst(Evaluator.Id("chapterlistload"))!!.children()
|
||||
|
||||
protected open val needPageCount = true
|
||||
|
||||
|
@ -171,14 +171,14 @@ abstract class MangaHub(
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.title = document.select(".breadcrumb .active span").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.genre = document.select(".row p a")?.joinToString { it.text() }
|
||||
manga.description = document.select(".tab-content p")?.first()?.text()
|
||||
manga.thumbnail_url = document.select("img.img-responsive")?.first()
|
||||
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.genre = document.select(".row p a").joinToString { it.text() }
|
||||
manga.description = document.select(".tab-content p").first()?.text()
|
||||
manga.thumbnail_url = document.select("img.img-responsive").first()
|
||||
?.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 {
|
||||
statusText.contains("ongoing", true) -> manga.status = SManga.ONGOING
|
||||
statusText.contains("completed", true) -> manga.status = SManga.COMPLETED
|
||||
|
@ -78,7 +78,7 @@ abstract class MangaMainac(
|
||||
override fun chapterListSelector() = "table.chap_tab tr"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val urlElement = element.select("a").first()
|
||||
val urlElement = element.select("a").first()!!
|
||||
val chapter = SChapter.create()
|
||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||
chapter.name = element.select("a").text()
|
||||
|
@ -22,8 +22,8 @@ abstract class MangaRawTheme(
|
||||
protected abstract fun String.sanitizeTitle(): String
|
||||
|
||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||
setUrlWithoutDomain(element.selectFirst(Evaluator.Tag("a")).attr("href"))
|
||||
title = element.selectFirst(Evaluator.Tag("h3")).text().sanitizeTitle()
|
||||
setUrlWithoutDomain(element.selectFirst(Evaluator.Tag("a"))!!.attr("href"))
|
||||
title = element.selectFirst(Evaluator.Tag("h3"))!!.text().sanitizeTitle()
|
||||
thumbnail_url = element.selectFirst(Evaluator.Tag("img"))?.absUrl("data-src")
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ abstract class MangaRawTheme(
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val imgSelector = Evaluator.Tag("img")
|
||||
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 {
|
||||
val urlElements = element.select("a")
|
||||
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()
|
||||
}
|
||||
|
||||
@ -452,8 +452,8 @@ abstract class MangaThemesia(
|
||||
private fun parseGenres(document: Document): List<Genre>? {
|
||||
return document.selectFirst("ul.genrez")?.select("li")?.map { li ->
|
||||
Genre(
|
||||
li.selectFirst("label").text(),
|
||||
li.selectFirst("input[type=checkbox]").attr("value"),
|
||||
li.selectFirst("label")!!.text(),
|
||||
li.selectFirst("input[type=checkbox]")!!.attr("value"),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -464,7 +464,7 @@ abstract class MangaThemesia(
|
||||
else -> attr("abs:src")
|
||||
}
|
||||
|
||||
protected open fun Elements.imgAttr(): String = this.first().imgAttr()
|
||||
protected open fun Elements.imgAttr(): String = this.first()!!.imgAttr()
|
||||
|
||||
// Unused
|
||||
override fun popularMangaSelector(): String = throw UnsupportedOperationException("Not used")
|
||||
|
@ -51,7 +51,7 @@ abstract class MangaWorld(
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
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.title = it.attr("title")
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ open class MCCMSNsfw(
|
||||
GET(baseUrl + chapter.url, headers)
|
||||
|
||||
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 ->
|
||||
Page(index, imageUrl = img.attr("src"))
|
||||
}
|
||||
|
@ -24,14 +24,14 @@ open class MCCMSWeb(
|
||||
fun parseListing(document: Document): MangasPage {
|
||||
val mangas = document.select(Evaluator.Class("common-comic-item")).map {
|
||||
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")
|
||||
title = titleElement.ownText()
|
||||
thumbnail_url = it.selectFirst(Evaluator.Tag("img")).attr("data-original")
|
||||
thumbnail_url = it.selectFirst(Evaluator.Tag("img"))!!.attr("data-original")
|
||||
}.cleanup()
|
||||
}
|
||||
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
|
||||
// Next page != Last page
|
||||
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)
|
||||
return client.newCall(GET(baseUrl + manga.url, pcHeaders)).asObservableSuccess().map { response ->
|
||||
SManga.create().apply {
|
||||
val document = response.asJsoup().selectFirst(Evaluator.Class("de-info__box"))
|
||||
title = document.selectFirst(Evaluator.Class("comic-title")).ownText()
|
||||
thumbnail_url = document.selectFirst(Evaluator.Tag("img")).attr("src")
|
||||
author = document.selectFirst(Evaluator.Class("name")).text()
|
||||
genre = document.selectFirst(Evaluator.Class("comic-status")).select(Evaluator.Tag("a")).joinToString { it.ownText() }
|
||||
description = document.selectFirst(Evaluator.Class("intro-total")).text()
|
||||
val document = response.asJsoup().selectFirst(Evaluator.Class("de-info__box"))!!
|
||||
title = document.selectFirst(Evaluator.Class("comic-title"))!!.ownText()
|
||||
thumbnail_url = document.selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||
author = document.selectFirst(Evaluator.Class("name"))!!.text()
|
||||
genre = document.selectFirst(Evaluator.Class("comic-status"))!!.select(Evaluator.Tag("a")).joinToString { it.ownText() }
|
||||
description = document.selectFirst(Evaluator.Class("intro-total"))!!.text()
|
||||
}.cleanup()
|
||||
}
|
||||
}
|
||||
@ -98,7 +98,7 @@ open class MCCMSWeb(
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
if (manga.url == "/index.php/search") return Observable.just(emptyList())
|
||||
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)
|
||||
SChapter.create().apply {
|
||||
url = link.attr("href")
|
||||
|
@ -35,10 +35,10 @@ abstract class MDB(
|
||||
override fun popularMangaRequest(page: Int) = GET(listUrl("page-$page"), headers)
|
||||
override fun popularMangaSelector() = "div.comic-main-section > div.comic-book-unit"
|
||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||
val link = element.selectFirst("h2 > a")
|
||||
val link = element.selectFirst("h2 > a")!!
|
||||
setUrlWithoutDomain(link.attr("href"))
|
||||
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 {
|
||||
@ -71,22 +71,22 @@ abstract class MDB(
|
||||
protected open fun transformDescription(description: String) = description
|
||||
|
||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||
title = document.selectFirst(Evaluator.Tag("h1")).text().let { transformTitle(it) }
|
||||
author = document.selectFirst(authorSelector).text()
|
||||
description = document.selectFirst("p.comic_story").text().let { transformDescription(it) }
|
||||
title = transformTitle(document.selectFirst(Evaluator.Tag("h1"))!!.text())
|
||||
author = document.selectFirst(authorSelector)!!.text()
|
||||
description = transformDescription(document.selectFirst("p.comic_story")!!.text())
|
||||
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.COMPLETED
|
||||
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> {
|
||||
val list = mutableListOf<String>()
|
||||
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())
|
||||
list.add(document.selectFirst("th:contains(面向读者) + td")!!.text().removeSuffix("漫画"))
|
||||
val tags = document.select("ul.tags > li > a")
|
||||
for (i in 1 until tags.size) { // skip status
|
||||
list.add(tags[i].text())
|
||||
@ -101,12 +101,12 @@ abstract class MDB(
|
||||
}
|
||||
|
||||
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 {
|
||||
val endIndex = indexOf(this[0], startIndex = 1) // find end quote
|
||||
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 ->
|
||||
Page(i, imageUrl = it)
|
||||
}
|
||||
@ -143,7 +143,7 @@ abstract class MDB(
|
||||
values.add(link.text())
|
||||
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))
|
||||
} else if (filterContainer.hasClass("form-row")) { // Dropdown filter
|
||||
for (select in filterContainer.select(Evaluator.Tag("select"))) {
|
||||
|
@ -134,7 +134,7 @@ abstract class MMRCMS(
|
||||
return client.newCall(GET("$baseUrl/changeMangaList?type=text", headers))
|
||||
.asObservableSuccess()
|
||||
.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) }
|
||||
.map {
|
||||
SManga.create().apply {
|
||||
@ -198,7 +198,7 @@ abstract class MMRCMS(
|
||||
private fun latestUpdatesSelector() = "div.mangalist div.manga-item"
|
||||
private fun latestUpdatesNextPageSelector() = "a[rel=next]"
|
||||
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) {
|
||||
null
|
||||
} else {
|
||||
@ -305,12 +305,12 @@ abstract class MMRCMS(
|
||||
|
||||
for (element in document.select(".row .dl-horizontal dt")) {
|
||||
when (element.text().trim().lowercase().removeSuffix(":")) {
|
||||
in detailAuthor -> author = element.nextElementSibling().text()
|
||||
in detailArtist -> artist = element.nextElementSibling().text()
|
||||
in detailGenre -> genre = element.nextElementSibling().select("a").joinToString {
|
||||
in detailAuthor -> author = element.nextElementSibling()!!.text()
|
||||
in detailArtist -> artist = element.nextElementSibling()!!.text()
|
||||
in detailGenre -> genre = element.nextElementSibling()!!.select("a").joinToString {
|
||||
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 detailStatusOngoing -> SManga.ONGOING
|
||||
else -> SManga.UNKNOWN
|
||||
@ -367,7 +367,7 @@ abstract class MMRCMS(
|
||||
val chapter = SChapter.create()
|
||||
|
||||
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
|
||||
val url = titleWrapper.getElementsByTag("a")
|
||||
.first { it.attr("href").contains(urlRegex) }
|
||||
|
@ -41,9 +41,9 @@ abstract class MultiChan(
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
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")
|
||||
element.select("h2 > a").first().let {
|
||||
element.select("h2 > a").first()!!.let {
|
||||
manga.setUrlWithoutDomain(it.attr("href"))
|
||||
}
|
||||
return manga
|
||||
@ -72,10 +72,10 @@ abstract class MultiChan(
|
||||
|
||||
val nextSearchPage = document.select(searchMangaNextPageSelector())
|
||||
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 onClick = selector.attr("onclick")
|
||||
onClick?.split("""\\d+""")
|
||||
onClick.split("""\\d+""")
|
||||
}
|
||||
nextSearchPage.attr("href", "$baseUrl/?do=search&subaction=search&story=$query&search_start=$pageNum")
|
||||
hasNextPage = true
|
||||
@ -91,7 +91,7 @@ abstract class MultiChan(
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
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 manga = SManga.create()
|
||||
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.status = parseStatus(infoElement.select(":contains(Загружено)").text())
|
||||
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
|
||||
}
|
||||
|
||||
@ -112,13 +112,13 @@ abstract class MultiChan(
|
||||
override fun chapterListSelector() = "table.table_cha tr:gt(1)"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val urlElement = element.select("a").first()
|
||||
val urlElement = element.select("a").first()!!
|
||||
|
||||
val chapter = SChapter.create()
|
||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||
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.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
|
||||
}
|
||||
|
||||
|
@ -86,9 +86,9 @@ abstract class MyMangaCMS(
|
||||
"div.pagination_wrap a.paging_item:last-of-type:not(.disabled)"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
setUrlWithoutDomain(element.select("a").first().attr("abs:href"))
|
||||
title = element.select("div.thumb_attr.series-title a[title]").first().text()
|
||||
thumbnail_url = element.select("div[data-bg]").first().attr("data-bg")
|
||||
setUrlWithoutDomain(element.select("a").first()!!.attr("abs:href"))
|
||||
title = element.select("div.thumb_attr.series-title a[title]").first()!!.text()
|
||||
thumbnail_url = element.select("div[data-bg]").first()!!.attr("data-bg")
|
||||
}
|
||||
//endregion
|
||||
|
||||
@ -179,10 +179,10 @@ abstract class MyMangaCMS(
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
setUrlWithoutDomain(
|
||||
document.select(".series-name-group a")
|
||||
.first()
|
||||
.first()!!
|
||||
.attr("abs:href"),
|
||||
)
|
||||
title = document.select(".series-name").first().text().trim()
|
||||
title = document.select(".series-name").first()!!.text().trim()
|
||||
|
||||
var alternativeNames: String? = null
|
||||
document.select(".info-item").forEach {
|
||||
@ -194,7 +194,7 @@ abstract class MyMangaCMS(
|
||||
"Tác giả:" -> author = value.joinToString(", ") { auth ->
|
||||
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
|
||||
"tạm ngưng" -> SManga.ON_HIATUS
|
||||
"đã hoàn thành" -> SManga.COMPLETED
|
||||
@ -226,7 +226,7 @@ abstract class MyMangaCMS(
|
||||
|
||||
thumbnail_url = document
|
||||
.select("div.content.img-in-ratio")
|
||||
.first()
|
||||
.first()!!
|
||||
.attr("style")
|
||||
.let { backgroundImageRegex.find(it)?.groups?.get(1)?.value }
|
||||
}
|
||||
@ -243,9 +243,9 @@ abstract class MyMangaCMS(
|
||||
private fun chapterFromElement(element: Element, scanlator: String?): SChapter =
|
||||
SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.attr("abs:href"))
|
||||
name = element.select("div.chapter-name").first().text()
|
||||
name = element.select("div.chapter-name").first()!!.text()
|
||||
date_upload = dateUpdatedParser(
|
||||
element.select("div.chapter-time").first().text(),
|
||||
element.select("div.chapter-time").first()!!.text(),
|
||||
)
|
||||
|
||||
val match = floatingNumberRegex.find(name)
|
||||
@ -262,11 +262,11 @@ abstract class MyMangaCMS(
|
||||
val document = response.asJsoup()
|
||||
val originalScanlator = document.select("div.fantrans-value a")
|
||||
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
|
||||
} else {
|
||||
originalScanlator.first().text().trim()
|
||||
originalScanlator.first()!!.text().trim()
|
||||
}
|
||||
|
||||
return document.select(chapterListSelector()).map { chapterFromElement(it, scanlator) }
|
||||
|
@ -77,7 +77,7 @@ abstract class NepNep(
|
||||
|
||||
// don't use ";" for substringBefore() !
|
||||
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()
|
||||
.replace(";", " ")
|
||||
return json.parseToJsonElement(str).jsonArray
|
||||
@ -85,7 +85,7 @@ abstract class NepNep(
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
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") }
|
||||
return parseDirectory(1)
|
||||
}
|
||||
@ -111,7 +111,7 @@ abstract class NepNep(
|
||||
private fun getThumbnailUrl(id: String): String {
|
||||
if (thumbnailUrl.isNullOrEmpty()) {
|
||||
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)
|
||||
@ -308,7 +308,7 @@ abstract class NepNep(
|
||||
}
|
||||
|
||||
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(";")
|
||||
return json.parseToJsonElement(vmChapters).jsonArray.map { json ->
|
||||
val indexChapter = json.getString("Chapter")!!
|
||||
@ -330,7 +330,7 @@ abstract class NepNep(
|
||||
val document = response.asJsoup()
|
||||
val script = document.selectFirst("script:containsData(MainFunction)")?.data()
|
||||
?: 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 pageTotal = curChapter.getString("Page")!!.toInt()
|
||||
|
@ -56,7 +56,7 @@ open class OtakuSanctuary(
|
||||
val page = emptyList<SManga>().toMutableList()
|
||||
|
||||
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
|
||||
if (url.toHttpUrl().host != baseUrl.toHttpUrl().host) {
|
||||
continue
|
||||
@ -80,7 +80,7 @@ open class OtakuSanctuary(
|
||||
setUrlWithoutDomain(url)
|
||||
title = element.select("div.mdl-card__supporting-text a[target=_blank]").text()
|
||||
.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
|
||||
@ -118,7 +118,7 @@ open class OtakuSanctuary(
|
||||
title = document.select("h1.title.text-lg-left.text-overflow-2-line")
|
||||
.text()
|
||||
.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() }
|
||||
description = document.select("div.summary p").joinToString("\n") {
|
||||
it.run {
|
||||
@ -129,7 +129,7 @@ open class OtakuSanctuary(
|
||||
genre = document.select("div.genres a").joinToString { it.text() }
|
||||
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) {
|
||||
"Ongoing" -> SManga.ONGOING
|
||||
"Done" -> SManga.COMPLETED
|
||||
@ -155,7 +155,7 @@ open class OtakuSanctuary(
|
||||
else -> 0L
|
||||
}
|
||||
} 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 comicItemTitleSelector = "p > a, h3 > a"
|
||||
protected open fun mangaFromElement(element: Element) = SManga.create().apply {
|
||||
val titleElement = element.selectFirst(comicItemTitleSelector)
|
||||
val titleElement = element.selectFirst(comicItemTitleSelector)!!
|
||||
title = titleElement.text()
|
||||
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") }
|
||||
}
|
||||
|
||||
@ -102,24 +102,24 @@ abstract class SinMH(
|
||||
// Details
|
||||
|
||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||
title = document.selectFirst(".book-title > h1").text()
|
||||
val detailsList = document.selectFirst(Evaluator.Class("detail-list"))
|
||||
title = document.selectFirst(".book-title > h1")!!.text()
|
||||
val detailsList = document.selectFirst(Evaluator.Class("detail-list"))!!
|
||||
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() // some sources have double prefix
|
||||
genre = mangaDetailsParseDefaultGenre(document, detailsList)
|
||||
status = when (detailsList.selectFirst("strong:contains(状态) + *").text()) {
|
||||
status = when (detailsList.selectFirst("strong:contains(状态) + *")!!.text()) {
|
||||
"连载中" -> SManga.ONGOING
|
||||
"已完结" -> SManga.COMPLETED
|
||||
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 {
|
||||
val category = detailsList.selectFirst("strong:contains(类型) + a")
|
||||
val breadcrumbs = document.selectFirst("div.breadcrumb-bar").select("a[href^=/list/]")
|
||||
val category = detailsList.selectFirst("strong:contains(类型) + a")!!
|
||||
val breadcrumbs = document.selectFirst("div.breadcrumb-bar")!!.select("a[href^=/list/]")
|
||||
return buildString {
|
||||
append(category.text())
|
||||
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 {
|
||||
val detailsDiv = document.selectFirst("div.comic_deCon")
|
||||
title = detailsDiv.selectFirst(Evaluator.Tag("h1")).text()
|
||||
val detailsDiv = document.selectFirst("div.comic_deCon")!!
|
||||
title = detailsDiv.selectFirst(Evaluator.Tag("h1"))!!.text()
|
||||
val details = detailsDiv.select("> ul > li")
|
||||
val linkSelector = Evaluator.Tag("a")
|
||||
author = details[0].selectFirst(linkSelector).text()
|
||||
status = when (details[1].selectFirst(linkSelector).text()) {
|
||||
author = details[0].selectFirst(linkSelector)!!.text()
|
||||
status = when (details[1].selectFirst(linkSelector)!!.text()) {
|
||||
"连载中" -> SManga.ONGOING
|
||||
"已完结" -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
genre = mutableListOf<Element>().apply {
|
||||
add(details[2].selectFirst(linkSelector)) // 类别
|
||||
add(details[2].selectFirst(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(", ")
|
||||
description = detailsDiv.selectFirst("> p.comic_deCon_d").text()
|
||||
thumbnail_url = document.selectFirst("div.comic_i_img > img").attr("src")
|
||||
description = detailsDiv.selectFirst("> p.comic_deCon_d")!!.text()
|
||||
thumbnail_url = document.selectFirst("div.comic_i_img > img")!!.attr("src")
|
||||
}
|
||||
|
||||
// Chapters
|
||||
@ -167,7 +167,7 @@ abstract class SinMH(
|
||||
section.select(itemSelector).map { chapterFromElement(it) }.sortedDescending()
|
||||
}
|
||||
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
|
||||
}
|
||||
return list
|
||||
@ -194,7 +194,7 @@ abstract class SinMH(
|
||||
|
||||
// baseUrl/js/common.js/getChapterImage()
|
||||
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 = ", ";")
|
||||
if (images.length <= 2) return emptyList() // [] or ""
|
||||
val path = script.substringBetween("chapterPath = \"", "\";")
|
||||
@ -237,8 +237,8 @@ abstract class SinMH(
|
||||
if (categories.isNotEmpty()) return
|
||||
val labelSelector = Evaluator.Tag("label")
|
||||
val linkSelector = Evaluator.Tag("a")
|
||||
categories = document.selectFirst(Evaluator.Class("filter-nav")).children().map { element ->
|
||||
val name = element.selectFirst(labelSelector).text()
|
||||
categories = document.selectFirst(Evaluator.Class("filter-nav"))!!.children().map { element ->
|
||||
val name = element.selectFirst(labelSelector)!!.text()
|
||||
val tags = element.select(linkSelector)
|
||||
val values = tags.map { it.text() }.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? {
|
||||
val picElement = document.select("#content > div.cont_box > div.detail_body")
|
||||
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 {
|
||||
@ -204,7 +204,7 @@ open class Webtoons(
|
||||
val infoElement = document.select("#_asideDetail")
|
||||
|
||||
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.artist = detailElement.select(".author:nth-of-type(2)").first()?.ownText() ?: manga.author
|
||||
manga.genre = detailElement.select(".genre").joinToString(", ") { it.text() }
|
||||
@ -220,7 +220,7 @@ open class Webtoons(
|
||||
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
|
||||
|
||||
@ -260,7 +260,7 @@ open class Webtoons(
|
||||
if (element.select(".ico_bgm").isNotEmpty()) {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ abstract class WPComics(
|
||||
title = it.text()
|
||||
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()
|
||||
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()
|
||||
genre = info.select("li.kind p.col-xs-8 a").joinToString { it.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())
|
||||
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
|
||||
|
||||
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 {
|
||||
title = infoElement.select("h1").first().text()
|
||||
title = infoElement.select("h1").first()!!.text()
|
||||
author = infoElement.select("div.author a").text()
|
||||
status = parseStatus(infoElement.select("div.update span[style]").text())
|
||||
genre = infoElement.select("div.genre a").joinToString { it.text() }
|
||||
@ -141,7 +141,7 @@ abstract class Zbulu(
|
||||
return SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
||||
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 fun getChaptersUrl(doc: Document): String {
|
||||
val script = doc.selectFirst(scriptSelector)
|
||||
val script = doc.selectFirst(scriptSelector)!!
|
||||
val feed = chapterFeedRegex
|
||||
.find(script.html())
|
||||
?.groupValues?.get(1)
|
||||
@ -109,17 +109,17 @@ abstract class ZeistManga(
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val profileManga = document.selectFirst(".grid.gtc-235fr")
|
||||
val profileManga = document.selectFirst(".grid.gtc-235fr")!!
|
||||
return SManga.create().apply {
|
||||
title = profileManga.selectFirst("h1.mt-0.mb-6.fs-20").text()
|
||||
thumbnail_url = profileManga.selectFirst("img").attr("src")
|
||||
title = profileManga.selectFirst("h1.mt-0.mb-6.fs-20")!!.text()
|
||||
thumbnail_url = profileManga.selectFirst("img")!!.attr("src")
|
||||
description = profileManga.select("#synopsis").text()
|
||||
status = SManga.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
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 ->
|
||||
Page(i, "", img.attr(imgSelectorAttr))
|
||||
}
|
||||
@ -153,8 +153,8 @@ abstract class ZeistManga(
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
return SManga.create().apply {
|
||||
setUrlWithoutDomain(element.select(".block").attr("href"))
|
||||
title = element.selectFirst(".clamp.toe.oh.block").text().trim()
|
||||
thumbnail_url = element.selectFirst("img").attr("src")
|
||||
title = element.selectFirst(".clamp.toe.oh.block")!!.text().trim()
|
||||
thumbnail_url = element.selectFirst("img")!!.attr("src")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ data class ZeistMangaEntryDto(
|
||||
|
||||
private fun getThumbnail(html: ZeistMangaEntryContentDto): String {
|
||||
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 {
|
||||
return SManga.create().apply {
|
||||
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")
|
||||
}
|
||||
}
|
||||
@ -162,7 +162,7 @@ abstract class ZManga(
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
return SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
name = element.select("span").first().ownText()
|
||||
name = element.select("span").first()!!.ownText()
|
||||
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())
|
||||
.select("channel > item").map { item ->
|
||||
SChapter.create().apply {
|
||||
url = item.selectFirst("guid").text()
|
||||
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
|
||||
url = item.selectFirst("guid")!!.text()
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ class BuonDua() : ParsedHttpSource() {
|
||||
manga.title = document.select(".article-header").text()
|
||||
manga.description = document.select(".article-info > strong").text().trim()
|
||||
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("#"))
|
||||
}
|
||||
manga.genre = genres.joinToString(", ")
|
||||
@ -74,7 +74,7 @@ class BuonDua() : ParsedHttpSource() {
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
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.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
|
||||
@ -86,7 +86,7 @@ class BuonDua() : ParsedHttpSource() {
|
||||
// Pages
|
||||
|
||||
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>()
|
||||
|
||||
numpages.forEachIndexed { index, page ->
|
||||
@ -94,7 +94,7 @@ class BuonDua() : ParsedHttpSource() {
|
||||
0 -> document
|
||||
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")
|
||||
pages.add(Page(pages.size, "", itUrl))
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ abstract class EHentai(
|
||||
}
|
||||
}
|
||||
// Get image
|
||||
it.parent().select(".glthumb img")?.first().apply {
|
||||
it.parent()?.select(".glthumb img")?.first().apply {
|
||||
thumbnail_url = this?.attr("data-src")?.nullIfBlank()
|
||||
?: this?.attr("src")
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class EveriaClub() : ParsedHttpSource() {
|
||||
// Latest
|
||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
||||
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.setUrlWithoutDomain(element.select(".entry-title > a").attr("abs:href"))
|
||||
return manga
|
||||
@ -46,7 +46,7 @@ class EveriaClub() : ParsedHttpSource() {
|
||||
// Popular
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
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.setUrlWithoutDomain(element.select("h3 > a").attr("abs:href"))
|
||||
return manga
|
||||
|
@ -46,10 +46,10 @@ class Hennojin(override val lang: String, suffix: String) : ParsedHttpSource() {
|
||||
override fun popularMangaFromElement(element: Element) =
|
||||
SManga.create().apply {
|
||||
element.selectFirst(".title_link > a").let {
|
||||
title = it.text()
|
||||
title = it!!.text()
|
||||
setUrlWithoutDomain(it.attr("href"))
|
||||
}
|
||||
thumbnail_url = element.selectFirst("img").attr("src")
|
||||
thumbnail_url = element.selectFirst("img")!!.attr("src")
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,9 +140,9 @@ class IMHentai(override val lang: String, private val imhLang: String) : ParsedH
|
||||
return this.joinToString {
|
||||
listOf(
|
||||
it.ownText(),
|
||||
it.select(".split_tag")?.text()
|
||||
?.trim()
|
||||
?.removePrefix("| "),
|
||||
it.select(".split_tag").text()
|
||||
.trim()
|
||||
.removePrefix("| "),
|
||||
)
|
||||
.filter { s -> !s.isNullOrBlank() }
|
||||
.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 {
|
||||
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 {
|
||||
it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
|
||||
}
|
||||
|
||||
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")
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val image_dir = document.select("#image_dir").`val`()
|
||||
val gallery_id = document.select("#gallery_id").`val`()
|
||||
val u_id = document.select("#u_id").`val`().toInt()
|
||||
val imageDir = document.select("#image_dir").`val`()
|
||||
val galleryId = document.select("#gallery_id").`val`()
|
||||
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 274826..403818 -> "m2.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(
|
||||
document.selectFirst("script:containsData(var g_th)").data()
|
||||
document.selectFirst("script:containsData(var g_th)")!!.data()
|
||||
.substringAfter("$.parseJSON('").substringBefore("');").trim(),
|
||||
).jsonObject
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
for (image in images) {
|
||||
val iext = image.value.toString().replace("\"", "").split(",")[0]
|
||||
val iext_pr = when (iext) {
|
||||
val iextPr = when (iext) {
|
||||
"p" -> "png"
|
||||
"b" -> "bmp"
|
||||
"g" -> "gif"
|
||||
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
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ class Junmeitu : ParsedHttpSource() {
|
||||
// Details
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
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.genre = document.select(".relation_tags > a").joinToString { it.text() }
|
||||
manga.status = SManga.COMPLETED
|
||||
@ -86,7 +86,7 @@ class Junmeitu : ParsedHttpSource() {
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
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.name = "Gallery"
|
||||
return chapter
|
||||
@ -104,7 +104,7 @@ class Junmeitu : ParsedHttpSource() {
|
||||
val index = lastIndexOf('.') // .html
|
||||
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 categoryId = script.substringBefore(';')
|
||||
val contentId = script.substringAfter("pc_id = ").substringBeforeLast(';')
|
||||
|
@ -1164,16 +1164,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
.execute().use { response ->
|
||||
|
||||
genresListMeta = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(LOG_TAG, "[Filter] Error decoding JSON for genres filter -> ${response.body}", e)
|
||||
emptyList()
|
||||
@ -1183,16 +1174,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
client.newCall(GET("$apiUrl/Metadata/tags", headersBuilder().build()))
|
||||
.execute().use { response ->
|
||||
tagsListMeta = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(LOG_TAG, "[Filter] Error decoding JSON for tagsList filter", e)
|
||||
emptyList()
|
||||
@ -1202,16 +1184,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
client.newCall(GET("$apiUrl/Metadata/age-ratings", headersBuilder().build()))
|
||||
.execute().use { response ->
|
||||
ageRatingsListMeta = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(
|
||||
LOG_TAG,
|
||||
@ -1225,16 +1198,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
client.newCall(GET("$apiUrl/Collection", headersBuilder().build()))
|
||||
.execute().use { response ->
|
||||
collectionsListMeta = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(
|
||||
LOG_TAG,
|
||||
@ -1248,16 +1212,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
client.newCall(GET("$apiUrl/Metadata/languages", headersBuilder().build()))
|
||||
.execute().use { response ->
|
||||
languagesListMeta = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(
|
||||
LOG_TAG,
|
||||
@ -1271,16 +1226,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
client.newCall(GET("$apiUrl/Library", headersBuilder().build()))
|
||||
.execute().use { response ->
|
||||
libraryListMeta = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(
|
||||
LOG_TAG,
|
||||
@ -1294,16 +1240,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
client.newCall(GET("$apiUrl/Metadata/people", headersBuilder().build()))
|
||||
.execute().use { response ->
|
||||
peopleListMeta = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(
|
||||
LOG_TAG,
|
||||
@ -1316,16 +1253,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
client.newCall(GET("$apiUrl/Metadata/publication-status", headersBuilder().build()))
|
||||
.execute().use { response ->
|
||||
pubStatusListMeta = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(
|
||||
LOG_TAG,
|
||||
@ -1345,9 +1273,7 @@ class Kavita(private val suffix: String = "") : ConfigurableSource, UnmeteredSou
|
||||
.subscribe(
|
||||
{},
|
||||
{ tr ->
|
||||
/**
|
||||
* Avoid polluting logs with traces of exception
|
||||
* **/
|
||||
// Avoid polluting logs with traces of exception
|
||||
if (tr is EmptyRequestBody || tr is LoginErrorException) {
|
||||
Log.e(LOG_TAG, "error while doing initial calls\n${tr.cause}")
|
||||
return@subscribe
|
||||
|
@ -581,13 +581,7 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
|
||||
try {
|
||||
client.newCall(GET("$baseUrl/api/v1/tags", headers)).execute().use { response ->
|
||||
tags = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(LOG_TAG, "error while decoding JSON for tags filter", e)
|
||||
emptySet()
|
||||
@ -600,13 +594,7 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
|
||||
try {
|
||||
client.newCall(GET("$baseUrl/api/v1/publishers", headers)).execute().use { response ->
|
||||
publishers = try {
|
||||
val responseBody = response.body
|
||||
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()
|
||||
}
|
||||
response.body.use { json.decodeFromString(it.string()) }
|
||||
} catch (e: Exception) {
|
||||
Log.e(LOG_TAG, "error while decoding JSON for publishers filter", e)
|
||||
emptySet()
|
||||
@ -619,14 +607,9 @@ open class Komga(private val suffix: String = "") : ConfigurableSource, Unmetere
|
||||
try {
|
||||
client.newCall(GET("$baseUrl/api/v1/authors", headers)).execute().use { response ->
|
||||
authors = try {
|
||||
val responseBody = response.body
|
||||
if (responseBody != null) {
|
||||
val list: List<AuthorDto> = responseBody.use { json.decodeFromString(it.string()) }
|
||||
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()
|
||||
}
|
||||
response.body
|
||||
.use { json.decodeFromString<List<AuthorDto>>(it.string()) }
|
||||
.groupBy { it.role }
|
||||
} catch (e: Exception) {
|
||||
Log.e(LOG_TAG, "error while decoding JSON for authors filter", e)
|
||||
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 latestUpdatesNextPageSelector(): String? = null
|
||||
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("/"))
|
||||
thumbnail_url = element.select(".img.image-item").attr("style").substringAfter("(").substringBefore(")")
|
||||
}
|
||||
@ -172,9 +172,9 @@ class LittleGarden : ParsedHttpSource() {
|
||||
// Pages
|
||||
override fun pageListParse(document: Document): List<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)
|
||||
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 ->
|
||||
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"))
|
||||
|
@ -106,21 +106,21 @@ class MangaPlusCreators(override val lang: String) : HttpSource() {
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
val result = response.asJsoup()
|
||||
val bookBox = result.selectFirst(".book-box")
|
||||
val bookBox = result.selectFirst(".book-box")!!
|
||||
|
||||
return SManga.create().apply {
|
||||
title = bookBox.selectFirst("div.title").text()
|
||||
author = bookBox.selectFirst("div.mod-btn-profile div.name").text()
|
||||
title = bookBox.selectFirst("div.title")!!.text()
|
||||
author = bookBox.selectFirst("div.mod-btn-profile div.name")!!.text()
|
||||
description = bookBox.select("div.summary p")
|
||||
.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
|
||||
"One-shot" -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
genre = bookBox.select("div.genre-area div.tag-genre")
|
||||
.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) =
|
||||
SManga.create().apply {
|
||||
url = element.attr("href")
|
||||
element.selectFirst(Evaluator.Tag("img")).let {
|
||||
element.selectFirst(Evaluator.Tag("img"))!!.let {
|
||||
title = it.attr("alt")
|
||||
thumbnail_url = it.attr("src")
|
||||
}
|
||||
@ -146,23 +146,23 @@ open class MangaReader(
|
||||
|
||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||
url = document.location().removePrefix(baseUrl)
|
||||
val root = document.selectFirst(Evaluator.Id("ani_detail"))
|
||||
val mangaTitle = root.selectFirst(Evaluator.Tag("h2")).ownText()
|
||||
val root = document.selectFirst(Evaluator.Id("ani_detail"))!!
|
||||
val mangaTitle = root.selectFirst(Evaluator.Tag("h2"))!!.ownText()
|
||||
title = if (url.endsWith(VOLUME_URL_SUFFIX)) VOLUME_TITLE_PREFIX + mangaTitle else mangaTitle
|
||||
description = root.run {
|
||||
val description = selectFirst(Evaluator.Class("description")).ownText()
|
||||
when (val altTitle = selectFirst(Evaluator.Class("manga-name-or")).ownText()) {
|
||||
val description = selectFirst(Evaluator.Class("description"))!!.ownText()
|
||||
when (val altTitle = selectFirst(Evaluator.Class("manga-name-or"))!!.ownText()) {
|
||||
"", mangaTitle -> description
|
||||
else -> "$description\n\nAlternative Title: $altTitle"
|
||||
}
|
||||
}
|
||||
thumbnail_url = root.selectFirst(Evaluator.Tag("img")).attr("src")
|
||||
genre = root.selectFirst(Evaluator.Class("genres")).children().joinToString { it.ownText() }
|
||||
for (item in root.selectFirst(Evaluator.Class("anisc-info")).children()) {
|
||||
thumbnail_url = root.selectFirst(Evaluator.Tag("img"))!!.attr("src")
|
||||
genre = root.selectFirst(Evaluator.Class("genres"))!!.children().joinToString { it.ownText() }
|
||||
for (item in root.selectFirst(Evaluator.Class("anisc-info"))!!.children()) {
|
||||
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)
|
||||
"Status:" -> status = when (item.selectFirst(Evaluator.Class("name")).ownText()) {
|
||||
"Status:" -> status = when (item.selectFirst(Evaluator.Class("name"))!!.ownText()) {
|
||||
"Finished" -> SManga.COMPLETED
|
||||
"Publishing" -> SManga.ONGOING
|
||||
else -> SManga.UNKNOWN
|
||||
@ -198,7 +198,7 @@ open class MangaReader(
|
||||
SChapter.create().apply {
|
||||
val number = element.attr("data-number")
|
||||
chapter_number = number.toFloatOrNull() ?: -1f
|
||||
element.selectFirst(Evaluator.Tag("a")).let {
|
||||
element.selectFirst(Evaluator.Tag("a"))!!.let {
|
||||
url = it.attr("href")
|
||||
name = run {
|
||||
val name = it.attr("title")
|
||||
@ -211,7 +211,7 @@ open class MangaReader(
|
||||
}
|
||||
|
||||
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 readingId = attr("data-reading-id")
|
||||
"$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 {
|
||||
title = element.select("div.content-title").text().trim()
|
||||
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"
|
||||
@ -88,7 +88,7 @@ open class MangaToon(
|
||||
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.select("div.recommend-comics-title").text().trim()
|
||||
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()
|
||||
|
@ -29,13 +29,13 @@ class MeituaTop : HttpSource() {
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
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 {
|
||||
url = it.selectFirst(Evaluator.Tag("a")).attr("href")
|
||||
val image = it.selectFirst(Evaluator.Tag("img"))
|
||||
url = it.selectFirst(Evaluator.Tag("a"))!!.attr("href")
|
||||
val image = it.selectFirst(Evaluator.Tag("img"))!!
|
||||
title = image.attr("alt")
|
||||
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]
|
||||
description = info[1]
|
||||
status = SManga.COMPLETED
|
||||
@ -86,8 +86,8 @@ class MeituaTop : HttpSource() {
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val document = response.asJsoup()
|
||||
val images = document.selectFirst(Evaluator.Class("ttnr")).select(Evaluator.Tag("img"))
|
||||
.map { it.attr("src")!! }.distinct()
|
||||
val images = document.selectFirst(Evaluator.Class("ttnr"))!!.select(Evaluator.Tag("img"))
|
||||
.map { it.attr("src") }.distinct()
|
||||
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 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 {
|
||||
cacheAssistant()
|
||||
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
|
||||
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
|
||||
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
|
||||
val scanlatedBy = document.select(".entry-terms:has(a[href*=group])").firstOrNull()
|
||||
?.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")
|
||||
status = when (document.select("a[href*=status]")?.first()?.text()) {
|
||||
status = when (document.select("a[href*=status]").first()?.text()) {
|
||||
"Ongoing" -> SManga.ONGOING
|
||||
"Completed" -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
@ -162,7 +162,7 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
|
||||
thumbnail_url = getThumbnail(
|
||||
getImage(
|
||||
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 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"
|
||||
// create first chapter since its on main manga page
|
||||
chapters.add(createChapter("1", document.baseUri(), date, chfirstname))
|
||||
// see if there are multiple chapters or not
|
||||
document.select(chapterListSelector())?.let { it ->
|
||||
document.select(chapterListSelector()).let { it ->
|
||||
it.forEach {
|
||||
if (!it.text().contains("Next »", true)) {
|
||||
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"
|
||||
chapters.add(createChapter(it.text(), document.baseUri(), date, chname))
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ data class Title(
|
||||
get() = "$title_slug|$title_id"
|
||||
|
||||
val description: String?
|
||||
get() = Jsoup.parse(story)?.text()
|
||||
get() = Jsoup.parse(story).text()
|
||||
|
||||
val thumbnail: String
|
||||
get() = CDN_URL + v_cover_img
|
||||
|
@ -51,7 +51,7 @@ object NHUtils {
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -98,7 +98,7 @@ open class NHentai(
|
||||
title = element.select("a > div").text().replace("\"", "").let {
|
||||
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")
|
||||
}
|
||||
}
|
||||
@ -247,11 +247,11 @@ open class NHentai(
|
||||
override fun chapterListSelector() = throw UnsupportedOperationException("Not used")
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
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 script = document.select("script:containsData(media_server)").first()!!.data()
|
||||
val mediaServer = Regex("""media_server\s*:\s*(\d+)""").find(script)?.groupValues!![1]
|
||||
|
||||
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")
|
||||
genre = it.select("li[itemprop=genre] a").joinToString { e -> e.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()
|
||||
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 {
|
||||
document.select("select#page").first().select("option").forEach {
|
||||
document.select("select#page").first()!!.select("option").forEach {
|
||||
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 {
|
||||
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 mangaDetailsParse(document: Document): SManga {
|
||||
val mainContent = document.select("div.main-content-page").first()
|
||||
val entryContent = mainContent.select("div.entry-content").first()
|
||||
val mainContent = document.select("div.main-content-page").first()!!
|
||||
val entryContent = mainContent.select("div.entry-content").first()!!
|
||||
val descriptionSelector = if (lang == "en") "h4 + h4, h4 + div h4" else "h1 + h4"
|
||||
val mangaSlug = document.location().replace(baseUrl, "")
|
||||
|
||||
|
@ -145,15 +145,15 @@ class PepperCarrot : HttpSource(), ConfigurableSource {
|
||||
|
||||
return translatedChapters.map { (number, it) ->
|
||||
SChapter.create().apply {
|
||||
url = it.selectFirst(Evaluator.Tag("a")).attr("href").removePrefix(BASE_URL)
|
||||
name = it.selectFirst(Evaluator.Tag("img")).attr("title").run {
|
||||
url = it.selectFirst(Evaluator.Tag("a"))!!.attr("href").removePrefix(BASE_URL)
|
||||
name = it.selectFirst(Evaluator.Tag("img"))!!.attr("title").run {
|
||||
val index = lastIndexOf('(')
|
||||
when {
|
||||
index >= 0 -> substring(0, index).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
|
||||
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 document = client.newCall(GET(url, headers)).execute().asJsoup()
|
||||
val result = hashMapOf<String, String>()
|
||||
for (file in document.selectFirst(Evaluator.Class("search-results")).children()) {
|
||||
val filename = file.selectFirst(Evaluator.Tag("strong")).ownText()
|
||||
for (file in document.selectFirst(Evaluator.Class("search-results"))!!.children()) {
|
||||
val filename = file.selectFirst(Evaluator.Tag("strong"))!!.ownText()
|
||||
if (!filename.endsWith(".po") || !filename.startsWith("po/")) continue
|
||||
val lang = filename.substring(3, filename.length - 3)
|
||||
|
||||
|
@ -45,14 +45,14 @@ class Photos18 : HttpSource(), ConfigurableSource {
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val document = response.asJsoup()
|
||||
parseCategories(document)
|
||||
val mangas = document.selectFirst(Evaluator.Id("videos")).children().map {
|
||||
val cardBody = it.selectFirst(Evaluator.Class("card-body"))
|
||||
val link = cardBody.selectFirst(Evaluator.Tag("a"))
|
||||
val mangas = document.selectFirst(Evaluator.Id("videos"))!!.children().map {
|
||||
val cardBody = it.selectFirst(Evaluator.Class("card-body"))!!
|
||||
val link = cardBody.selectFirst(Evaluator.Tag("a"))!!
|
||||
SManga.create().apply {
|
||||
url = link.attr("href").stripLang()
|
||||
title = link.ownText()
|
||||
thumbnail_url = baseUrl + it.selectFirst(Evaluator.Tag("img")).attr("data-src")
|
||||
genre = cardBody.selectFirst(Evaluator.Tag("label")).ownText()
|
||||
thumbnail_url = baseUrl + it.selectFirst(Evaluator.Tag("img"))!!.attr("data-src")
|
||||
genre = cardBody.selectFirst(Evaluator.Tag("label"))!!.ownText()
|
||||
status = SManga.COMPLETED
|
||||
initialized = true
|
||||
}
|
||||
@ -98,7 +98,7 @@ class Photos18 : HttpSource(), ConfigurableSource {
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
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 ->
|
||||
Page(index, imageUrl = image.attr("data-src"))
|
||||
}
|
||||
@ -145,12 +145,12 @@ class Photos18 : HttpSource(), ConfigurableSource {
|
||||
|
||||
private fun parseCategories(document: Document) {
|
||||
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) {
|
||||
add(Pair("All", ""))
|
||||
items.mapTo(this) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ abstract class SandraAndWoo(
|
||||
private fun pageImageSelector() = "#comic img"
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val img = document.selectFirst(pageImageSelector())
|
||||
val img = document.selectFirst(pageImageSelector())!!
|
||||
val path = img.attr("src")
|
||||
|
||||
return listOf(Page(0, "", "${baseUrl}$path"))
|
||||
|
@ -58,7 +58,7 @@ class Tappytoon(override val lang: String) : HttpSource() {
|
||||
|
||||
private val apiHeaders by lazy {
|
||||
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())
|
||||
.jsonObject["props"]!!.jsonObject["initialState"]!!
|
||||
.jsonObject["axios"]!!.jsonObject["headers"]!!.jsonObject
|
||||
|
@ -50,7 +50,7 @@ abstract class ToomicsGlobal(
|
||||
override fun popularMangaSelector(): String = "li > div.visual"
|
||||
|
||||
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
|
||||
setUrlWithoutDomain(element.select("a").attr("href").removeSuffix("/ab/on"))
|
||||
thumbnail_url = element.select("img").attr("src")
|
||||
@ -125,9 +125,9 @@ abstract class ToomicsGlobal(
|
||||
val num = element.select("div.cell-num").text()
|
||||
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
|
||||
date_upload = parseChapterDate(element.select("div.cell-time time").text()!!)
|
||||
date_upload = parseChapterDate(element.select("div.cell-time time").text())
|
||||
scanlator = "Toomics"
|
||||
url = element.select("a").attr("onclick")
|
||||
.substringAfter("href='")
|
||||
|
@ -65,11 +65,11 @@ class Xinmeitulu : ParsedHttpSource() {
|
||||
// Details
|
||||
|
||||
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()
|
||||
description = document.select(".container > *:not(div)").text()
|
||||
status = SManga.COMPLETED
|
||||
thumbnail_url = document.selectFirst("figure img").attr("abs:data-original")
|
||||
thumbnail_url = document.selectFirst("figure img")!!.attr("abs:data-original")
|
||||
}
|
||||
|
||||
// Chapters
|
||||
@ -77,7 +77,7 @@ class Xinmeitulu : ParsedHttpSource() {
|
||||
override fun chapterListSelector() = "html"
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ class XkcdFR : Xkcd("https://xkcd.lapin.org", "fr") {
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response) =
|
||||
response.asJsoup().selectFirst(imageSelector).let {
|
||||
response.asJsoup().selectFirst(imageSelector)!!.let {
|
||||
// no interactive comics here
|
||||
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