Tapas - new chapter list parsing (#3349)
This commit is contained in:
parent
95a779335e
commit
2d3aa436de
|
@ -5,7 +5,7 @@ ext {
|
||||||
appName = 'Tachiyomi: Tapas'
|
appName = 'Tachiyomi: Tapas'
|
||||||
pkgNameSuffix = 'en.tapastic'
|
pkgNameSuffix = 'en.tapastic'
|
||||||
extClass = '.Tapastic'
|
extClass = '.Tapastic'
|
||||||
extVersionCode = 9
|
extVersionCode = 10
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,13 @@ import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.support.v7.preference.ListPreference
|
import android.support.v7.preference.ListPreference
|
||||||
import android.support.v7.preference.PreferenceScreen
|
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.network.GET
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
@ -18,6 +25,7 @@ import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
|
@ -141,71 +149,70 @@ class Tapastic : ConfigurableSource, ParsedHttpSource() {
|
||||||
|
|
||||||
// Details
|
// Details
|
||||||
|
|
||||||
|
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||||
|
return GET(baseUrl + "${manga.url}/info")
|
||||||
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
title = document.select(".desc__title").text().trim()
|
genre = document.select("div.info-detail__row a.genre-btn").joinToString { it.text() }
|
||||||
author = document.select(".tag__author").text().trim()
|
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
|
artist = author
|
||||||
description = document.select(".js-series-description").text().trim()
|
description = document.select("div.row-body span.description__body").text()
|
||||||
genre = document.select("div.info__genre a, div.item__genre a")
|
|
||||||
.joinToString(", ") { it.text() }
|
|
||||||
thumbnail_url = document.select("div.header__thumb img").attr("src")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chapters
|
// 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<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val mangaId = document.select("div.info-body__bottom a").attr("data-id")
|
||||||
val chapters = mutableListOf<SChapter>()
|
val chapters = mutableListOf<SChapter>()
|
||||||
|
|
||||||
fun List<Element>.filterLocked(boolean: Boolean): List<Element> {
|
|
||||||
return if (boolean) this.filterNot { it.select("a").hasClass("js-locked") } else this
|
|
||||||
}
|
|
||||||
|
|
||||||
// recursively build the chapter list
|
// recursively build the chapter list
|
||||||
fun parseChapters(document: Document) {
|
fun parseChapters(page: Int) {
|
||||||
document.select(chapterListSelector())
|
val url = "$baseUrl/series/$mangaId/episodes?page=$page&sort=NEWEST&init_load=0&large=true&last_access=0&"
|
||||||
// filter out future releases
|
val json = gson.fromJson<JsonObject>(client.newCall(GET(url, headers)).execute().body()!!.string())["data"]
|
||||||
.filterNot { it.select("a").hasClass("js-coming-soon") }
|
|
||||||
|
Jsoup.parse(json["body"].string).select(chapterListSelector())
|
||||||
.let { list ->
|
.let { list ->
|
||||||
// show/don't show locked chapters based on user's preferences
|
// show/don't show locked chapters based on user's preferences
|
||||||
if (chapterListPref() == "free") list.filterNot { it.select("a").hasClass("js-have-to-sign") }
|
if (chapterListPref() == "free") list.filterNot { it.isLockedChapter() } else list
|
||||||
else list
|
|
||||||
}
|
}
|
||||||
.map { chapters.add(chapterFromElement(it)) }
|
.map { chapters.add(chapterFromElement(it)) }
|
||||||
|
|
||||||
document.select("a.paging__button--next").firstOrNull()?.let {
|
if (json["pagination"]["has_next"].bool) parseChapters(json["pagination"]["page"].int)
|
||||||
parseChapters(client.newCall(GET(it.attr("abs:href"), headers)).execute().asJsoup())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parseChapters(response.asJsoup())
|
parseChapters(1)
|
||||||
return chapters
|
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 {
|
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||||
val lock = !element.select(".sp-ico-episode-lock, .sp-ico-schedule-white").isNullOrEmpty()
|
val episode = element.select("p.scene").text()
|
||||||
name = if (lock) {
|
val chName = element.select("span.title__body").text()
|
||||||
"\uD83D\uDD12 "
|
name = (if (element.isLockedChapter()) "\uD83D\uDD12 " else "") + "$episode | $chName"
|
||||||
} else {
|
setUrlWithoutDomain(element.attr("href"))
|
||||||
""
|
date_upload = datePattern.find(element.select("p.additional").text())?.value.toDate()
|
||||||
} + 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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseDate(date: String): Long {
|
private fun String?.toDate(): Long {
|
||||||
return SimpleDateFormat("MMM dd, yyyy", Locale.US).parse(date)?.time ?: 0
|
this ?: return 0L
|
||||||
|
return SimpleDateFormat("MMM dd, yyyy", Locale.US).parse(this).time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
|
|
Loading…
Reference in New Issue