LeviatanScans: fix page list (#16649)
* LevitanScans: fix page list Co-authored-by: beerpsi <92439990+beerpiss@users.noreply.github.com> * fix name --------- Co-authored-by: beerpsi <92439990+beerpiss@users.noreply.github.com>
This commit is contained in:
parent
8b15072a4c
commit
bdb8f96eed
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
implementation(project(':lib-cryptoaes'))
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package eu.kanade.tachiyomi.extension.all.leviatanscans
|
||||
|
||||
import android.util.Base64
|
||||
import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
abstract class LeviatanScans(
|
||||
baseUrl: String,
|
||||
lang: String,
|
||||
dateFormat: SimpleDateFormat,
|
||||
) : Madara(
|
||||
"Leviatan Scans",
|
||||
baseUrl,
|
||||
lang,
|
||||
dateFormat,
|
||||
) {
|
||||
override val useNewChapterEndpoint: Boolean = true
|
||||
|
||||
override fun chapterListSelector() = "li.wp-manga-chapter:not(.premium-block)"
|
||||
|
||||
override fun popularMangaFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.popularMangaFromElement(element))
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.latestUpdatesFromElement(element))
|
||||
|
||||
override fun searchMangaFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.searchMangaFromElement(element))
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val chapter = replaceRandomUrlPartInChapter(super.chapterFromElement(element))
|
||||
|
||||
with(element) {
|
||||
selectFirst(chapterUrlSelector)?.let { urlElement ->
|
||||
chapter.name = urlElement.ownText()
|
||||
}
|
||||
}
|
||||
|
||||
return chapter
|
||||
}
|
||||
|
||||
private fun replaceRandomUrlPartInManga(manga: SManga): SManga {
|
||||
val split = manga.url.split("/")
|
||||
manga.url = split.slice(split.indexOf("manga") until split.size).joinToString("/", "/")
|
||||
return manga
|
||||
}
|
||||
|
||||
private fun replaceRandomUrlPartInChapter(chapter: SChapter): SChapter {
|
||||
val split = chapter.url.split("/")
|
||||
chapter.url = baseUrl + split.slice(split.indexOf("manga") until split.size).joinToString("/", "/")
|
||||
return chapter
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val chapterProtector = document.getElementById("chapter-protector-data")?.html()
|
||||
?: return super.pageListParse(document)
|
||||
|
||||
val password = chapterProtector
|
||||
.substringAfter("wpmangaprotectornonce='")
|
||||
.substringBefore("';")
|
||||
val chapterData = json.parseToJsonElement(
|
||||
chapterProtector
|
||||
.substringAfter("chapter_data='")
|
||||
.substringBefore("';")
|
||||
.replace("\\/", "/"),
|
||||
).jsonObject
|
||||
|
||||
val unsaltedCiphertext = Base64.decode(chapterData["ct"]!!.jsonPrimitive.content, Base64.DEFAULT)
|
||||
val salt = chapterData["s"]!!.jsonPrimitive.content.decodeHex()
|
||||
val ciphertext = SALTED + salt + unsaltedCiphertext
|
||||
|
||||
val rawImgArray = CryptoAES.decrypt(Base64.encodeToString(ciphertext, Base64.DEFAULT), password)
|
||||
val imgArrayString = json.parseToJsonElement(rawImgArray).jsonPrimitive.content
|
||||
val imgArray = json.parseToJsonElement(imgArrayString).jsonArray
|
||||
|
||||
return imgArray.mapIndexed { idx, it ->
|
||||
Page(idx, document.location(), it.jsonPrimitive.content)
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/66614516
|
||||
private fun String.decodeHex(): ByteArray {
|
||||
check(length % 2 == 0) { "Must have an even length" }
|
||||
|
||||
return chunked(2)
|
||||
.map { it.toInt(16).toByte() }
|
||||
.toByteArray()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val SALTED = "Salted__".toByteArray(Charsets.UTF_8)
|
||||
}
|
||||
}
|
|
@ -1,13 +1,9 @@
|
|||
package eu.kanade.tachiyomi.extension.all.leviatanscans
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import okhttp3.OkHttpClient
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -18,64 +14,23 @@ class LeviatanScansFactory : SourceFactory {
|
|||
)
|
||||
}
|
||||
|
||||
class LeviatanScansEN : Madara("Leviatan Scans", "https://en.leviatanscans.com", "en", SimpleDateFormat("MMM dd, yyyy", Locale.US)) {
|
||||
|
||||
class LeviatanScansEN : LeviatanScans(
|
||||
"https://en.leviatanscans.com",
|
||||
"en",
|
||||
SimpleDateFormat("MMM dd, yyyy", Locale.US),
|
||||
) {
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2)
|
||||
.build()
|
||||
|
||||
override val useNewChapterEndpoint: Boolean = true
|
||||
|
||||
override fun popularMangaFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.popularMangaFromElement(element))
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.latestUpdatesFromElement(element))
|
||||
|
||||
override fun searchMangaFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.searchMangaFromElement(element))
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val chapter = replaceRandomUrlPartInChapter(super.chapterFromElement(element))
|
||||
|
||||
with(element) {
|
||||
selectFirst(chapterUrlSelector)?.let { urlElement ->
|
||||
chapter.name = urlElement.ownText()
|
||||
}
|
||||
}
|
||||
|
||||
return chapter
|
||||
}
|
||||
override val mangaDetailsSelectorDescription = "div.manga-summary"
|
||||
override val mangaDetailsSelectorAuthor = "div.manga-authors"
|
||||
}
|
||||
|
||||
class LeviatanScansES : LeviatanScans(
|
||||
"https://es.leviatanscans.com",
|
||||
"es",
|
||||
SimpleDateFormat("MMM dd, yy", Locale("es")),
|
||||
) {
|
||||
override val mangaDetailsSelectorStatus = ".post-content_item:contains(Status) .summary-content"
|
||||
}
|
||||
|
||||
class LeviatanScansES : Madara("Leviatan Scans", "https://es.leviatanscans.com", "es", SimpleDateFormat("MMM, yy", Locale("es"))) {
|
||||
override val useNewChapterEndpoint: Boolean = true
|
||||
|
||||
override fun popularMangaFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.popularMangaFromElement(element))
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.latestUpdatesFromElement(element))
|
||||
|
||||
override fun searchMangaFromElement(element: Element) =
|
||||
replaceRandomUrlPartInManga(super.searchMangaFromElement(element))
|
||||
|
||||
override fun chapterFromElement(element: Element) =
|
||||
replaceRandomUrlPartInChapter(super.chapterFromElement(element))
|
||||
|
||||
override val mangaDetailsSelectorStatus = ".post-content_item:contains(Status) .summary-content"
|
||||
}
|
||||
|
||||
fun Madara.replaceRandomUrlPartInManga(manga: SManga): SManga {
|
||||
val split = manga.url.split("/")
|
||||
manga.url = split.slice(split.indexOf("manga") until split.size).joinToString("/", "/")
|
||||
return manga
|
||||
}
|
||||
|
||||
fun Madara.replaceRandomUrlPartInChapter(chapter: SChapter): SChapter {
|
||||
val split = chapter.url.split("/")
|
||||
chapter.url = baseUrl + split.slice(split.indexOf("manga") until split.size).joinToString("/", "/")
|
||||
return chapter
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class MadaraGenerator : ThemeSourceGenerator {
|
|||
|
||||
override val sources = listOf(
|
||||
MultiLang("Atlantis Scan", "https://atlantisscan.com", listOf("es", "pt-BR"), isNsfw = true),
|
||||
MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 13),
|
||||
MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 14),
|
||||
MultiLang("MangaForFree.net", "https://mangaforfree.net", listOf("en", "ko", "all"), isNsfw = true, className = "MangaForFreeFactory", pkgName = "mangaforfree", overrideVersionCode = 1),
|
||||
MultiLang("Manhwa18.cc", "https://manhwa18.cc", listOf("en", "ko", "all"), isNsfw = true, className = "Manhwa18CcFactory", pkgName = "manhwa18cc", overrideVersionCode = 4),
|
||||
MultiLang("Reaper Scans", "https://reaperscans.com", listOf("fr", "tr"), className = "ReaperScansFactory", pkgName = "reaperscans", overrideVersionCode = 12),
|
||||
|
|
Loading…
Reference in New Issue