[RU]ComX adult pages solve captcha (#12219)

* [RU]ComX adult pages solve captcha

* extVersionCode

* LICENSED message

* LICENSED 404

* fix logged-in

* normal/full chapter name

* empty chapter name

* chapter_number & simpleDateFormat companion
This commit is contained in:
Ejan 2022-06-17 07:00:09 +05:00 committed by GitHub
parent a9bd85d728
commit b11102c1bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 19 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'Com-X'
pkgNameSuffix = 'ru.comx'
extClass = '.ComX'
extVersionCode = 19
extVersionCode = 20
}
apply from: "$rootDir/common.gradle"

View File

@ -1,7 +1,9 @@
package eu.kanade.tachiyomi.extension.ru.comx
import android.webkit.CookieManager
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservable
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
@ -14,20 +16,24 @@ import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.float
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
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit
@ -42,11 +48,49 @@ class ComX : ParsedHttpSource() {
override val lang = "ru"
override val supportsLatest = true
private val cookieManager by lazy { CookieManager.getInstance() }
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.rateLimit(3)
.cookieJar(
object : CookieJar {
// Syncs okhttp with WebView cookies, allowing logged-in users do logged-in stuff
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
for (cookie in cookies) {
cookieManager.setCookie(url.toString(), cookie.toString())
}
}
override fun loadForRequest(url: HttpUrl): MutableList<Cookie> {
val cookiesString = cookieManager.getCookie(url.toString())
if (cookiesString != null && cookiesString.isNotEmpty()) {
val cookieHeaders = cookiesString.split("; ").toList()
val cookies = mutableListOf<Cookie>()
for (header in cookieHeaders) {
cookies.add(Cookie.parse(url, header)!!)
}
// Adds age verification cookies to access mature comics
return if (url.toString().contains("/reader/")) cookies.apply {
add(
Cookie.Builder()
.domain(baseUrl.substringAfter("//"))
.path("/")
.name("adult")
.value(
url.toString().substringAfter("/reader/")
.substringBefore("/")
)
.build()
)
} else cookies
} else {
return mutableListOf()
}
}
}
)
.build()
override fun headersBuilder(): Headers.Builder = Headers.Builder()
@ -190,11 +234,11 @@ class ComX : ParsedHttpSource() {
ratingValue > 0.5 -> "✬☆☆☆☆"
else -> "☆☆☆☆☆"
}
val rawAgeStop = if (document.toString().contains("ВНИМАНИЕ! 18+")) "18+" else ""
val manga = SManga.create()
manga.title = infoElement.select(".page__title-original").text().replace(" / ", " | ").split(" | ").first()
manga.author = infoElement.select(".page__list li:contains(Издатель)").text()
manga.genre = infoElement.select(".page__tags a").joinToString { it.text() }
manga.genre = rawAgeStop + ", " + infoElement.select(".page__tags a").joinToString { it.text() }
manga.status = parseStatus(infoElement.select(".page__list li:contains(Статус)").text())
manga.description = infoElement.select(".page__header h1").text().replace(" / ", " | ").split(" | ").first() + "\n" + ratingStar + " " + ratingValue + " (голосов: " + ratingVotes + ")\n" + Jsoup.parse(infoElement.select(".page__text ").first().html().replace("<br>", "REPLACbR")).text().replace("REPLACbR", "\n")
@ -224,8 +268,7 @@ class ComX : ParsedHttpSource() {
override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup()
if (document.toString().contains("ВНИМАНИЕ! 18+") && document.select(".login__title.stretch-free-width.ws-nowrap").first().text().contains("Войти"))
throw Exception("Для просмотра 18+ контента необходима авторизация через WebView")
val dataStr = document
.toString()
.substringAfter("window.__DATA__ = ")
@ -236,30 +279,29 @@ class ComX : ParsedHttpSource() {
val chaptersList = data["chapters"]?.jsonArray
val chapters: List<SChapter>? = chaptersList?.map {
val chapter = SChapter.create()
chapter.name = it.jsonObject["title"]!!.jsonPrimitive.content
chapter.date_upload = parseDate(it.jsonObject["date"]!!.jsonPrimitive.content)
// title_en is full chapter name, no english name
chapter.name = it.jsonObject["title_en"]!!.jsonPrimitive.content
if (chapter.name.isEmpty())
chapter.name = it.jsonObject["title"]!!.jsonPrimitive.content
chapter.date_upload = simpleDateFormat.parse(it.jsonObject["date"]!!.jsonPrimitive.content)?.time ?: 0L
chapter.chapter_number = it.jsonObject["posi"]!!.jsonPrimitive.float
chapter.setUrlWithoutDomain("/readcomix/" + data["news_id"] + "/" + it.jsonObject["id"]!!.jsonPrimitive.content + ".html")
chapter
}
return chapters ?: emptyList()
}
private val simpleDateFormat by lazy { SimpleDateFormat("dd.MM.yyyy", Locale.US) }
private fun parseDate(date: String?): Long {
date ?: return 0L
return try {
simpleDateFormat.parse(date)!!.time
} catch (_: Exception) {
Date().time
}
}
override fun chapterFromElement(element: Element): SChapter =
throw NotImplementedError("Unused")
// Pages
override fun pageListParse(response: Response): List<Page> {
val html = response.body!!.string()
// Comics 18+
if (html.contains("adult__header"))
throw Exception("Комикс 18+ (что-то сломалось)")
val baseImgUrl = "https://img.com-x.life/comix/"
val beginTag = "\"images\":["
@ -280,6 +322,19 @@ class ComX : ParsedHttpSource() {
return pages
}
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
return client.newCall(pageListRequest(chapter))
.asObservable().doOnNext { response ->
if (!response.isSuccessful) {
if (response.code == 404 && response.asJsoup().toString().contains("Выпуск был удален по требованию правообладателя"))
throw Exception("Лицензировано. Возможно может помочь авторизация через WebView") else throw Exception("HTTP error ${response.code}")
}
}
.map { response ->
pageListParse(response)
}
}
override fun pageListParse(document: Document): List<Page> {
throw Exception("Not used")
}
@ -463,4 +518,8 @@ class ComX : ParsedHttpSource() {
CheckFilter("Яой", "120"),
CheckFilter("Ёнкома", "121"),
)
companion object {
private val simpleDateFormat by lazy { SimpleDateFormat("dd.MM.yyyy", Locale.US) }
}
}