From 5fda10228b086f13a7b669952e996d70ca1cfec7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Edgar=20Mej=C3=ADa?= <edgar13155@gmail.com>
Date: Sun, 9 Jun 2019 18:35:47 -0600
Subject: [PATCH] Fix TMO error. (#1175)

Fix TMO error #1166
---
 .../src/com/squareup/duktape/Duktape.java     |   4 +
 src/es/tumangaonline/build.gradle             |   3 +-
 .../es/tumangaonline/TuMangaOnline.kt         | 258 ++++++++++--------
 3 files changed, 155 insertions(+), 110 deletions(-)

diff --git a/lib/duktape-stub/src/com/squareup/duktape/Duktape.java b/lib/duktape-stub/src/com/squareup/duktape/Duktape.java
index 12bdb0252..e638b4e63 100644
--- a/lib/duktape-stub/src/com/squareup/duktape/Duktape.java
+++ b/lib/duktape-stub/src/com/squareup/duktape/Duktape.java
@@ -23,4 +23,8 @@ public class Duktape implements Closeable {
         throw new RuntimeException("Stub!");
     }
 
+    public synchronized <T> T get(final String name, final Class<T> type) {
+        throw new RuntimeException("Stub!");
+    }
+
 }
\ No newline at end of file
diff --git a/src/es/tumangaonline/build.gradle b/src/es/tumangaonline/build.gradle
index 1e67eb6be..dffb0fde1 100755
--- a/src/es/tumangaonline/build.gradle
+++ b/src/es/tumangaonline/build.gradle
@@ -5,12 +5,13 @@ ext {
     appName = 'Tachiyomi: TuMangaOnline'
     pkgNameSuffix = 'es.tumangaonline'
     extClass = '.TuMangaOnline'
-    extVersionCode = 4
+    extVersionCode = 5
     libVersion = '1.2'
 }
 
 dependencies {
     implementation project(':lib-ratelimit')
+    compileOnly project(':duktape-stub')
 }
 
 apply from: "$rootDir/common.gradle"
diff --git a/src/es/tumangaonline/src/eu/kanade/tachiyomi/extension/es/tumangaonline/TuMangaOnline.kt b/src/es/tumangaonline/src/eu/kanade/tachiyomi/extension/es/tumangaonline/TuMangaOnline.kt
index 1a9d1fcd9..e72432d26 100755
--- a/src/es/tumangaonline/src/eu/kanade/tachiyomi/extension/es/tumangaonline/TuMangaOnline.kt
+++ b/src/es/tumangaonline/src/eu/kanade/tachiyomi/extension/es/tumangaonline/TuMangaOnline.kt
@@ -11,6 +11,7 @@ import org.jsoup.nodes.Element
 import java.text.SimpleDateFormat
 import java.util.*
 import java.util.concurrent.TimeUnit
+import com.squareup.duktape.Duktape
 
 class TuMangaOnline : ParsedHttpSource() {
 
@@ -25,32 +26,32 @@ class TuMangaOnline : ParsedHttpSource() {
     private val rateLimitInterceptor = RateLimitInterceptor(4)
 
     override val client: OkHttpClient = network.cloudflareClient.newBuilder()
-            .addNetworkInterceptor(rateLimitInterceptor)
-            .connectTimeout(1, TimeUnit.MINUTES)
-            .readTimeout(1, TimeUnit.MINUTES)
-            .retryOnConnectionFailure(true)
-            .followRedirects(true)
-            .build()!!
+        .addNetworkInterceptor(rateLimitInterceptor)
+        .connectTimeout(1, TimeUnit.MINUTES)
+        .readTimeout(1, TimeUnit.MINUTES)
+        .retryOnConnectionFailure(true)
+        .followRedirects(true)
+        .build()!!
 
     override fun headersBuilder(): Headers.Builder {
         return Headers.Builder()
-                .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/60")
+            .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/60")
     }
 
     private fun getBuilder(url: String): String {
         val req = Request.Builder()
-                .headers(headersBuilder()
-                        .add("Referer", "$baseUrl/library/manga/")
-                        .add("Cache-mode", "no-cache")
-                        .build())
-                .url(url)
-                .build()
+            .headers(headersBuilder()
+                .add("Referer", "$baseUrl/library/manga/")
+                .add("Cache-mode", "no-cache")
+                .build())
+            .url(url)
+            .build()
 
         return client.newCall(req)
-                .execute()
-                .request()
-                .url()
-                .toString()
+            .execute()
+            .request()
+            .url()
+            .toString()
     }
 
     override fun popularMangaSelector() = "div.element"
@@ -149,8 +150,8 @@ class TuMangaOnline : ParsedHttpSource() {
                 }
                 is GenreList -> {
                     filter.state
-                            .filter { genre -> genre.state }
-                            .forEach { genre -> url.addQueryParameter("genders[]", genre.id) }
+                        .filter { genre -> genre.state }
+                        .forEach { genre -> url.addQueryParameter("genders[]", genre.id) }
                 }
             }
         }
@@ -200,57 +201,92 @@ class TuMangaOnline : ParsedHttpSource() {
     private fun parseChapterDate(date: String): Long = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(date).time
 
     override fun pageListRequest(chapter: SChapter): Request {
-        val url = getBuilder(baseUrl + chapter.url)
+        val url = getBuilder(baseUrl + chapter.url).substringBeforeLast("/") + "/cascade"
 
         // Get /cascade instead of /paginate to get all pages at once
-        return GET(url.substringBeforeLast("/") + "/cascade", headers)
+        return GET(url, headers)
     }
 
-    override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
-        document.select("div#viewer-container > div.viewer-image-container > img.viewer-image")?.forEach {
-            add(Page(size, "", it.attr("src")))
+    override fun pageListParse(response: Response): List<Page> {
+        val pages = mutableListOf<Page>()
+        val body = response.body()!!.string()
+        var images = ""
+        val script = """
+            function chapterInit(data) {
+               pipe = "|";
+               idsR = /img_[^\.^;]+\.src\s*=\s*"([^"]+)/gm;
+               idData = ""
+               do {
+                   m = idsR.exec(data);
+                   if (m) {
+                       idData = idData + pipe + m[1] ;
+                   }
+               } while (m);
+               return idData;
+            }
+        """
+
+        Duktape.create().use {
+            it.evaluate(script)
+
+            val chapterInit = it.get("chapterInit", JSIn::class.java)
+            images = chapterInit.call(true, body)
         }
+
+        images.split("|").forEachIndexed { index, element ->
+            if (element.isNotEmpty()) {
+                pages.add(Page(index, baseUrl, element))
+            }
+        }
+
+        return pages
+    }
+
+    override fun pageListParse(document: Document) = throw UnsupportedOperationException("Not used")
+
+    override fun imageUrlRequest(page: Page): Request {
+        return GET(page.url, headers)
     }
 
     override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used")
 
     private class Types : UriPartFilter("Tipo", arrayOf(
-            Pair("Ver todo", ""),
-            Pair("Manga", "manga"),
-            Pair("Manhua", "manhua"),
-            Pair("Manhwa", "manhwa"),
-            Pair("Novela", "novel"),
-            Pair("One shot", "one_shot"),
-            Pair("Doujinshi", "doujinshi"),
-            Pair("Oel", "oel")
+        Pair("Ver todo", ""),
+        Pair("Manga", "manga"),
+        Pair("Manhua", "manhua"),
+        Pair("Manhwa", "manhwa"),
+        Pair("Novela", "novel"),
+        Pair("One shot", "one_shot"),
+        Pair("Doujinshi", "doujinshi"),
+        Pair("Oel", "oel")
     ))
 
     private class Demography : UriPartFilter("Demografía", arrayOf(
-            Pair("Ver todo", ""),
-            Pair("Seinen", "seinen"),
-            Pair("Shoujo", "shoujo"),
-            Pair("Shounen", "shounen"),
-            Pair("Josei", "josei"),
-            Pair("Kodomo", "kodomo")
+        Pair("Ver todo", ""),
+        Pair("Seinen", "seinen"),
+        Pair("Shoujo", "shoujo"),
+        Pair("Shounen", "shounen"),
+        Pair("Josei", "josei"),
+        Pair("Kodomo", "kodomo")
     ))
 
     private class FilterBy : UriPartFilter("Ordenar por", arrayOf(
-            Pair("Título", "title"),
-            Pair("Autor", "author"),
-            Pair("Compañia", "company")
+        Pair("Título", "title"),
+        Pair("Autor", "author"),
+        Pair("Compañia", "company")
     ))
 
     private class OrderBy : UriPartFilter("Ordenar por", arrayOf(
-            Pair("Me gusta", "likes_count"),
-            Pair("Alfabético", "alphabetically"),
-            Pair("Puntuación", "score"),
-            Pair("Creación", "creation"),
-            Pair("Fecha estreno", "release_date")
+        Pair("Me gusta", "likes_count"),
+        Pair("Alfabético", "alphabetically"),
+        Pair("Puntuación", "score"),
+        Pair("Creación", "creation"),
+        Pair("Fecha estreno", "release_date")
     ))
 
     private class OrderDir : UriPartFilter("Ordenar por", arrayOf(
-            Pair("ASC", "asc"),
-            Pair("DESC", "desc")
+        Pair("ASC", "asc"),
+        Pair("DESC", "desc")
     ))
 
     private class WebcomicFilter : Filter.TriState("Webcomic")
@@ -262,76 +298,80 @@ class TuMangaOnline : ParsedHttpSource() {
     private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Géneros", genres)
 
     override fun getFilterList() = FilterList(
-            Types(),
-            Demography(),
-            Filter.Separator(),
-            FilterBy(),
-            OrderBy(),
-            OrderDir(),
-            Filter.Separator(),
-            WebcomicFilter(),
-            FourKomaFilter(),
-            AmateurFilter(),
-            EroticFilter(),
-            GenreList(getGenreList())
+        Types(),
+        Demography(),
+        Filter.Separator(),
+        FilterBy(),
+        OrderBy(),
+        OrderDir(),
+        Filter.Separator(),
+        WebcomicFilter(),
+        FourKomaFilter(),
+        AmateurFilter(),
+        EroticFilter(),
+        GenreList(getGenreList())
     )
 
     // Array.from(document.querySelectorAll('#books-genders .col-auto .custom-control')).map(a => `Genre("${a.querySelector('label').innerText}", "${a.querySelector('input').value}")`).join(',\n')
     // on https://tumangaonline.me/library
     private fun getGenreList() = listOf(
-            Genre("Acción", "1"),
-            Genre("Aventura", "2"),
-            Genre("Comedia", "3"),
-            Genre("Drama", "4"),
-            Genre("Recuentos de la vida", "5"),
-            Genre("Ecchi", "6"),
-            Genre("Fantasia", "7"),
-            Genre("Magia", "8"),
-            Genre("Sobrenatural", "9"),
-            Genre("Horror", "10"),
-            Genre("Misterio", "11"),
-            Genre("Psicológico", "12"),
-            Genre("Romance", "13"),
-            Genre("Ciencia Ficción", "14"),
-            Genre("Thriller", "15"),
-            Genre("Deporte", "16"),
-            Genre("Girls Love", "17"),
-            Genre("Boys Love", "18"),
-            Genre("Harem", "19"),
-            Genre("Mecha", "20"),
-            Genre("Supervivencia", "21"),
-            Genre("Reencarnación", "22"),
-            Genre("Gore", "23"),
-            Genre("Apocalíptico", "24"),
-            Genre("Tragedia", "25"),
-            Genre("Vida Escolar", "26"),
-            Genre("Historia", "27"),
-            Genre("Militar", "28"),
-            Genre("Policiaco", "29"),
-            Genre("Crimen", "30"),
-            Genre("Superpoderes", "31"),
-            Genre("Vampiros", "32"),
-            Genre("Artes Marciales", "33"),
-            Genre("Samurái", "34"),
-            Genre("Género Bender", "35"),
-            Genre("Realidad Virtual", "36"),
-            Genre("Ciberpunk", "37"),
-            Genre("Musica", "38"),
-            Genre("Parodia", "39"),
-            Genre("Animación", "40"),
-            Genre("Demonios", "41"),
-            Genre("Familia", "42"),
-            Genre("Extranjero", "43"),
-            Genre("Niños", "44"),
-            Genre("Realidad", "45"),
-            Genre("Telenovela", "46"),
-            Genre("Guerra", "47"),
-            Genre("Oeste", "48")
+        Genre("Acción", "1"),
+        Genre("Aventura", "2"),
+        Genre("Comedia", "3"),
+        Genre("Drama", "4"),
+        Genre("Recuentos de la vida", "5"),
+        Genre("Ecchi", "6"),
+        Genre("Fantasia", "7"),
+        Genre("Magia", "8"),
+        Genre("Sobrenatural", "9"),
+        Genre("Horror", "10"),
+        Genre("Misterio", "11"),
+        Genre("Psicológico", "12"),
+        Genre("Romance", "13"),
+        Genre("Ciencia Ficción", "14"),
+        Genre("Thriller", "15"),
+        Genre("Deporte", "16"),
+        Genre("Girls Love", "17"),
+        Genre("Boys Love", "18"),
+        Genre("Harem", "19"),
+        Genre("Mecha", "20"),
+        Genre("Supervivencia", "21"),
+        Genre("Reencarnación", "22"),
+        Genre("Gore", "23"),
+        Genre("Apocalíptico", "24"),
+        Genre("Tragedia", "25"),
+        Genre("Vida Escolar", "26"),
+        Genre("Historia", "27"),
+        Genre("Militar", "28"),
+        Genre("Policiaco", "29"),
+        Genre("Crimen", "30"),
+        Genre("Superpoderes", "31"),
+        Genre("Vampiros", "32"),
+        Genre("Artes Marciales", "33"),
+        Genre("Samurái", "34"),
+        Genre("Género Bender", "35"),
+        Genre("Realidad Virtual", "36"),
+        Genre("Ciberpunk", "37"),
+        Genre("Musica", "38"),
+        Genre("Parodia", "39"),
+        Genre("Animación", "40"),
+        Genre("Demonios", "41"),
+        Genre("Familia", "42"),
+        Genre("Extranjero", "43"),
+        Genre("Niños", "44"),
+        Genre("Realidad", "45"),
+        Genre("Telenovela", "46"),
+        Genre("Guerra", "47"),
+        Genre("Oeste", "48")
     )
 
     private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
-            Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
+        Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
         fun toUriPart() = vals[state].second
     }
 
+    internal interface JSIn {
+        fun call(b: Boolean, data: String): String
+    }
+
 }