diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/OnlineSource.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/OnlineSource.kt index 746666cf07..fa9759b82e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/OnlineSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/OnlineSource.kt @@ -14,7 +14,10 @@ import eu.kanade.tachiyomi.data.source.Source import eu.kanade.tachiyomi.data.source.model.MangasPage import eu.kanade.tachiyomi.data.source.model.Page import eu.kanade.tachiyomi.util.UrlUtil -import okhttp3.* +import okhttp3.Headers +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response import rx.Observable import uy.kohesive.injekt.injectLazy @@ -397,27 +400,6 @@ abstract class OnlineSource(context: Context) : Source { // Utility methods - /** - * Returns an absolute url from a href. - * - * Ex: - * href="http://example.com/foo" url="http://example.com" -> http://example.com/foo - * href="/mypath" url="http://example.com/foo" -> http://example.com/mypath - * href="bar" url="http://example.com/foo" -> http://example.com/bar - * href="?bar" url="http://example.com/foo" -> http://example.com/foo?bar - * href="bar" url="http://example.com/foo/" -> http://example.com/foo/bar - * - * @param href the href attribute from the html. - * @param url the requested url. - */ - fun getAbsoluteUrl(href: String, url: HttpUrl) = when { - href.startsWith("http://") || href.startsWith("https://") -> href - href.startsWith("/") -> url.newBuilder().encodedPath("/").fragment(null).query(null) - .toString() + href.substring(1) - href.startsWith("?") -> url.toString().substringBeforeLast('?') + "$href" - else -> url.toString().substringBeforeLast('/') + "/$href" - } - fun fetchAllImageUrlsFromPageList(pages: List) = Observable.from(pages) .filter { !it.imageUrl.isNullOrEmpty() } .mergeWith(fetchRemainingImageUrlsFromPageList(pages)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/ParsedOnlineSource.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/ParsedOnlineSource.kt index 80e11fce8c..2c2b8de14a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/ParsedOnlineSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/ParsedOnlineSource.kt @@ -5,8 +5,8 @@ import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.source.model.MangasPage import eu.kanade.tachiyomi.data.source.model.Page +import eu.kanade.tachiyomi.util.asJsoup import okhttp3.Response -import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -24,7 +24,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) { * @param page the page object to be filled. */ override fun popularMangaParse(response: Response, page: MangasPage) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() for (element in document.select(popularMangaSelector())) { Manga.create(id).apply { popularMangaFromElement(element, this) @@ -33,9 +33,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) { } popularMangaNextPageSelector()?.let { selector -> - page.nextPageUrl = document.select(selector).first()?.attr("href")?.let { - getAbsoluteUrl(it, response.request().url()) - } + page.nextPageUrl = document.select(selector).first()?.absUrl("href") } } @@ -67,7 +65,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) { * @param query the search query. */ override fun searchMangaParse(response: Response, page: MangasPage, query: String) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() for (element in document.select(searchMangaSelector())) { Manga.create(id).apply { searchMangaFromElement(element, this) @@ -76,9 +74,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) { } searchMangaNextPageSelector()?.let { selector -> - page.nextPageUrl = document.select(selector).first()?.attr("href")?.let { - getAbsoluteUrl(it, response.request().url()) - } + page.nextPageUrl = document.select(selector).first()?.absUrl("href") } } @@ -109,7 +105,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) { * @param manga the manga to fill. */ override fun mangaDetailsParse(response: Response, manga: Manga) { - mangaDetailsParse(Jsoup.parse(response.body().string()), manga) + mangaDetailsParse(response.asJsoup(), manga) } /** @@ -127,7 +123,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) { * @param chapters the list of chapters to fill. */ override fun chapterListParse(response: Response, chapters: MutableList) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() for (element in document.select(chapterListSelector())) { Chapter.create().apply { @@ -157,7 +153,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) { * @param pages the list of pages to fill. */ override fun pageListParse(response: Response, pages: MutableList) { - pageListParse(Jsoup.parse(response.body().string()), pages) + pageListParse(response.asJsoup(), pages) } /** @@ -174,7 +170,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) { * @param response the response from the site. */ override fun imageUrlParse(response: Response): String { - return imageUrlParse(Jsoup.parse(response.body().string())) + return imageUrlParse(response.asJsoup()) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/YamlOnlineSource.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/YamlOnlineSource.kt index 22b145e503..090166006d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/YamlOnlineSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/YamlOnlineSource.kt @@ -8,9 +8,9 @@ import eu.kanade.tachiyomi.data.network.POST import eu.kanade.tachiyomi.data.source.getLanguages import eu.kanade.tachiyomi.data.source.model.MangasPage import eu.kanade.tachiyomi.data.source.model.Page +import eu.kanade.tachiyomi.util.asJsoup import okhttp3.Request import okhttp3.Response -import org.jsoup.Jsoup import org.jsoup.nodes.Element import java.text.SimpleDateFormat import java.util.* @@ -52,7 +52,7 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con override fun popularMangaInitialUrl() = map.popular.url override fun popularMangaParse(response: Response, page: MangasPage) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() for (element in document.select(map.popular.manga_css)) { Manga.create(id).apply { title = element.text() @@ -62,9 +62,7 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con } map.popular.next_url_css?.let { selector -> - page.nextPageUrl = document.select(selector).first()?.attr("href")?.let { - getAbsoluteUrl(it, response.request().url()) - } + page.nextPageUrl = document.select(selector).first()?.absUrl("href") } } @@ -81,7 +79,7 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con override fun searchMangaInitialUrl(query: String) = map.search.url.replace("\$query", query) override fun searchMangaParse(response: Response, page: MangasPage, query: String) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() for (element in document.select(map.search.manga_css)) { Manga.create(id).apply { title = element.text() @@ -91,14 +89,12 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con } map.search.next_url_css?.let { selector -> - page.nextPageUrl = document.select(selector).first()?.attr("href")?.let { - getAbsoluteUrl(it, response.request().url()) - } + page.nextPageUrl = document.select(selector).first()?.absUrl("href") } } override fun mangaDetailsParse(response: Response, manga: Manga) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() with(map.manga) { val pool = parts.get(document) @@ -112,7 +108,7 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con } override fun chapterListParse(response: Response, chapters: MutableList) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() with(map.chapters) { val pool = emptyMap() val dateFormat = SimpleDateFormat(date?.format, Locale.ENGLISH) @@ -131,7 +127,7 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con } override fun pageListParse(response: Response, pages: MutableList) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() with(map.pages) { val url = response.request().url().toString() pages_css?.let { @@ -143,20 +139,16 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con } for ((i, element) in document.select(image_css).withIndex()) { - pages.getOrNull(i)?.imageUrl = element.attr(image_attr).let { - getAbsoluteUrl(it, response.request().url()) - } + pages.getOrNull(i)?.imageUrl = element.absUrl(image_attr) } } } override fun imageUrlParse(response: Response): String { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() return with(map.pages) { - document.select(image_css).first().attr(image_attr).let { - getAbsoluteUrl(it, response.request().url()) - } + document.select(image_css).first().absUrl(image_attr) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt index ac04052da5..7f114bfdb5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt @@ -14,11 +14,11 @@ import eu.kanade.tachiyomi.data.source.model.MangasPage import eu.kanade.tachiyomi.data.source.model.Page import eu.kanade.tachiyomi.data.source.online.LoginSource import eu.kanade.tachiyomi.data.source.online.ParsedOnlineSource +import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.selectText import okhttp3.FormBody import okhttp3.Request import okhttp3.Response -import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element import rx.Observable @@ -60,7 +60,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex override fun popularMangaInitialUrl() = "$baseUrl/search_ajax?order_cond=views&order=desc&p=1" override fun popularMangaParse(response: Response, page: MangasPage) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() for (element in document.select(popularMangaSelector())) { Manga.create(id).apply { popularMangaFromElement(element, this) @@ -87,7 +87,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex override fun searchMangaInitialUrl(query: String) = "$baseUrl/search_ajax?name=${Uri.encode(query)}&p=1" override fun searchMangaParse(response: Response, page: MangasPage, query: String) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() for (element in document.select(searchMangaSelector())) { Manga.create(id).apply { searchMangaFromElement(element, this) @@ -139,7 +139,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex throw Exception(notice) } - val document = Jsoup.parse(body) + val document = response.asJsoup(body) for (element in document.select(chapterListSelector())) { Chapter.create().apply { @@ -221,11 +221,11 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex override fun login(username: String, password: String) = client.newCall(GET("$baseUrl/forums/index.php?app=core&module=global§ion=login", headers)) .asObservable() - .flatMap { doLogin(it.body().string(), username, password) } + .flatMap { doLogin(it, username, password) } .map { isAuthenticationSuccessful(it) } - private fun doLogin(response: String, username: String, password: String): Observable { - val doc = Jsoup.parse(response) + private fun doLogin(response: Response, username: String, password: String): Observable { + val doc = response.asJsoup() val form = doc.select("#login").first() val url = form.attr("action") val authKey = form.select("input[name=auth_key]").first() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt index def557ecdc..17d9f10450 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt @@ -7,8 +7,8 @@ import eu.kanade.tachiyomi.data.source.EN import eu.kanade.tachiyomi.data.source.Language import eu.kanade.tachiyomi.data.source.model.Page import eu.kanade.tachiyomi.data.source.online.ParsedOnlineSource +import eu.kanade.tachiyomi.util.asJsoup import okhttp3.Response -import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element import java.text.ParseException @@ -105,7 +105,7 @@ class Mangafox(context: Context, override val id: Int) : ParsedOnlineSource(cont } override fun pageListParse(response: Response, pages: MutableList) { - val document = Jsoup.parse(response.body().string()) + val document = response.asJsoup() val url = response.request().url().toString().substringBeforeLast('/') document.select("select.m").first().select("option:not([value=0])").forEach { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/JsoupExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/JsoupExtensions.kt index be971001e0..86a5b18ac8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/JsoupExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/JsoupExtensions.kt @@ -1,5 +1,8 @@ package eu.kanade.tachiyomi.util +import okhttp3.Response +import org.jsoup.Jsoup +import org.jsoup.nodes.Document import org.jsoup.nodes.Element fun Element.selectText(css: String, defaultValue: String? = null): String? { @@ -10,3 +13,10 @@ fun Element.selectInt(css: String, defaultValue: Int = 0): Int { return select(css).first()?.text()?.toInt() ?: defaultValue } +/** + * Returns a Jsoup document for this response. + * @param html the body of the response. Use only if the body was read before calling this method. + */ +fun Response.asJsoup(html: String? = null): Document { + return Jsoup.parse(html ?: body().string(), request().url().toString()) +} \ No newline at end of file