Fix TMO error. (#1175)

Fix TMO error #1166
This commit is contained in:
Edgar Mejía 2019-06-09 18:35:47 -06:00 committed by Eugene
parent bc861636fd
commit 5fda10228b
3 changed files with 155 additions and 110 deletions

View File

@ -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!");
}
}

View File

@ -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"

View File

@ -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
}
}