diff --git a/src/en/mangataro/build.gradle b/src/en/mangataro/build.gradle index fdb07cf98..e26ab20ec 100644 --- a/src/en/mangataro/build.gradle +++ b/src/en/mangataro/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'MangaTaro' extClass = '.MangaTaro' - extVersionCode = 5 + extVersionCode = 6 isNsfw = false } diff --git a/src/en/mangataro/src/eu/kanade/tachiyomi/extension/en/mangataro/Dto.kt b/src/en/mangataro/src/eu/kanade/tachiyomi/extension/en/mangataro/Dto.kt index a66f5ffca..d97dbd8dc 100644 --- a/src/en/mangataro/src/eu/kanade/tachiyomi/extension/en/mangataro/Dto.kt +++ b/src/en/mangataro/src/eu/kanade/tachiyomi/extension/en/mangataro/Dto.kt @@ -112,3 +112,19 @@ class Thumbnail( class Rendered( val rendered: String, ) + +@Serializable +class ChapterList( + val chapters: List, +) + +@Serializable +class Chapter( + val url: String, + val chapter: String, + val title: String? = null, + val date: String, + @SerialName("group_name") + val groupName: String? = null, + val language: String, +) diff --git a/src/en/mangataro/src/eu/kanade/tachiyomi/extension/en/mangataro/MangaTaro.kt b/src/en/mangataro/src/eu/kanade/tachiyomi/extension/en/mangataro/MangaTaro.kt index bbca52512..e5f69fa7a 100644 --- a/src/en/mangataro/src/eu/kanade/tachiyomi/extension/en/mangataro/MangaTaro.kt +++ b/src/en/mangataro/src/eu/kanade/tachiyomi/extension/en/mangataro/MangaTaro.kt @@ -28,7 +28,12 @@ import org.jsoup.Jsoup import org.jsoup.parser.Parser import rx.Observable import java.lang.UnsupportedOperationException +import java.security.MessageDigest +import java.text.SimpleDateFormat import java.util.Calendar +import java.util.Date +import java.util.Locale +import java.util.TimeZone class MangaTaro : HttpSource() { @@ -232,37 +237,55 @@ class MangaTaro : HttpSource() { } override fun chapterListRequest(manga: SManga): Request { - val (id, slug) = manga.url.parseAs() + val timestamp = System.currentTimeMillis() / 1000 + val token = md5( + "${timestamp}mng_ch_${isoDateFormatter.format(Date())}", + ).substring(0, 16) + val mangaId = manga.url.parseAs().id - return GET("$baseUrl/manga/$slug#$id", headers) + val url = "$baseUrl/auth/manga-chapters".toHttpUrl().newBuilder().apply { + addQueryParameter("manga_id", mangaId) + addQueryParameter("offset", "0") + addQueryParameter("limit", "9999") + addQueryParameter("order", "DESC") + addQueryParameter("_t", token) + addQueryParameter("_ts", timestamp.toString()) + }.build() + + return GET(url, headers) } override fun chapterListParse(response: Response): List { - countViews(response.request.url.fragment!!) + countViews(response.request.url.queryParameter("manga_id")!!) - val document = response.asJsoup() - val placeholders = listOf("", "N/A", "—") + val data = response.parseAs() + + val placeholders = listOf(null, "", "N/A", "—") var hasScanlator = false - val chapters = document.select(".chapter-list a").map { + // currently there is only English chapters on the site, at least from a quick look. + // if they ever have multiple languages, we would need to make this a source factory + val chapters = data.chapters.filter { + it.language == "en" + }.map { SChapter.create().apply { - setUrlWithoutDomain(it.absUrl("href")) - val details = it.select("> div + div > div") + setUrlWithoutDomain(it.url) name = buildString { - append(it.attr("title")) - details[1].text().also { title -> + append("Chapter ") + append(it.chapter) + it.title.also { title -> if (title !in placeholders) { append(": ", title) } } } - it.attr("data-group-name").let { group -> + it.groupName.let { group -> if (group !in placeholders) { scanlator = group hasScanlator = true } } - date_upload = details[3].text().parseRelativeDate() + date_upload = it.date.parseRelativeDate() } } @@ -285,6 +308,16 @@ class MangaTaro : HttpSource() { } } + fun md5(input: String): String { + val md = MessageDigest.getInstance("MD5") + val digest = md.digest(input.toByteArray()) + return digest.joinToString("") { "%02x".format(it) } + } + + private val isoDateFormatter = SimpleDateFormat("yyyyMMddHH", Locale.US).apply { + timeZone = TimeZone.getTimeZone("UTC") + } + private fun String.toSlug() = toHttpUrl().let { url -> val path = url.pathSegments.filter(String::isNotBlank) @@ -301,17 +334,19 @@ class MangaTaro : HttpSource() { ?: return 0L when (unit) { - "h" -> calendar.add(Calendar.HOUR, -amount.toInt()) - "d" -> calendar.add(Calendar.DAY_OF_YEAR, -amount.toInt()) - "w" -> calendar.add(Calendar.WEEK_OF_YEAR, -amount.toInt()) - "mo" -> calendar.add(Calendar.MONTH, -amount.toInt()) - "y" -> calendar.add(Calendar.YEAR, -amount.toInt()) + "second" -> calendar.add(Calendar.SECOND, -amount.toInt()) + "minute" -> calendar.add(Calendar.MINUTE, -amount.toInt()) + "hour" -> calendar.add(Calendar.HOUR, -amount.toInt()) + "day" -> calendar.add(Calendar.DAY_OF_YEAR, -amount.toInt()) + "week" -> calendar.add(Calendar.WEEK_OF_YEAR, -amount.toInt()) + "month" -> calendar.add(Calendar.MONTH, -amount.toInt()) + "year" -> calendar.add(Calendar.YEAR, -amount.toInt()) } return calendar.timeInMillis } - private val relativeDateRegex = Regex("""(\d+)(h|d|w|mo|y) ago""") + private val relativeDateRegex = Regex("""(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago""") private fun countViews(postId: String) { val payload = """{"post_id":"$postId"}"""