From 4710bd9f02d6ce766c5e5d5dc19ff1aa4ecc94b4 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 18 May 2022 10:48:22 +0300 Subject: [PATCH] Refactor extensions --- build.gradle | 2 +- .../kotatsu/parsers/site/AnibelParser.kt | 2 +- .../kotatsu/parsers/site/BatoToParser.kt | 4 +- .../kotatsu/parsers/site/ChanParser.kt | 7 ++- .../kotatsu/parsers/site/ExHentaiParser.kt | 6 +- .../kotatsu/parsers/site/GroupleParser.kt | 4 +- .../kotatsu/parsers/site/MadaraParser.kt | 14 ++--- .../kotatsu/parsers/site/MangaLibParser.kt | 4 +- .../kotatsu/parsers/site/MangaOwlParser.kt | 4 +- .../kotatsu/parsers/site/MangaTownParser.kt | 20 ++++--- .../kotatsu/parsers/site/NineMangaParser.kt | 3 +- .../kotatsu/parsers/site/NudeMoonParser.kt | 2 +- .../kotatsu/parsers/site/YaoiChanParser.kt | 4 +- .../util/{CollectionExt.kt => Collection.kt} | 2 + .../util/{CookieJarExt.kt => CookieJar.kt} | 2 + .../koitharu/kotatsu/parsers/util/Jsoup.kt | 56 +++++++++++++++++++ .../util/{PrimitiveExt.kt => Number.kt} | 2 + .../parsers/util/{HttpExt.kt => OkHttp.kt} | 2 + .../parsers/util/{ParseExt.kt => Parse.kt} | 33 +++++++++-- .../parsers/util/{StringExt.kt => String.kt} | 2 + 20 files changed, 134 insertions(+), 41 deletions(-) rename src/main/kotlin/org/koitharu/kotatsu/parsers/util/{CollectionExt.kt => Collection.kt} (97%) rename src/main/kotlin/org/koitharu/kotatsu/parsers/util/{CookieJarExt.kt => CookieJar.kt} (96%) create mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/util/Jsoup.kt rename src/main/kotlin/org/koitharu/kotatsu/parsers/util/{PrimitiveExt.kt => Number.kt} (97%) rename src/main/kotlin/org/koitharu/kotatsu/parsers/util/{HttpExt.kt => OkHttp.kt} (87%) rename src/main/kotlin/org/koitharu/kotatsu/parsers/util/{ParseExt.kt => Parse.kt} (75%) rename src/main/kotlin/org/koitharu/kotatsu/parsers/util/{StringExt.kt => String.kt} (99%) diff --git a/build.gradle b/build.gradle index c30cf9f8..b0eaaa9b 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1' implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'com.squareup.okio:okio:3.1.0' - implementation 'org.jsoup:jsoup:1.14.3' + implementation 'org.jsoup:jsoup:1.15.1' implementation 'org.json:json:20220320' implementation 'androidx.collection:collection-ktx:1.2.0' diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/AnibelParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/AnibelParser.kt index 097df140..99e11cc7 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/AnibelParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/AnibelParser.kt @@ -58,7 +58,7 @@ internal class AnibelParser(override val context: MangaLoaderContext) : MangaPar genres slug mediaType - status + status } } """.trimIndent(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/BatoToParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/BatoToParser.kt index 9cadcd89..bb41f55e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/BatoToParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/BatoToParser.kt @@ -189,7 +189,7 @@ internal class BatoToParser(override val context: MangaLoaderContext) : MangaPar val root = body.getElementById("series-list") ?: parseFailed("Cannot find root") return root.children().map { div -> val a = div.selectFirst("a") ?: parseFailed() - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") val title = div.selectFirst(".item-title")?.text() ?: parseFailed("Title not found") Manga( id = generateUid(href), @@ -222,7 +222,7 @@ internal class BatoToParser(override val context: MangaLoaderContext) : MangaPar private fun Element.parseChapter(index: Int): MangaChapter? { val a = selectFirst("a.chapt") ?: return null val extra = selectFirst(".extra") - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") return MangaChapter( id = generateUid(href), name = a.text(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ChanParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ChanParser.kt index 0de28e21..164f61c9 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ChanParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ChanParser.kt @@ -42,11 +42,11 @@ internal abstract class ChanParser(source: MangaSource) : MangaParser(source) { return root.select("div.content_row").mapNotNull { row -> val a = row.selectFirst("div.manga_row1")?.selectFirst("h2")?.selectFirst("a") ?: return@mapNotNull null - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") Manga( id = generateUid(href), url = href, - publicUrl = href.inContextOf(a), + publicUrl = href.toAbsoluteUrl(a.host ?: domain), altTitle = a.attr("title"), title = a.text().substringAfterLast('(').substringBeforeLast(')'), author = row.getElementsByAttributeValueStarting( @@ -81,7 +81,8 @@ internal abstract class ChanParser(source: MangaSource) : MangaParser(source) { description = root.getElementById("description")?.html()?.substringBeforeLast(" - val href = tr?.selectFirst("a")?.relUrl("href") ?: return@mapIndexedNotNull null + val href = tr?.selectFirst("a")?.attrAsRelativeUrlOrNull("href") + ?: return@mapIndexedNotNull null MangaChapter( id = generateUid(href), name = tr.selectFirst("a")?.text().orEmpty(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ExHentaiParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ExHentaiParser.kt index cde5ef98..17b45c6c 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ExHentaiParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ExHentaiParser.kt @@ -106,7 +106,7 @@ internal class ExHentaiParser( val (td1, td2) = tr.children() val glink = td2.selectFirst("div.glink") ?: parseFailed("glink not found") val a = glink.parents().select("a").first() ?: parseFailed("link not found") - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") val tagsDiv = glink.nextElementSibling() ?: parseFailed("tags div not found") val mainTag = td2.selectFirst("div.cn")?.let { div -> MangaTag( @@ -148,7 +148,7 @@ internal class ExHentaiParser( ?.substringAfterLast(' ') ?.toFloatOrNull() ?.div(5f) ?: manga.rating, - largeCoverUrl = cover?.css("background")?.cssUrl(), + largeCoverUrl = cover?.styleValueOrNull("background")?.cssUrl(), description = taglist?.select("tr")?.joinToString("
") { tr -> val (tc, td) = tr.children() val subtags = td.select("a").joinToString { it.html() } @@ -181,7 +181,7 @@ internal class ExHentaiParser( val doc = context.httpGet(chapter.url.withDomain()).parseHtml() val root = doc.body().getElementById("gdt") ?: parseFailed("Root not found") return root.select("a").map { a -> - val url = a.relUrl("href") + val url = a.attrAsRelativeUrl("href") MangaPage( id = generateUid(url), url = url, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/GroupleParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/GroupleParser.kt index 21acd172..5ce4e34e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/GroupleParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/GroupleParser.kt @@ -81,7 +81,7 @@ internal abstract class GroupleParser(source: MangaSource, userAgent: String) : if (descDiv.selectFirst("i.fa-user") != null) { return@mapNotNull null // skip author } - val href = imgDiv.selectFirst("a")?.attr("href")?.inContextOf(node) + val href = imgDiv.selectFirst("a")?.attrAsAbsoluteUrlOrNull("href") if (href == null || href.toHttpUrl().host != baseHost) { return@mapNotNull null // skip external links } @@ -148,7 +148,7 @@ internal abstract class GroupleParser(source: MangaSource, userAgent: String) : chapters = root.selectFirst("div.chapters-link")?.selectFirst("table") ?.select("tr:has(td > a)")?.asReversed()?.mapIndexedNotNull { i, tr -> val a = tr.selectFirst("a") ?: return@mapIndexedNotNull null - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") var translators = "" val translatorElement = a.attr("title") if (!translatorElement.isNullOrBlank()) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MadaraParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MadaraParser.kt index 54d3e6be..823c8c51 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MadaraParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MadaraParser.kt @@ -55,12 +55,13 @@ internal abstract class MadaraParser( payload, ).parseHtml() return doc.select("div.row.c-tabs-item__content").map { div -> - val href = div.selectFirst("a")?.relUrl("href") ?: parseFailed("Link not found") + val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") + ?: parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") Manga( id = generateUid(href), url = href, - publicUrl = href.inContextOf(div), + publicUrl = href.toAbsoluteUrl(div.host ?: getDomain()), coverUrl = div.selectFirst("img")?.src().orEmpty(), title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(), altTitle = null, @@ -140,12 +141,10 @@ internal abstract class MadaraParser( ?.joinToString { it.html() }, chapters = root2.select("li").asReversed().mapIndexed { i, li -> val a = li.selectFirst("a") - val href = a?.relUrl("href").orEmpty().ifEmpty { - parseFailed("Link is missing") - } + val href = a?.attrAsRelativeUrlOrNull("href") ?: parseFailed("Link is missing") MangaChapter( id = generateUid(href), - name = a!!.ownText(), + name = a.ownText(), number = i + 1, url = href, uploadDate = parseChapterDate( @@ -361,7 +360,8 @@ internal abstract class MadaraParser( } @MangaSourceParser("HENTAI_4FREE", "Hentai4Free", "en") - class Hentai4Free(context: MangaLoaderContext) : MadaraParser(context, MangaSource.HENTAI_4FREE, "hentai4free.net") { + class Hentai4Free(context: MangaLoaderContext) : + MadaraParser(context, MangaSource.HENTAI_4FREE, "hentai4free.net") { override val tagPrefix = "hentai-tag/" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaLibParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaLibParser.kt index 8a582096..41a5b0f8 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaLibParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaLibParser.kt @@ -65,7 +65,7 @@ internal open class MangaLibParser( ?: return emptyList() return items.mapNotNull { card -> val a = card.selectFirst("a.media-card") ?: return@mapNotNull null - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") Manga( id = generateUid(href), title = card.selectFirst("h3")?.text().orEmpty(), @@ -74,7 +74,7 @@ internal open class MangaLibParser( author = null, rating = RATING_UNKNOWN, url = href, - publicUrl = href.inContextOf(a), + publicUrl = href.toAbsoluteUrl(a.host ?: getDomain()), tags = emptySet(), state = null, isNsfw = false, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaOwlParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaOwlParser.kt index 301b6dfb..9a1cfb12 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaOwlParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaOwlParser.kt @@ -53,7 +53,7 @@ internal class MangaOwlParser(override val context: MangaLoaderContext) : MangaP val slides = doc.body().select("ul.slides") ?: parseFailed("An error occurred while parsing") val items = slides.select("div.col-md-2") return items.mapNotNull { item -> - val href = item.selectFirst("h6 a")?.relUrl("href") ?: return@mapNotNull null + val href = item.selectFirst("h6 a")?.attrAsRelativeUrlOrNull("href") ?: return@mapNotNull null Manga( id = generateUid(href), title = item.selectFirst("h6 a")?.text() ?: return@mapNotNull null, @@ -134,7 +134,7 @@ internal class MangaOwlParser(override val context: MangaLoaderContext) : MangaP val doc = context.httpGet(fullUrl).parseHtml() val root = doc.body().select("div.item img.owl-lazy") ?: throw ParseException("Root not found") return root.map { div -> - val url = div?.relUrl("data-src") ?: parseFailed("Page image not found") + val url = div?.attrAsRelativeUrlOrNull("data-src") ?: parseFailed("Page image not found") MangaPage( id = generateUid(url), url = url, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaTownParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaTownParser.kt index c8332729..b317ca38 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaTownParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MangaTownParser.kt @@ -58,10 +58,10 @@ internal class MangaTownParser(override val context: MangaLoaderContext) : Manga ?: throw ParseException("Root not found") return root.select("li").mapNotNull { li -> val a = li.selectFirst("a.manga_cover") - val href = a?.relUrl("href") + val href = a?.attrAsRelativeUrlOrNull("href") ?: return@mapNotNull null val views = li.select("p.view") - val status = views.findOwnText { x -> x.startsWith("Status:") } + val status = views.firstNotNullOfOrNull { it.ownText().takeIf { x -> x.startsWith("Status:") } } ?.substringAfter(':')?.trim()?.lowercase(Locale.ROOT) Manga( id = generateUid(href), @@ -71,7 +71,8 @@ internal class MangaTownParser(override val context: MangaLoaderContext) : Manga altTitle = null, rating = li.selectFirst("p.score")?.selectFirst("b") ?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, - author = views.findText { x -> x.startsWith("Author:") }?.substringAfter(':') + author = views.firstNotNullOfOrNull { it.text().takeIf { x -> x.startsWith("Author:") } } + ?.substringAfter(':') ?.trim(), state = when (status) { "ongoing" -> MangaState.ONGOING @@ -87,7 +88,7 @@ internal class MangaTownParser(override val context: MangaLoaderContext) : Manga }.orEmpty(), url = href, isNsfw = false, - publicUrl = href.inContextOf(a), + publicUrl = href.toAbsoluteUrl(a.host ?: getDomain()), ) } } @@ -112,9 +113,10 @@ internal class MangaTownParser(override val context: MangaLoaderContext) : Manga }.orEmpty(), description = info?.getElementById("show")?.ownText(), chapters = chaptersList?.mapIndexedNotNull { i, li -> - val href = li.selectFirst("a")?.relUrl("href") + val href = li.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: return@mapIndexedNotNull null - val name = li.select("span").filter { it.className().isEmpty() } + val name = li.select("span") + .filter { x -> x.className().isEmpty() } .joinToString(" - ") { it.text() }.trim() MangaChapter( id = generateUid(href), @@ -139,8 +141,8 @@ internal class MangaTownParser(override val context: MangaLoaderContext) : Manga val root = doc.body().selectFirst("div.page_select") ?: throw ParseException("Cannot find root") return root.selectFirst("select")?.select("option")?.mapNotNull { - val href = it.relUrl("value") - if (href.endsWith("featured.html")) { + val href = it.attrAsRelativeUrlOrNull("value") + if (href == null || href.endsWith("featured.html")) { return@mapNotNull null } MangaPage( @@ -193,7 +195,7 @@ internal class MangaTownParser(override val context: MangaLoaderContext) : Manga val dateFormat = SimpleDateFormat("MMM dd,yyyy", Locale.US) return list.select("li").asReversed().mapIndexedNotNull { i, li -> val a = li.selectFirst("a") ?: return@mapIndexedNotNull null - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") val name = a.selectFirst("span.vol")?.text().orEmpty().ifEmpty { a.ownText() } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NineMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NineMangaParser.kt index 4e5f0b36..9d2ca8eb 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NineMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NineMangaParser.kt @@ -117,7 +117,8 @@ internal abstract class NineMangaParser( chapters = root.selectFirst("div.chapterbox")?.select("ul.sub_vol_ul > li") ?.asReversed()?.mapIndexed { i, li -> val a = li.selectFirst("a.chapter_list_a") - val href = a?.relUrl("href")?.replace("%20", " ") ?: parseFailed("Link not found") + val href = a?.attrAsRelativeUrlOrNull("href") + ?.replace("%20", " ") ?: parseFailed("Link not found") MangaChapter( id = generateUid(href), name = a.text(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NudeMoonParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NudeMoonParser.kt index 740a2618..ad36a90b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NudeMoonParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/NudeMoonParser.kt @@ -68,7 +68,7 @@ internal class NudeMoonParser( return root.select("table.news_pic2").mapNotNull { row -> val a = row.selectFirst("td.bg_style1")?.selectFirst("a") ?: return@mapNotNull null - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") val title = a.selectFirst("h2")?.text().orEmpty() val info = row.selectFirst("td[width=100%]") ?: return@mapNotNull null Manga( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/YaoiChanParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/YaoiChanParser.kt index c344cf7b..36d38d60 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/YaoiChanParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/YaoiChanParser.kt @@ -7,8 +7,8 @@ import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrl import org.koitharu.kotatsu.parsers.util.parseHtml -import org.koitharu.kotatsu.parsers.util.relUrl @MangaSourceParser("YAOICHAN", "Яой-тян", "ru") internal class YaoiChanParser(override val context: MangaLoaderContext) : ChanParser(MangaSource.YAOICHAN) { @@ -25,7 +25,7 @@ internal class YaoiChanParser(override val context: MangaLoaderContext) : ChanPa chapters = root.select("table.table_cha").flatMap { table -> table.select("div.manga") }.mapNotNull { it.selectFirst("a") }.reversed().mapIndexed { i, a -> - val href = a.relUrl("href") + val href = a.attrAsRelativeUrl("href") MangaChapter( id = generateUid(href), name = a.text().trim(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/CollectionExt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Collection.kt similarity index 97% rename from src/main/kotlin/org/koitharu/kotatsu/parsers/util/CollectionExt.kt rename to src/main/kotlin/org/koitharu/kotatsu/parsers/util/Collection.kt index 5eaa8ef7..df3d4b85 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/CollectionExt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Collection.kt @@ -1,3 +1,5 @@ +@file:JvmName("CollectionUtils") + package org.koitharu.kotatsu.parsers.util import androidx.collection.ArrayMap diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/CookieJarExt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/CookieJar.kt similarity index 96% rename from src/main/kotlin/org/koitharu/kotatsu/parsers/util/CookieJarExt.kt rename to src/main/kotlin/org/koitharu/kotatsu/parsers/util/CookieJar.kt index 7ff3cc82..4c07eef5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/CookieJarExt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/CookieJar.kt @@ -1,3 +1,5 @@ +@file:JvmName("CookieJarUtils") + package org.koitharu.kotatsu.parsers.util import okhttp3.Cookie diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Jsoup.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Jsoup.kt new file mode 100644 index 00000000..a611d763 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Jsoup.kt @@ -0,0 +1,56 @@ +@file:JvmName("JsoupUtils") + +package org.koitharu.kotatsu.parsers.util + +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import org.jsoup.nodes.Element + +val Element.host: String? + get() { + val uri = baseUri() + return if (uri.isEmpty()) { + null + } else { + uri.toHttpUrlOrNull()?.host + } + } + +fun Element.attrOrNull(attributeKey: String) = attr(attributeKey).takeUnless { it.isEmpty() } + +fun Element.attrAsRelativeUrlOrNull(attributeKey: String): String? { + val attr = attr(attributeKey).trim() + if (attr.isEmpty()) { + return null + } + if (attr.startsWith("/")) { + return attr + } + val host = baseUri().toHttpUrlOrNull()?.host ?: return null + return attr.substringAfter(host) +} + +fun Element.attrAsRelativeUrl(attributeKey: String): String { + return requireNotNull(attrAsRelativeUrlOrNull(attributeKey)) { + "Cannot get relative url for $attributeKey: \"${attr(attributeKey)}\"" + } +} + +fun Element.attrAsAbsoluteUrlOrNull(attributeKey: String): String? { + val attr = attr(attributeKey).trim() + if (attr.isEmpty()) { + return null + } + return (baseUri().toHttpUrlOrNull()?.newBuilder(attr) ?: return null).toString() +} + +fun Element.attrAsAbsoluteUrl(attributeKey: String): String { + return requireNotNull(attrAsAbsoluteUrlOrNull(attributeKey)) { + "Cannot get absolute url for $attributeKey: \"${attr(attributeKey)}\"" + } +} + +fun Element.styleValueOrNull(property: String): String? { + val regex = Regex("${Regex.escape(property)}\\s*:\\s*[^;]+") + val css = attr("style").find(regex) ?: return null + return css.substringAfter(':').removeSuffix(';').trim() +} \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/PrimitiveExt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Number.kt similarity index 97% rename from src/main/kotlin/org/koitharu/kotatsu/parsers/util/PrimitiveExt.kt rename to src/main/kotlin/org/koitharu/kotatsu/parsers/util/Number.kt index c98b895e..3c5abc9b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/PrimitiveExt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Number.kt @@ -1,3 +1,5 @@ +@file:JvmName("NumberUtils") + package org.koitharu.kotatsu.parsers.util import java.text.DecimalFormat diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/HttpExt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/OkHttp.kt similarity index 87% rename from src/main/kotlin/org/koitharu/kotatsu/parsers/util/HttpExt.kt rename to src/main/kotlin/org/koitharu/kotatsu/parsers/util/OkHttp.kt index a84d62fb..08c5d3c0 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/HttpExt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/OkHttp.kt @@ -1,3 +1,5 @@ +@file:JvmName("OkHttpUtils") + package org.koitharu.kotatsu.parsers.util import kotlinx.coroutines.suspendCancellableCoroutine diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/ParseExt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Parse.kt similarity index 75% rename from src/main/kotlin/org/koitharu/kotatsu/parsers/util/ParseExt.kt rename to src/main/kotlin/org/koitharu/kotatsu/parsers/util/Parse.kt index d729d9cf..61196bd7 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/ParseExt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/Parse.kt @@ -1,3 +1,5 @@ +@file:JvmName("ParseUtils") + package org.koitharu.kotatsu.parsers.util import okhttp3.Response @@ -45,6 +47,11 @@ fun Response.parseJsonArray(): JSONArray { } } +@Deprecated( + message = "", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith("firstNotNullOfOrNull { it.ownText().takeIf(predicate) }"), +) inline fun Elements.findOwnText(predicate: (String) -> Boolean): String? { for (x in this) { val ownText = x.ownText() @@ -55,6 +62,11 @@ inline fun Elements.findOwnText(predicate: (String) -> Boolean): String? { return null } +@Deprecated( + message = "", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith("firstNotNullOfOrNull { it.text().takeIf(predicate) }"), +) inline fun Elements.findText(predicate: (String) -> Boolean): String? { for (x in this) { val text = x.text() @@ -65,6 +77,11 @@ inline fun Elements.findText(predicate: (String) -> Boolean): String? { return null } +@Deprecated( + message = "Use toAbsoluteUrl() instead", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith("toAbsoluteUrl(node.host)"), +) fun String.inContextOf(node: Node): String { return if (this.isEmpty()) { "" @@ -86,6 +103,11 @@ fun String.toAbsoluteUrl(domain: String): String = when { else -> this } +@Deprecated( + message = "", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith("attrAsRelativeUrl(attributeKey)"), +) fun Element.relUrl(attributeKey: String): String { val attr = attr(attributeKey).trim() if (attr.isEmpty()) { @@ -100,11 +122,12 @@ fun Element.relUrl(attributeKey: String): String { private val REGEX_URL_BASE = Regex("^[^/]{2,6}://[^/]+/", RegexOption.IGNORE_CASE) -fun Element.css(property: String): String? { - val regex = Regex("${Regex.escape(property)}\\s*:\\s*[^;]+") - val css = attr("style").find(regex) ?: return null - return css.substringAfter(':').removeSuffix(';').trim() -} +@Deprecated( + message = "", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith("styleValueOrNull(property)"), +) +fun Element.css(property: String): String? = styleValueOrNull(property) fun DateFormat.tryParse(str: String?): Long = if (str.isNullOrEmpty()) { 0L diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/StringExt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/String.kt similarity index 99% rename from src/main/kotlin/org/koitharu/kotatsu/parsers/util/StringExt.kt rename to src/main/kotlin/org/koitharu/kotatsu/parsers/util/String.kt index 9cae0f0b..d4e538e3 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/StringExt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/String.kt @@ -1,3 +1,5 @@ +@file:JvmName("StringUtils") + package org.koitharu.kotatsu.parsers.util import androidx.collection.arraySetOf