diff --git a/src/tr/merlinscans/build.gradle b/src/tr/merlinscans/build.gradle index 10e03f916..f492e9959 100644 --- a/src/tr/merlinscans/build.gradle +++ b/src/tr/merlinscans/build.gradle @@ -1,9 +1,9 @@ ext { extName = 'Merlin Scans' extClass = '.MerlinScans' - themePkg = 'madara' + themePkg = 'mangathemesia' baseUrl = 'https://merlinscans.com' - overrideVersionCode = 0 + overrideVersionCode = 1 } apply from: "$rootDir/common.gradle" diff --git a/src/tr/merlinscans/src/eu/kanade/tachiyomi/extension/tr/merlinscans/MerlinScans.kt b/src/tr/merlinscans/src/eu/kanade/tachiyomi/extension/tr/merlinscans/MerlinScans.kt index 078e3e83d..b887043e0 100644 --- a/src/tr/merlinscans/src/eu/kanade/tachiyomi/extension/tr/merlinscans/MerlinScans.kt +++ b/src/tr/merlinscans/src/eu/kanade/tachiyomi/extension/tr/merlinscans/MerlinScans.kt @@ -1,10 +1,12 @@ package eu.kanade.tachiyomi.extension.tr.merlinscans -import eu.kanade.tachiyomi.multisrc.madara.Madara +import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia import java.text.SimpleDateFormat import java.util.Locale -class MerlinScans : Madara("Merlin Scans", "https://merlinscans.com", "tr", SimpleDateFormat("MMMM dd, yyyy", Locale("tr"))) { - - override val useNewChapterEndpoint = true -} +class MerlinScans : MangaThemesia( + "Merlin Scans", + "https://merlinscans.com", + "tr", + dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("tr")), +) diff --git a/src/tr/noxscans/build.gradle b/src/tr/noxscans/build.gradle index f747be95c..0b07752f1 100644 --- a/src/tr/noxscans/build.gradle +++ b/src/tr/noxscans/build.gradle @@ -3,7 +3,7 @@ ext { extClass = '.NoxScans' themePkg = 'mangathemesia' baseUrl = 'https://noxscans.com' - overrideVersionCode = 0 + overrideVersionCode = 1 isNsfw = false } diff --git a/src/tr/noxscans/src/eu/kanade/tachiyomi/extension/tr/noxscans/NoxScans.kt b/src/tr/noxscans/src/eu/kanade/tachiyomi/extension/tr/noxscans/NoxScans.kt index 97a7de071..25d437f85 100644 --- a/src/tr/noxscans/src/eu/kanade/tachiyomi/extension/tr/noxscans/NoxScans.kt +++ b/src/tr/noxscans/src/eu/kanade/tachiyomi/extension/tr/noxscans/NoxScans.kt @@ -1,6 +1,13 @@ package eu.kanade.tachiyomi.extension.tr.noxscans import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import okhttp3.Response +import org.json.JSONObject +import org.jsoup.Jsoup +import org.jsoup.nodes.Document import java.text.SimpleDateFormat import java.util.Locale @@ -9,4 +16,103 @@ class NoxScans : MangaThemesia( "https://noxscans.com", "tr", dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("tr")), -) +) { + companion object { + private val IMAGE_EXTENSIONS = listOf(".webp", ".jpg", ".jpeg", ".png", ".gif") + private const val VERIFICATION_ERROR = + "Bölümü görüntülemek için WebView'de doğrulama yapmanız gerekiyor" + private const val ROBOT_VERIFICATION_ERROR = + "Robot doğrulaması gerekiyor. WebView'de doğrulama yapın" + } + + private fun checkVerification(document: Document, url: String? = null) { + when { + document.select("form[action*=kontrol]").isNotEmpty() -> throw Exception( + VERIFICATION_ERROR, + ) + + url?.contains("/kontrol/") == true -> throw Exception(ROBOT_VERIFICATION_ERROR) + } + } + + override fun chapterListParse(response: Response): List { + return response.use { resp -> + val document = Jsoup.parse(resp.peekBody(Long.MAX_VALUE).string()) + checkVerification(document, resp.request.url.toString()) + super.chapterListParse(resp) + } + } + + override fun pageListParse(document: Document): List { + checkVerification(document, document.location()) + + val scriptContent = document.selectFirst("script:containsData(ts_reader.run)")?.data() + ?: return super.pageListParse(document) + + return try { + parseReaderScript(scriptContent) + } catch (e: Exception) { + super.pageListParse(document) + } + } + + private fun parseReaderScript(scriptContent: String): List { + val jsonStr = scriptContent.substringAfter("ts_reader.run(").substringBefore(");") + val jsonData = JSONObject(jsonStr) + + val serverArrayKey = + findServerArrayKey(jsonData) ?: throw Exception("Server array not found") + val serverArray = jsonData.getJSONArray(serverArrayKey) + val firstServer = serverArray.getJSONObject(0) + + val imageArrayKey = + findImageArrayKey(firstServer) ?: throw Exception("Image array not found") + val imageArray = firstServer.getJSONArray(imageArrayKey) + + return List(imageArray.length()) { i -> + Page(i, "", imageArray.getString(i)) + } + } + + private fun findServerArrayKey(jsonData: JSONObject): String? = + jsonData.keys().asSequence().find { key -> + try { + val value = jsonData.getJSONArray(key) + value.length() > 0 && isValidServerObject(value.getJSONObject(0)) + } catch (e: Exception) { + false + } + } + + private fun isValidServerObject(obj: JSONObject): Boolean = + obj.length() == 2 && obj.keys().asSequence().any { key -> + try { + val arrayValue = obj.getJSONArray(key) + arrayValue.length() > 0 && isImageUrl(arrayValue.getString(0)) + } catch (e: Exception) { + false + } + } + + private fun findImageArrayKey(server: JSONObject): String? = + server.keys().asSequence().find { key -> + try { + val value = server.getJSONArray(key) + value.length() > 0 && isImageUrl(value.getString(0)) + } catch (e: Exception) { + false + } + } + + override fun mangaDetailsParse(response: Response): SManga { + return response.use { resp -> + val document = Jsoup.parse(resp.body.string()) + checkVerification(document, resp.request.url.toString()) + super.mangaDetailsParse(resp) + } + } + + private fun isImageUrl(url: String): Boolean = IMAGE_EXTENSIONS.any { ext -> + url.lowercase().endsWith(ext) && url.contains("/wp-content/uploads/") + } +}