Update jsoup (#15321)
This commit is contained in:
parent
7964dc4613
commit
e1f59a845e
|
@ -21,7 +21,7 @@ coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-androi
|
|||
injekt-core = { module = "com.github.inorichi.injekt:injekt-core", version = "65b0440" }
|
||||
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…
Reference in New Issue