From 599b2a6c81e1694c5d7198dde31a7bdaddebd739 Mon Sep 17 00:00:00 2001 From: e-shl <35057681+e-shl@users.noreply.github.com> Date: Thu, 30 Dec 2021 22:28:28 +0500 Subject: [PATCH] [RU]ComX new HTML view (#10283) * [RU]ComX new HTML view * saveFromResponse Cookie * saveFromResponse Cookie 2 * Exception antibot string --- src/ru/comx/build.gradle | 2 +- .../tachiyomi/extension/ru/comx/ComX.kt | 290 +++++++++--------- 2 files changed, 151 insertions(+), 141 deletions(-) diff --git a/src/ru/comx/build.gradle b/src/ru/comx/build.gradle index 49e30cbd9..63cff03b0 100644 --- a/src/ru/comx/build.gradle +++ b/src/ru/comx/build.gradle @@ -6,7 +6,7 @@ ext { extName = 'ComX' pkgNameSuffix = 'ru.comx' extClass = '.ComX' - extVersionCode = 12 + extVersionCode = 13 } dependencies { diff --git a/src/ru/comx/src/eu/kanade/tachiyomi/extension/ru/comx/ComX.kt b/src/ru/comx/src/eu/kanade/tachiyomi/extension/ru/comx/ComX.kt index e0691b3f2..cd491ea82 100644 --- a/src/ru/comx/src/eu/kanade/tachiyomi/extension/ru/comx/ComX.kt +++ b/src/ru/comx/src/eu/kanade/tachiyomi/extension/ru/comx/ComX.kt @@ -1,9 +1,9 @@ package eu.kanade.tachiyomi.extension.ru.comx +import android.webkit.CookieManager import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.Page @@ -17,9 +17,11 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive +import okhttp3.Cookie +import okhttp3.CookieJar import okhttp3.FormBody import okhttp3.Headers -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.HttpUrl import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response @@ -42,22 +44,30 @@ class ComX : ParsedHttpSource() { override val lang = "ru" override val supportsLatest = true - - private val userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0" - + private val cookieManager by lazy { CookieManager.getInstance() } override val client: OkHttpClient = network.cloudflareClient.newBuilder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .addNetworkInterceptor(RateLimitInterceptor(3)) + .cookieJar(object : CookieJar { + override fun saveFromResponse(url: HttpUrl, cookies: List) = + cookies.filter { it.matches(url) }.forEach { + cookieManager.setCookie(url.toString(), it.toString()) + } + + override fun loadForRequest(url: HttpUrl) = + cookieManager.getCookie(url.toString())?.split("; ") + ?.mapNotNull { Cookie.parse(url, it) } ?: emptyList() + }) .build() override fun headersBuilder(): Headers.Builder = Headers.Builder() - .add("User-Agent", userAgent) - .add("Referer", baseUrl) + .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/78.0") + .add("Referer", baseUrl + "/comix-read/") - override fun popularMangaSelector() = "div.shortstory1" + override fun popularMangaSelector() = "div.short" - override fun latestUpdatesSelector() = "ul.last-comix li" + override fun latestUpdatesSelector() = "ul#content-load li.latest" override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/comix-read/page/$page/", headers) @@ -69,74 +79,80 @@ class ComX : ParsedHttpSource() { val mangas = document.select(popularMangaSelector()).map { element -> popularMangaFromElement(element) } - if (mangas.isEmpty()) throw UnsupportedOperationException("Error: Open in WebView and solve the Antirobot!") + if (document.html().contains("Sorry, your request has been denied.")) throw UnsupportedOperationException("Error: Open in WebView and solve the Antirobot!") - val hasNextPage = popularMangaNextPageSelector().let { selector -> - document.select(selector).first() - } != null - - return MangasPage(mangas, hasNextPage) + return MangasPage(mangas, document.select(".pagination__pages span").first().text().toInt() <= document.select(".pagination__pages a:last-child").first().text().toInt()) } override fun popularMangaFromElement(element: Element): SManga { val manga = SManga.create() manga.thumbnail_url = baseUrl + element.select("img").first().attr("src") - element.select("div.info-poster1 a").first().let { + element.select(".readed__title a").first().let { manga.setUrlWithoutDomain(it.attr("href")) manga.title = it.text() } return manga } + override fun latestUpdatesParse(response: Response): MangasPage { + val document = response.asJsoup() + + val mangas = document.select(latestUpdatesSelector()).map { element -> + latestUpdatesFromElement(element) + } + if (document.html().contains("Sorry, your request has been denied.")) throw UnsupportedOperationException("Error: Open in WebView and solve the Antirobot!") + + return MangasPage(mangas, false) + } override fun latestUpdatesFromElement(element: Element): SManga { val manga = SManga.create() manga.thumbnail_url = baseUrl + element.select("img").first().attr("src") - element.select("a.comix-last-title").first().let { + element.select("a.latest__title").first().let { manga.setUrlWithoutDomain(it.attr("href")) manga.title = it.text() } return manga } - override fun popularMangaNextPageSelector() = ".pnext:last-child" + override fun popularMangaNextPageSelector(): Nothing? = null override fun latestUpdatesNextPageSelector(): Nothing? = null - override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() + override fun searchMangaNextPageSelector(): Nothing? = null override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = "$baseUrl/index.php?do=xsearch&searchCat=comix-read&page=$page".toHttpUrlOrNull()!!.newBuilder() + /** val url = "$baseUrl/index.php?do=xsearch&searchCat=comix-read&page=$page".toHttpUrlOrNull()!!.newBuilder() (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is TypeList -> filter.state.forEach { type -> - if (type.state) { - url.addQueryParameter("field[type][${type.id}]", 1.toString()) - } - } - is PubList -> filter.state.forEach { publisher -> - if (publisher.state) { - url.addQueryParameter("subCat[]", publisher.id) - } - } - is GenreList -> filter.state.forEach { genre -> - if (genre.state) { - url.addQueryParameter("field[genre][${genre.id}]", 1.toString()) - } - } - } + when (filter) { + is TypeList -> filter.state.forEach { type -> + if (type.state) { + url.addQueryParameter("field[type][${type.id}]", 1.toString()) } + } + is PubList -> filter.state.forEach { publisher -> + if (publisher.state) { + url.addQueryParameter("subCat[]", publisher.id) + } + } + is GenreList -> filter.state.forEach { genre -> + if (genre.state) { + url.addQueryParameter("field[genre][${genre.id}]", 1.toString()) + } + } + } + }**/ if (query.isNotEmpty()) { return POST( - "$baseUrl/comix-read/", + "$baseUrl/index.php?do=search&search_start=$page", body = FormBody.Builder() .add("do", "search") - .add("story", query) .add("subaction", "search") + .add("story", query) .build(), headers = headers ) } - return GET(url.toString(), headers) + return GET("$baseUrl/comix-read/", headers) } override fun searchMangaSelector() = popularMangaSelector() @@ -144,26 +160,19 @@ class ComX : ParsedHttpSource() { override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div.maincont").first() + if (document.html().contains("Sorry, your request has been denied.")) throw UnsupportedOperationException("Error: Open in WebView and solve the Antirobot!") + val infoElement = document.select("div.page__grid").first() val manga = SManga.create() - manga.author = infoElement.select(".fullstory__infoSection:eq(1) > .fullstory__infoSectionContent").text() - manga.genre = infoElement.select(".fullstory__infoSection:eq(2) > .fullstory__infoSectionContent").text() - .split(",").plusElement("Комикс").joinToString { it.trim() } + manga.author = infoElement.select(".page__list li:eq(1)").text() + manga.genre = infoElement.select(".page__tags a").joinToString { it.text() } + manga.status = parseStatus(infoElement.select(".page__list li:eq(2)").text()) - manga.status = parseStatus(infoElement.select(".fullstory__infoSection:eq(3) > .fullstory__infoSectionContent").text()) + manga.description = infoElement.select(".page__text ").text() - val text = infoElement.select("*").text() - if (!text.contains("Добавить описание на комикс")) { - val fromRemove = "Отслеживать" - val toRemove = "Читать комикс" - val desc = text.removeRange(0, text.indexOf(fromRemove) + fromRemove.length) - manga.description = desc.removeRange(desc.indexOf(toRemove) + toRemove.length, desc.length) - } - - val src = infoElement.select("img").attr("src") - if (src.contains(baseUrl)) { - manga.thumbnail_url = src + val src = infoElement.select(".img-wide img").attr("src") + if (src.contains(baseUrl.substringAfter("://"))) { + manga.thumbnail_url = "http:" + src } else { manga.thumbnail_url = baseUrl + src } @@ -172,7 +181,8 @@ class ComX : ParsedHttpSource() { private fun parseStatus(element: String): Int = when { element.contains("Продолжается") || - element.contains(" из ") -> SManga.ONGOING + element.contains(" из ") || + element.contains("Онгоинг") -> SManga.ONGOING element.contains("Заверш") || element.contains("Лимитка") || element.contains("Ван шот") || @@ -184,8 +194,8 @@ class ComX : ParsedHttpSource() { override fun chapterListSelector() = throw NotImplementedError("Unused") override fun chapterListParse(response: Response): List { - val document = response.asJsoup() + if (document.html().contains("Sorry, your request has been denied.")) throw UnsupportedOperationException("Error: Open in WebView and solve the Antirobot!") val dataStr = document .toString() .substringAfter("window.__DATA__ = ") @@ -248,7 +258,7 @@ class ComX : ParsedHttpSource() { override fun imageRequest(page: Page): Request { return GET(page.imageUrl!!, headers) } - + /** private class CheckFilter(name: String, val id: String) : Filter.CheckBox(name) private class TypeList(types: List) : Filter.Group("Тип выпуска", types) @@ -256,95 +266,95 @@ class ComX : ParsedHttpSource() { private class GenreList(genres: List) : Filter.Group("Жанры", genres) override fun getFilterList() = FilterList( - TypeList(getTypeList()), - PubList(getPubList()), - GenreList(getGenreList()), + TypeList(getTypeList()), + PubList(getPubList()), + GenreList(getGenreList()), ) private fun getTypeList() = listOf( - CheckFilter("Лимитка", "1"), - CheckFilter("Ван шот", "2"), - CheckFilter("Графический Роман", "3"), - CheckFilter("Онгоинг", "4"), + CheckFilter("Лимитка", "1"), + CheckFilter("Ван шот", "2"), + CheckFilter("Графический Роман", "3"), + CheckFilter("Онгоинг", "4"), ) private fun getPubList() = listOf( - CheckFilter("Marvel", "2"), - CheckFilter("DC Comics", "14"), - CheckFilter("Dark Horse", "7"), - CheckFilter("IDW Publishing", "6"), - CheckFilter("Image", "4"), - CheckFilter("Vertigo", "8"), - CheckFilter("Dynamite Entertainment", "10"), - CheckFilter("Wildstorm", "5"), - CheckFilter("Avatar Press", "11"), - CheckFilter("Boom! Studios", "12"), - CheckFilter("Top Cow", "9"), - CheckFilter("Oni Press", "13"), - CheckFilter("Valiant", "15"), - CheckFilter("Icon Comics", "16"), - CheckFilter("Manga", "3"), - CheckFilter("Manhua", "45"), - CheckFilter("Manhwa", "44"), - CheckFilter("Разные комиксы", "18") + CheckFilter("Marvel", "2"), + CheckFilter("DC Comics", "14"), + CheckFilter("Dark Horse", "7"), + CheckFilter("IDW Publishing", "6"), + CheckFilter("Image", "4"), + CheckFilter("Vertigo", "8"), + CheckFilter("Dynamite Entertainment", "10"), + CheckFilter("Wildstorm", "5"), + CheckFilter("Avatar Press", "11"), + CheckFilter("Boom! Studios", "12"), + CheckFilter("Top Cow", "9"), + CheckFilter("Oni Press", "13"), + CheckFilter("Valiant", "15"), + CheckFilter("Icon Comics", "16"), + CheckFilter("Manga", "3"), + CheckFilter("Manhua", "45"), + CheckFilter("Manhwa", "44"), + CheckFilter("Разные комиксы", "18") ) private fun getGenreList() = listOf( - CheckFilter("Sci-Fi", "2"), - CheckFilter("Антиутопия", "3"), - CheckFilter("Апокалипсис", "4"), - CheckFilter("Боевик", "5"), - CheckFilter("Боевые искусства", "6"), - CheckFilter("Вампиры", "7"), - CheckFilter("Вестерн", "8"), - CheckFilter("Военный", "9"), - CheckFilter("Детектив", "10"), - CheckFilter("Драма", "11"), - CheckFilter("Зомби", "12"), - CheckFilter("Игры", "13"), - CheckFilter("Исекай", "14"), - CheckFilter("Исторический", "15"), - CheckFilter("Киберпанк", "16"), - CheckFilter("Комедия", "17"), - CheckFilter("Космоопера", "18"), - CheckFilter("Космос", "19"), - CheckFilter("Криминал", "20"), - CheckFilter("МелоДрама", "21"), - CheckFilter("Мистика", "22"), - CheckFilter("Научная Фантастика", "23"), - CheckFilter("Неотвратимость", "24"), - CheckFilter("Нуар", "25"), - CheckFilter("Паника", "26"), - CheckFilter("Пародия", "27"), - CheckFilter("Повседневность", "28"), - CheckFilter("Постапокалиптика", "29"), - CheckFilter("ПредательСредиНас", "30"), - CheckFilter("Приключения", "31"), - CheckFilter("Путешествия во времени", "32"), - CheckFilter("Сверхъестественное", "33"), - CheckFilter("Слэшер", "34"), - CheckFilter("Смерть", "35"), - CheckFilter("Супергерои", "36"), - CheckFilter("Супергероика", "37"), - CheckFilter("Сёнен", "38"), - CheckFilter("Тревога", "39"), - CheckFilter("Триллер", "40"), - CheckFilter("Ужасы", "41"), - CheckFilter("Фантасмагория", "42"), - CheckFilter("Фантастика", "43"), - CheckFilter("Фэнтези", "44"), - CheckFilter("Экшен", "45"), - CheckFilter("Экшн", "46"), - CheckFilter("Эротика", "47"), - CheckFilter("сэйнэн", "66"), - CheckFilter("сёдзё", "67"), - CheckFilter("сёнэн", "68"), - CheckFilter("сёнэн-ай", "69"), - CheckFilter("трагедия", "70"), - CheckFilter("фэнтези", "73"), - CheckFilter("школа", "74"), - CheckFilter("этти", "76"), - CheckFilter("яой", "77"), + CheckFilter("Sci-Fi", "2"), + CheckFilter("Антиутопия", "3"), + CheckFilter("Апокалипсис", "4"), + CheckFilter("Боевик", "5"), + CheckFilter("Боевые искусства", "6"), + CheckFilter("Вампиры", "7"), + CheckFilter("Вестерн", "8"), + CheckFilter("Военный", "9"), + CheckFilter("Детектив", "10"), + CheckFilter("Драма", "11"), + CheckFilter("Зомби", "12"), + CheckFilter("Игры", "13"), + CheckFilter("Исекай", "14"), + CheckFilter("Исторический", "15"), + CheckFilter("Киберпанк", "16"), + CheckFilter("Комедия", "17"), + CheckFilter("Космоопера", "18"), + CheckFilter("Космос", "19"), + CheckFilter("Криминал", "20"), + CheckFilter("МелоДрама", "21"), + CheckFilter("Мистика", "22"), + CheckFilter("Научная Фантастика", "23"), + CheckFilter("Неотвратимость", "24"), + CheckFilter("Нуар", "25"), + CheckFilter("Паника", "26"), + CheckFilter("Пародия", "27"), + CheckFilter("Повседневность", "28"), + CheckFilter("Постапокалиптика", "29"), + CheckFilter("ПредательСредиНас", "30"), + CheckFilter("Приключения", "31"), + CheckFilter("Путешествия во времени", "32"), + CheckFilter("Сверхъестественное", "33"), + CheckFilter("Слэшер", "34"), + CheckFilter("Смерть", "35"), + CheckFilter("Супергерои", "36"), + CheckFilter("Супергероика", "37"), + CheckFilter("Сёнен", "38"), + CheckFilter("Тревога", "39"), + CheckFilter("Триллер", "40"), + CheckFilter("Ужасы", "41"), + CheckFilter("Фантасмагория", "42"), + CheckFilter("Фантастика", "43"), + CheckFilter("Фэнтези", "44"), + CheckFilter("Экшен", "45"), + CheckFilter("Экшн", "46"), + CheckFilter("Эротика", "47"), + CheckFilter("сэйнэн", "66"), + CheckFilter("сёдзё", "67"), + CheckFilter("сёнэн", "68"), + CheckFilter("сёнэн-ай", "69"), + CheckFilter("трагедия", "70"), + CheckFilter("фэнтези", "73"), + CheckFilter("школа", "74"), + CheckFilter("этти", "76"), + CheckFilter("яой", "77"), - ) + )**/ }