2022-10-09 17:14:50 +00:00
|
|
|
package eu.kanade.tachiyomi.extension.pt.sinensis
|
|
|
|
|
2023-01-27 20:07:36 +00:00
|
|
|
import android.util.Base64
|
|
|
|
import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES
|
2022-10-09 17:14:50 +00:00
|
|
|
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
|
|
|
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
2023-01-27 20:07:36 +00:00
|
|
|
import eu.kanade.tachiyomi.source.model.Page
|
2022-10-09 17:14:50 +00:00
|
|
|
import eu.kanade.tachiyomi.source.model.SChapter
|
|
|
|
import eu.kanade.tachiyomi.source.model.SManga
|
2023-01-27 20:07:36 +00:00
|
|
|
import kotlinx.serialization.decodeFromString
|
|
|
|
import kotlinx.serialization.json.jsonArray
|
|
|
|
import kotlinx.serialization.json.jsonPrimitive
|
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
2022-10-09 17:14:50 +00:00
|
|
|
import okhttp3.OkHttpClient
|
2023-01-27 20:07:36 +00:00
|
|
|
import org.jsoup.nodes.Document
|
2022-10-09 17:14:50 +00:00
|
|
|
import org.jsoup.nodes.Element
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.util.Locale
|
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
|
|
|
|
class SinensisScan : Madara(
|
|
|
|
"Sinensis Scan",
|
|
|
|
"https://sinensisscans.com",
|
|
|
|
"pt-BR",
|
|
|
|
SimpleDateFormat("dd/MM/yyyy", Locale("pt", "BR"))
|
|
|
|
) {
|
|
|
|
|
|
|
|
// Name changed from Sinensis to Sinensis Scan
|
|
|
|
override val id: Long = 3891513807564817914
|
|
|
|
|
|
|
|
override val client: OkHttpClient = super.client.newBuilder()
|
|
|
|
.rateLimit(1, 2, TimeUnit.SECONDS)
|
|
|
|
.build()
|
|
|
|
|
|
|
|
override fun popularMangaFromElement(element: Element): SManga {
|
|
|
|
return super.popularMangaFromElement(element).apply {
|
2023-01-27 20:07:36 +00:00
|
|
|
setUrlWithoutDomain(url.removeBadPath("manga"))
|
2022-10-09 17:14:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun searchMangaFromElement(element: Element): SManga {
|
|
|
|
return super.searchMangaFromElement(element).apply {
|
2023-01-27 20:07:36 +00:00
|
|
|
setUrlWithoutDomain(url.removeBadPath("manga"))
|
2022-10-09 17:14:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun chapterFromElement(element: Element): SChapter {
|
|
|
|
return super.chapterFromElement(element).apply {
|
2023-01-27 20:07:36 +00:00
|
|
|
setUrlWithoutDomain(url.removeBadPath("manga"))
|
2022-10-09 17:14:50 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-27 20:07:36 +00:00
|
|
|
|
|
|
|
override fun pageListParse(document: Document): List<Page> {
|
|
|
|
val chapterProtector = document.selectFirst("script#chapter-protector-data")?.data()
|
|
|
|
?: return super.pageListParse(document)
|
|
|
|
|
|
|
|
val password = chapterProtector
|
|
|
|
.substringAfter("wpmangaprotectornonce='")
|
|
|
|
.substringBefore("';")
|
|
|
|
val chapterData = chapterProtector
|
|
|
|
.substringAfter("chapter_data='")
|
|
|
|
.substringBefore("';")
|
|
|
|
.replace("\\/", "/")
|
|
|
|
.let { json.decodeFromString<Map<String, String>>(it) }
|
|
|
|
|
|
|
|
val unsaltedCipherText = Base64.decode(chapterData["ct"]!!, Base64.DEFAULT)
|
|
|
|
val salt = chapterData["s"]!!.decodeHex()
|
|
|
|
val cipherText = SALTED + salt + unsaltedCipherText
|
|
|
|
|
|
|
|
val rawImageArray = CryptoAES.decrypt(Base64.encodeToString(cipherText, Base64.DEFAULT), password)
|
|
|
|
val imageArrayString = json.parseToJsonElement(rawImageArray).jsonPrimitive.content
|
|
|
|
val imageArray = json.parseToJsonElement(imageArrayString).jsonArray
|
|
|
|
|
|
|
|
return imageArray.mapIndexed { i, jsonElement ->
|
|
|
|
Page(i, document.location(), jsonElement.jsonPrimitive.content)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun String.decodeHex(): ByteArray {
|
|
|
|
check(length % 2 == 0) { "Must have an even length" }
|
|
|
|
|
|
|
|
return chunked(2)
|
|
|
|
.map { it.toInt(16).toByte() }
|
|
|
|
.toByteArray()
|
|
|
|
}
|
|
|
|
|
|
|
|
private fun String.removeBadPath(expectedFirstPath: String): String {
|
|
|
|
val fullUrl = if (contains(baseUrl)) this else (baseUrl + this)
|
|
|
|
val url = fullUrl.toHttpUrl()
|
|
|
|
|
|
|
|
if (url.pathSegments.firstOrNull() != expectedFirstPath) {
|
|
|
|
return url.newBuilder().removePathSegment(0).toString()
|
|
|
|
}
|
|
|
|
|
|
|
|
return url.toString()
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
val SALTED = "Salted__".toByteArray(Charsets.UTF_8)
|
|
|
|
}
|
2022-10-09 17:14:50 +00:00
|
|
|
}
|