diff --git a/src/es/tumangaonline/build.gradle b/src/es/tumangaonline/build.gradle index 162b5109a..8b411a27e 100755 --- a/src/es/tumangaonline/build.gradle +++ b/src/es/tumangaonline/build.gradle @@ -5,7 +5,7 @@ ext { appName = 'Tachiyomi: TuMangaOnline' pkgNameSuffix = 'es.tumangaonline' extClass = '.TuMangaOnline' - extVersionCode = 12 + extVersionCode = 13 libVersion = '1.2' } 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 e42ed4035..983c5541e 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 @@ -4,8 +4,6 @@ import android.app.Application import android.content.SharedPreferences import android.support.v7.preference.ListPreference import android.support.v7.preference.PreferenceScreen -import com.github.salomonbrys.kotson.string -import com.google.gson.JsonParser import okhttp3.* import java.util.* import org.jsoup.nodes.Element @@ -17,7 +15,6 @@ import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor -import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.ConfigurableSource import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -41,25 +38,27 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() { .retryOnConnectionFailure(true) .followRedirects(true) .build()!! + + private val userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0" 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", userAgent) .add("Referer", "$baseUrl/") .add("Cache-mode", "no-cache") } - private fun getBuilder(url: String): String { - val req = Request.Builder() - .headers(headersBuilder().add("Referer", "$baseUrl/library/manga/").build()) + private fun getBuilder(url: String, headers: Headers, formBody: FormBody): String { + val req = Request.Builder() + .headers(headers) .url(url) + .post(formBody) .build() - return client.newCall(req) - .execute() - .request() - .url() - .toString() + return client.newCall(req) + .execute() + .body()!! + .string() } private val preferences: SharedPreferences by lazy { @@ -83,8 +82,8 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() { thumbnail_url = it.select("style").toString().substringAfter("('").substringBeforeLast("')") } } - - override fun latestUpdatesParse(response: Response): MangasPage { + + override fun latestUpdatesParse(response: Response): MangasPage { val document = response.asJsoup() val mangas = document.select(latestUpdatesSelector()) .distinctBy { it.select("div.thumbnail-title > h4.text-truncate").text().trim() } @@ -196,12 +195,17 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() { override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() + private val scriptselector = "addEventListener" + override fun chapterListParse(response: Response): List { val document = response.asJsoup() + val chapterurl = response.request().url().toString() + val script = document.select("script:containsData($scriptselector)").html() + val chapteridselector = script.substringAfter("getAttribute(\"").substringBefore("\"") // One-shot if (document.select("div.chapters").isEmpty()) { - return document.select(oneShotChapterListSelector()).map { oneShotChapterFromElement(it) } + return document.select(oneShotChapterListSelector()).map { oneShotChapterFromElement(it, chapterurl, chapteridselector) } } // Regular list of chapters @@ -212,10 +216,10 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() { val scanelement = chapelement.select("ul.chapter-list > li") val dupselect = getduppref()!! if (dupselect=="one") { - scanelement.first { chapters.add(regularChapterFromElement(it, chaptername, chapternumber)) } + scanelement.first { chapters.add(regularChapterFromElement(it, chaptername, chapternumber, chapterurl, chapteridselector)) } } else { - scanelement.forEach { chapters.add(regularChapterFromElement(it, chaptername, chapternumber)) } + scanelement.forEach { chapters.add(regularChapterFromElement(it, chaptername, chapternumber, chapterurl, chapteridselector)) } } } return chapters @@ -226,8 +230,9 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() { private fun oneShotChapterListSelector() = "div.chapter-list-element > ul.list-group li.list-group-item" - private fun oneShotChapterFromElement(element: Element) = SChapter.create().apply { - setUrlWithoutDomain(element.select("div.row > .text-right > a").attr("href")) + private fun oneShotChapterFromElement(element: Element, chapterurl: String, chapteridselector: String) = SChapter.create().apply { + val button = element.select("div.row > .text-right > [$chapteridselector]") //button + url = "$chapterurl#${button.attr(chapteridselector)}" name = "One Shot" scanlator = element.select("div.col-md-6.text-truncate")?.text() date_upload = element.select("span.badge.badge-primary.p-2").first()?.text()?.let { parseChapterDate(it) } ?: 0 @@ -235,8 +240,9 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() { private fun regularChapterListSelector() = "div.chapters > ul.list-group li.p-0.list-group-item" - private fun regularChapterFromElement(element: Element, chname: String, number: Float) = SChapter.create().apply { - setUrlWithoutDomain(element.select("div.row > .text-right > a").attr("href")) + private fun regularChapterFromElement(element: Element, chname: String, number: Float, chapterurl: String, chapteridselector: String) = SChapter.create().apply { + val button = element.select("div.row > .text-right > [$chapteridselector]") //button + url = "$chapterurl#${button.attr(chapteridselector)}" name = chname chapter_number = number scanlator = element.select("div.col-md-6.text-truncate")?.text() @@ -246,30 +252,46 @@ class TuMangaOnline : ConfigurableSource, 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).substringBeforeLast("/") + "/cascade" + val (chapterURL, chapterID) = chapter.url.split("#") + val response = client.newCall(GET(chapterURL, headers)).execute() + val document = response.asJsoup() + val csrfToken = document.select("meta[name=csrf-token]").attr("content") + val script = document.select("script:containsData($scriptselector)").html() + val functionID = script.substringAfter("addEventListener").substringAfter("{").substringBefore("(").trim().removePrefix("_") + val function = script.substringAfter("function _$functionID(").substringBefore("});") + val goto = function.substringAfter("url: '").substringBefore("'") + val paramChapter = function.substringAfter("data").substringBefore("\":_").substringAfterLast("\"") + val getHeaders = headersBuilder() + .add("User-Agent", userAgent) + .add("Referer", chapterURL) + .add("Content-Type","application/x-www-form-urlencoded; charset=UTF-8") + .add("X-CSRF-TOKEN",csrfToken) + .add("X-Requested-With","XMLHttpRequest") + .add(functionID,functionID) + .build() + + val formBody = FormBody.Builder() + .add(paramChapter, chapterID) + .build() + + val url = getBuilder(goto,getHeaders,formBody).substringBeforeLast("/") + "/cascade" // Get /cascade instead of /paginate to get all pages at once + + val headers = headersBuilder() + .add("User-Agent", userAgent) + .add("Referer", chapterURL) + .build() + return GET(url, headers) } - override fun pageListParse(response: Response): List { + override fun pageListParse(response: Response): List = mutableListOf().apply { val body = response.asJsoup() - val imageRoute = body.select("script:containsData(imageRoute)").html().substringAfter("imageRoute = \"").substringBefore(":IMAGE_NAME") - val token = body.select("meta[name=csrf-token]").attr("content") - val base64 = body.select("script:containsData(base64)").html().substringAfter("','").substringBefore("','all');") - val chapterid = body.baseUri().substringAfter("viewer/").substringBefore("/cascade") - val headers = headersBuilder() - .add("Content-Type", "application/json; charset=utf-8") - .add("X-CSRF-TOKEN",token) - .build() - val jsonData = client.newCall(POST("$baseUrl/upload_images/$chapterid/$base64/all", headers)).execute() - val jbody = jsonData.body()!!.string() - val results = JsonParser().parse(jbody).asJsonArray - val pages = mutableListOf() - for (i in 0 until results.size()) { - pages.add(Page(i, "",imageRoute + results[i].string)) + + body.select("div#viewer-container > div.viewer-image-container > img.viewer-image")?.forEach { + add(Page(size, "", it.attr("src"))) } - return pages } override fun pageListParse(document: Document) = throw UnsupportedOperationException("Not used")