From 2d3aa436de9b04291cbbd33ad4afed0d23789860 Mon Sep 17 00:00:00 2001 From: Mike <51273546+SnakeDoc83@users.noreply.github.com> Date: Fri, 29 May 2020 02:49:52 -0400 Subject: [PATCH] Tapas - new chapter list parsing (#3349) --- src/en/tapastic/build.gradle | 2 +- .../extension/en/tapastic/Tapastic.kt | 87 ++++++++++--------- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/en/tapastic/build.gradle b/src/en/tapastic/build.gradle index c1263e4bc..66e4e1825 100644 --- a/src/en/tapastic/build.gradle +++ b/src/en/tapastic/build.gradle @@ -5,7 +5,7 @@ ext { appName = 'Tachiyomi: Tapas' pkgNameSuffix = 'en.tapastic' extClass = '.Tapastic' - extVersionCode = 9 + extVersionCode = 10 libVersion = '1.2' } diff --git a/src/en/tapastic/src/eu/kanade/tachiyomi/extension/en/tapastic/Tapastic.kt b/src/en/tapastic/src/eu/kanade/tachiyomi/extension/en/tapastic/Tapastic.kt index ad6344a6d..3695c3453 100644 --- a/src/en/tapastic/src/eu/kanade/tachiyomi/extension/en/tapastic/Tapastic.kt +++ b/src/en/tapastic/src/eu/kanade/tachiyomi/extension/en/tapastic/Tapastic.kt @@ -5,6 +5,13 @@ import android.content.SharedPreferences import android.net.Uri import android.support.v7.preference.ListPreference import android.support.v7.preference.PreferenceScreen +import com.github.salomonbrys.kotson.bool +import com.github.salomonbrys.kotson.fromJson +import com.github.salomonbrys.kotson.get +import com.github.salomonbrys.kotson.int +import com.github.salomonbrys.kotson.string +import com.google.gson.Gson +import com.google.gson.JsonObject import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.Filter @@ -18,6 +25,7 @@ import java.text.SimpleDateFormat import java.util.Locale import okhttp3.Request import okhttp3.Response +import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.jsoup.nodes.Element import uy.kohesive.injekt.Injekt @@ -141,71 +149,70 @@ class Tapastic : ConfigurableSource, ParsedHttpSource() { // Details + override fun mangaDetailsRequest(manga: SManga): Request { + return GET(baseUrl + "${manga.url}/info") + } + override fun mangaDetailsParse(document: Document) = SManga.create().apply { - title = document.select(".desc__title").text().trim() - author = document.select(".tag__author").text().trim() + genre = document.select("div.info-detail__row a.genre-btn").joinToString { it.text() } + title = document.select("div.title-wrapper a.title").text() + thumbnail_url = document.select("div.thumb-wrapper img").attr("abs:src") + author = document.select("ul.creator-section a.name").joinToString { it.text() } artist = author - description = document.select(".js-series-description").text().trim() - genre = document.select("div.info__genre a, div.item__genre a") - .joinToString(", ") { it.text() } - thumbnail_url = document.select("div.header__thumb img").attr("src") + description = document.select("div.row-body span.description__body").text() } // Chapters - override fun chapterListRequest(manga: SManga): Request { - return GET(baseUrl + manga.url + "?sort_order=desc", headers) + /** + * Checklist: Paginated chapter lists, locked chapters, future chapters, early-access chapters (app only?), chapter order + */ + + private val gson by lazy { Gson() } + + private fun Element.isLockedChapter(): Boolean { + return this.hasClass("js-have-to-sign") } override fun chapterListParse(response: Response): List { + val document = response.asJsoup() + val mangaId = document.select("div.info-body__bottom a").attr("data-id") val chapters = mutableListOf() - fun List.filterLocked(boolean: Boolean): List { - return if (boolean) this.filterNot { it.select("a").hasClass("js-locked") } else this - } - // recursively build the chapter list - fun parseChapters(document: Document) { - document.select(chapterListSelector()) - // filter out future releases - .filterNot { it.select("a").hasClass("js-coming-soon") } + fun parseChapters(page: Int) { + val url = "$baseUrl/series/$mangaId/episodes?page=$page&sort=NEWEST&init_load=0&large=true&last_access=0&" + val json = gson.fromJson(client.newCall(GET(url, headers)).execute().body()!!.string())["data"] + + Jsoup.parse(json["body"].string).select(chapterListSelector()) .let { list -> // show/don't show locked chapters based on user's preferences - if (chapterListPref() == "free") list.filterNot { it.select("a").hasClass("js-have-to-sign") } - else list + if (chapterListPref() == "free") list.filterNot { it.isLockedChapter() } else list } .map { chapters.add(chapterFromElement(it)) } - document.select("a.paging__button--next").firstOrNull()?.let { - parseChapters(client.newCall(GET(it.attr("abs:href"), headers)).execute().asJsoup()) - } + if (json["pagination"]["has_next"].bool) parseChapters(json["pagination"]["page"].int) } - parseChapters(response.asJsoup()) + parseChapters(1) return chapters } - override fun chapterListSelector() = "li.content__item" + override fun chapterListSelector() = "li a:not(.js-early-access):not(.js-coming-soon)" + + private val datePattern = Regex("""\w\w\w \d\d, \d\d\d\d""") + override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { - val lock = !element.select(".sp-ico-episode-lock, .sp-ico-schedule-white").isNullOrEmpty() - name = if (lock) { - "\uD83D\uDD12 " - } else { - "" - } + element.select(".info__title").text().trim() - - setUrlWithoutDomain(element.select("a").attr("href")) - - chapter_number = - element.select(".info__header").text().substringAfter("Episode") - .substringBefore("Early access").trim().toFloat() - - date_upload = - parseDate(element.select(".info__tag").text().substringAfter(":").substringBefore("•").trim()) + val episode = element.select("p.scene").text() + val chName = element.select("span.title__body").text() + name = (if (element.isLockedChapter()) "\uD83D\uDD12 " else "") + "$episode | $chName" + setUrlWithoutDomain(element.attr("href")) + date_upload = datePattern.find(element.select("p.additional").text())?.value.toDate() } - private fun parseDate(date: String): Long { - return SimpleDateFormat("MMM dd, yyyy", Locale.US).parse(date)?.time ?: 0 + private fun String?.toDate(): Long { + this ?: return 0L + return SimpleDateFormat("MMM dd, yyyy", Locale.US).parse(this).time } // Pages