diff --git a/src/uk/mangainua/build.gradle b/src/uk/mangainua/build.gradle index ff5ee9049..5760a5906 100644 --- a/src/uk/mangainua/build.gradle +++ b/src/uk/mangainua/build.gradle @@ -5,7 +5,7 @@ ext { extName = 'MangaInUa' pkgNameSuffix = 'uk.mangainua' extClass = '.Mangainua' - extVersionCode = 3 + extVersionCode = 4 isNsfw = true } diff --git a/src/uk/mangainua/res/mipmap-hdpi/ic_launcher.png b/src/uk/mangainua/res/mipmap-hdpi/ic_launcher.png index d546cd897..c479bc1db 100644 Binary files a/src/uk/mangainua/res/mipmap-hdpi/ic_launcher.png and b/src/uk/mangainua/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/uk/mangainua/res/mipmap-mdpi/ic_launcher.png b/src/uk/mangainua/res/mipmap-mdpi/ic_launcher.png index 3b63958da..ced96f77d 100644 Binary files a/src/uk/mangainua/res/mipmap-mdpi/ic_launcher.png and b/src/uk/mangainua/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/uk/mangainua/res/mipmap-xhdpi/ic_launcher.png b/src/uk/mangainua/res/mipmap-xhdpi/ic_launcher.png index 812eba114..f37eb7802 100644 Binary files a/src/uk/mangainua/res/mipmap-xhdpi/ic_launcher.png and b/src/uk/mangainua/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/uk/mangainua/res/mipmap-xxhdpi/ic_launcher.png b/src/uk/mangainua/res/mipmap-xxhdpi/ic_launcher.png index 5d90bc81d..3961213bc 100644 Binary files a/src/uk/mangainua/res/mipmap-xxhdpi/ic_launcher.png and b/src/uk/mangainua/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/uk/mangainua/res/mipmap-xxxhdpi/ic_launcher.png b/src/uk/mangainua/res/mipmap-xxxhdpi/ic_launcher.png index 43900ba24..99ef7402b 100644 Binary files a/src/uk/mangainua/res/mipmap-xxxhdpi/ic_launcher.png and b/src/uk/mangainua/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/uk/mangainua/src/eu/kanade/tachiyomi/extension/uk/mangainua/Mangainua.kt b/src/uk/mangainua/src/eu/kanade/tachiyomi/extension/uk/mangainua/Mangainua.kt index 66f2d6d59..685059d11 100644 --- a/src/uk/mangainua/src/eu/kanade/tachiyomi/extension/uk/mangainua/Mangainua.kt +++ b/src/uk/mangainua/src/eu/kanade/tachiyomi/extension/uk/mangainua/Mangainua.kt @@ -7,13 +7,17 @@ import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import eu.kanade.tachiyomi.util.asJsoup import okhttp3.FormBody import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import org.jsoup.select.Elements +import org.jsoup.select.Evaluator import java.text.SimpleDateFormat import java.util.Locale @@ -27,7 +31,7 @@ class Mangainua : ParsedHttpSource() { override val client: OkHttpClient = network.cloudflareClient - override fun headersBuilder(): Headers.Builder = Headers.Builder() + override fun headersBuilder(): Headers.Builder = super.headersBuilder() .add("Referer", baseUrl) // Popular @@ -37,11 +41,11 @@ class Mangainua : ParsedHttpSource() { override fun popularMangaSelector() = "div.owl-carousel div.card--big" override fun popularMangaFromElement(element: Element): SManga { return SManga.create().apply { - element.select("h3.card__title a").first()!!.let { + element.selectFirst("h3.card__title a")!!.let { setUrlWithoutDomain(it.attr("href")) title = it.text() } - thumbnail_url = element.select("img").attr("abs:src") + thumbnail_url = element.selectFirst("img")?.absUrl("src") } } override fun popularMangaNextPageSelector() = "not used" @@ -53,11 +57,11 @@ class Mangainua : ParsedHttpSource() { override fun latestUpdatesSelector() = "main.main article.item" override fun latestUpdatesFromElement(element: Element): SManga { return SManga.create().apply { - element.select("h3.card__title a").first()!!.let { + element.selectFirst("h3.card__title a")!!.let { setUrlWithoutDomain(it.attr("href")) title = it.text() } - thumbnail_url = element.select("div.card--big img").attr("abs:data-src") + thumbnail_url = element.selectFirst("div.card--big img")?.absUrl("data-src") } } override fun latestUpdatesNextPageSelector() = "a:contains(Наступна)" @@ -76,18 +80,18 @@ class Mangainua : ParsedHttpSource() { headers = headers, ) } else { - throw UnsupportedOperationException("Запит має містити щонайменше 3 символи / The query must contain at least 3 characters") + throw Exception("Запит має містити щонайменше 3 символи / The query must contain at least 3 characters") } } override fun searchMangaSelector() = latestUpdatesSelector() override fun searchMangaFromElement(element: Element): SManga { return SManga.create().apply { - element.select("h3.card__title a").first()!!.let { + element.selectFirst("h3.card__title a")!!.let { setUrlWithoutDomain(it.attr("href")) title = it.text() } - thumbnail_url = element.select("div.card--big img").attr("abs:src") + thumbnail_url = element.selectFirst("div.card--big img")?.absUrl("src") } } override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector() @@ -95,35 +99,40 @@ class Mangainua : ParsedHttpSource() { // Manga Details override fun mangaDetailsParse(document: Document): SManga { return SManga.create().apply { - title = document.select("span.UAname").text() - description = document.select("div.item__full-description").text() - thumbnail_url = document.select("div.item__full-sidebar--poster img").first()!!.attr("abs:src") - status = when (document.select("div.item__full-sideba--header:has(div:containsOwn(Статус перекладу:))").first()?.select("span.item__full-sidebar--description")?.first()?.text()) { + title = document.selectFirst("span.UAname")!!.text() + description = document.selectFirst("div.item__full-description")!!.text() + thumbnail_url = document.selectFirst("div.item__full-sidebar--poster img")!!.absUrl("src") + status = when (document.selectFirst("div.item__full-sideba--header:has(div:containsOwn(Статус перекладу:))")?.selectFirst("span.item__full-sidebar--description")?.text()) { "Триває" -> SManga.ONGOING "Покинуто" -> SManga.CANCELLED "Закінчений" -> SManga.COMPLETED else -> SManga.UNKNOWN } - val type = when (document.select("div.item__full-sideba--header:has(div:containsOwn(Тип:))").first()?.select("span.item__full-sidebar--description")?.first()!!.text()) { + val type = when (document.selectFirst("div.item__full-sideba--header:has(div:containsOwn(Тип:))")?.selectFirst("span.item__full-sidebar--description")!!.text()) { "ВЕБМАНХВА" -> "Manhwa" "МАНХВА" -> "Manhwa" "МАНЬХВА" -> "Manhua" "ВЕБМАНЬХВА" -> "Manhua" else -> "Manga" } - genre = document.select("div.item__full-sideba--header:has(div:containsOwn(Жанри:))").first()?.select("span.item__full-sidebar--description")?.first()!!.select("a").joinToString { it.text() } + ", " + type + genre = document.selectFirst("div.item__full-sideba--header:has(div:containsOwn(Жанри:))")?.selectFirst("span.item__full-sidebar--description")!!.select("a").joinToString { it.text() } + ", " + type } } // Chapters - override fun chapterListSelector() = "div.ltcitems" - - private var previousChapterName: String? = null - private var previousChapterNumber: Float = 0.0f + override fun chapterListSelector() = throw UnsupportedOperationException() override fun chapterFromElement(element: Element): SChapter { - return SChapter.create().apply { - element.select("a").let { urlElement -> + throw UnsupportedOperationException() + } + + private fun parseChapterElements(elements: Elements): List { + var previousChapterName: String? = null + var previousChapterNumber: Float = 0.0f + val dateFormat = DATE_FORMATTER + return elements.map { element -> + SChapter.create().apply { + val urlElement = element.selectFirst("a")!! setUrlWithoutDomain(urlElement.attr("href")) val chapterName = urlElement.text().substringAfter("НОВЕ").trim() val chapterNumber = urlElement.text().substringAfter("Розділ").substringBefore("-").trim() @@ -137,31 +146,58 @@ class Mangainua : ParsedHttpSource() { chapter_number = chapterNumber.toFloat() previousChapterNumber = chapterNumber.toFloat() } + date_upload = dateFormat.parse(element.child(0).ownText())?.time!! } - date_upload = parseDate(element.select("div.ltcright:containsOwn(.)").text()) } } override fun chapterListParse(response: Response): List { - return super.chapterListParse(response).reversed() + val document = response.asJsoup() + val userHash = document.parseUserHash() + val metaElement = document.selectFirst(Evaluator.Id("linkstocomics"))!! + val body = FormBody.Builder() + .addEncoded("action", "show") + .addEncoded("news_id", metaElement.attr("data-news_id")) + .addEncoded("news_category", metaElement.attr("data-news_category")) + .addEncoded("this_link", metaElement.attr("data-this_link")) + .addEncoded("user_hash", userHash) + .build() + val request = POST("$baseUrl/engine/ajax/controller.php?mod=load_chapters", headers, body) + val chaptersHtml = client.newCall(request).execute().body.string() + val chaptersDocument = Jsoup.parseBodyFragment(chaptersHtml) + return parseChapterElements(chaptersDocument.body().children()).asReversed() } // Pages override fun pageListParse(document: Document): List { - return document.select("ul.loadcomicsimages img").mapIndexed { i, element -> - Page(i, "", element.attr("abs:data-src")) + val userHash = document.parseUserHash() + val newsId = document.selectFirst(Evaluator.Id("comics"))!!.attr("data-news_id") + val url = "$baseUrl/engine/ajax/controller.php?mod=load_chapters_image&news_id=$newsId&action=show&user_hash=$userHash" + val pagesHtml = client.newCall(GET(url, headers)).execute().body.string() + val pagesDocument = Jsoup.parseBodyFragment(pagesHtml) + return pagesDocument.getElementsByTag("img").mapIndexed { index, img -> + Page(index, imageUrl = img.attr("data-src")) } } - override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") - - private fun parseDate(dateStr: String): Long { - return runCatching { DATE_FORMATTER.parse(dateStr)?.time } - .getOrNull() ?: 0L - } + override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException() companion object { private val DATE_FORMATTER by lazy { SimpleDateFormat("dd.MM.yyyy", Locale.ENGLISH) } + + private fun Document.parseUserHash(): String { + val start = "site_login_hash = '" + for (element in body().children()) { + if (element.tagName() != "script") continue + val data = element.data() + val leftIndex = data.indexOf(start) + if (leftIndex == -1) continue + val startIndex = leftIndex + start.length + val endIndex = data.indexOf('\'', startIndex) + return data.substring(startIndex, endIndex) + } + throw Exception("Couldn't find user hash") + } } }