GigaViewer: Add paginated chapter list parse support (#9911)
* Support for paginated readable products API * Simplify date handling * Chapter status labels * Fix type * Handle null display_open_at value * Additional chapter status label * Mark GigaViewer paginated sources * Implement requested changes from feedback * Remove unused fields * Use tryParse for date handling * Remove label constants * Remove extra whitespace
This commit is contained in:
parent
fd494a9fa7
commit
286ccd2f53
@ -2,4 +2,4 @@ plugins {
|
||||
id("lib-multisrc")
|
||||
}
|
||||
|
||||
baseVersionCode = 6
|
||||
baseVersionCode = 7
|
||||
|
@ -14,6 +14,8 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import keiyoushi.utils.parseAs
|
||||
import keiyoushi.utils.tryParse
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
@ -34,7 +36,6 @@ import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
import kotlin.math.floor
|
||||
@ -44,6 +45,7 @@ abstract class GigaViewer(
|
||||
override val baseUrl: String,
|
||||
override val lang: String,
|
||||
private val cdnUrl: String = "",
|
||||
private val isPaginated: Boolean = false,
|
||||
) : ParsedHttpSource() {
|
||||
|
||||
override val supportsLatest = true
|
||||
@ -134,7 +136,7 @@ abstract class GigaViewer(
|
||||
.attr("data-src")
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
protected fun chapterListParseSinglePage(response: Response): List<SChapter> {
|
||||
val document = response.asJsoup()
|
||||
val aggregateId = document.selectFirst("script.js-valve")!!.attr("data-giga_series")
|
||||
|
||||
@ -180,6 +182,61 @@ abstract class GigaViewer(
|
||||
return chapters
|
||||
}
|
||||
|
||||
protected fun paginatedChaptersRequest(referer: String, aggregateId: String, offset: Int): Response {
|
||||
val headers = headers.newBuilder()
|
||||
.set("Referer", referer)
|
||||
.build()
|
||||
|
||||
val apiUrl = baseUrl.toHttpUrl().newBuilder()
|
||||
.addPathSegment("api")
|
||||
.addPathSegment("viewer")
|
||||
.addPathSegment("pagination_readable_products")
|
||||
.addQueryParameter("type", "episode")
|
||||
.addQueryParameter("aggregate_id", aggregateId)
|
||||
.addQueryParameter("sort_order", "desc")
|
||||
.addQueryParameter("offset", offset.toString())
|
||||
.build()
|
||||
.toString()
|
||||
|
||||
val request = GET(apiUrl, headers)
|
||||
return client.newCall(request).execute()
|
||||
}
|
||||
|
||||
protected fun chapterListParsePaginated(response: Response): List<SChapter> {
|
||||
val document = response.asJsoup()
|
||||
val referer = response.request.url.toString()
|
||||
val aggregateId = document.selectFirst("script.js-valve")!!.attr("data-giga_series")
|
||||
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
|
||||
var offset = 0
|
||||
|
||||
// repeat until the offset is too large to return any chapters, resulting in an empty list
|
||||
while (true) {
|
||||
// make request
|
||||
val result = paginatedChaptersRequest(referer, aggregateId, offset)
|
||||
val resultData = result.parseAs<List<GigaViewerPaginationReadableProduct>>()
|
||||
if (resultData.isEmpty()) {
|
||||
break
|
||||
}
|
||||
resultData.mapTo(chapters) { element ->
|
||||
element.toSChapter(chapterListMode, publisher)
|
||||
}
|
||||
// increase offset
|
||||
offset += resultData.size
|
||||
}
|
||||
|
||||
return chapters
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
return if (isPaginated) {
|
||||
chapterListParsePaginated(response)
|
||||
} else {
|
||||
chapterListParseSinglePage(response)
|
||||
}
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = "li.episode"
|
||||
|
||||
protected open val chapterListMode = CHAPTER_LIST_PAID
|
||||
@ -195,9 +252,7 @@ abstract class GigaViewer(
|
||||
} else if (chapterListMode == CHAPTER_LIST_LOCKED && element.hasClass("private")) {
|
||||
name = LOCK + name
|
||||
}
|
||||
date_upload = info.selectFirst("span.series-episode-list-date")
|
||||
?.text().orEmpty()
|
||||
.toDate()
|
||||
date_upload = DATE_PARSER_SIMPLE.tryParse(info.selectFirst("span.series-episode-list-date")?.text().orEmpty())
|
||||
scanlator = publisher
|
||||
setUrlWithoutDomain(if (info.tagName() == "a") info.attr("href") else mangaUrl)
|
||||
}
|
||||
@ -314,14 +369,7 @@ abstract class GigaViewer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.toDate(): Long {
|
||||
return runCatching { DATE_PARSER.parse(this)?.time }
|
||||
.getOrNull() ?: 0L
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DATE_PARSER by lazy { SimpleDateFormat("yyyy/MM/dd", Locale.ENGLISH) }
|
||||
|
||||
private const val DIVIDE_NUM = 4
|
||||
private const val MULTIPLE = 8
|
||||
private val jpegMediaType = "image/jpeg".toMediaType()
|
||||
@ -329,7 +377,7 @@ abstract class GigaViewer(
|
||||
const val CHAPTER_LIST_PAID = 0
|
||||
const val CHAPTER_LIST_LOCKED = 1
|
||||
|
||||
private const val YEN_BANKNOTE = "💴 "
|
||||
private const val LOCK = "🔒 "
|
||||
const val YEN_BANKNOTE = "💴 "
|
||||
const val LOCK = "🔒 "
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,14 @@
|
||||
package eu.kanade.tachiyomi.multisrc.gigaviewer
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.gigaviewer.GigaViewer.Companion.CHAPTER_LIST_LOCKED
|
||||
import eu.kanade.tachiyomi.multisrc.gigaviewer.GigaViewer.Companion.CHAPTER_LIST_PAID
|
||||
import eu.kanade.tachiyomi.multisrc.gigaviewer.GigaViewer.Companion.LOCK
|
||||
import eu.kanade.tachiyomi.multisrc.gigaviewer.GigaViewer.Companion.YEN_BANKNOTE
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import keiyoushi.utils.tryParse
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
@Serializable
|
||||
data class GigaViewerEpisodeDto(
|
||||
@ -24,3 +32,31 @@ data class GigaViewerPage(
|
||||
val type: String = "",
|
||||
val width: Int = 0,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class GigaViewerPaginationReadableProduct(
|
||||
private val display_open_at: String?,
|
||||
private val readable_product_id: String = "",
|
||||
private val status: GigaViewerPaginationReadableProductStatus?,
|
||||
private val title: String = "",
|
||||
) {
|
||||
fun toSChapter(chapterListMode: Int, publisher: String) = SChapter.create().apply {
|
||||
name = title
|
||||
if (chapterListMode == CHAPTER_LIST_PAID && status?.label != "is_free") {
|
||||
name = YEN_BANKNOTE + name
|
||||
} else if (chapterListMode == CHAPTER_LIST_LOCKED && status?.label == "unpublished") {
|
||||
name = LOCK + name
|
||||
}
|
||||
date_upload = DATE_PARSER_COMPLEX.tryParse(display_open_at)
|
||||
scanlator = publisher
|
||||
url = "/episode/$readable_product_id"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class GigaViewerPaginationReadableProductStatus(
|
||||
val label: String?, // is_free, is_rentable, is_purchasable, unpublished
|
||||
)
|
||||
|
||||
val DATE_PARSER_SIMPLE = SimpleDateFormat("yyyy/MM/dd", Locale.ENGLISH)
|
||||
val DATE_PARSER_COMPLEX = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH)
|
||||
|
@ -10,6 +10,7 @@ class ComicDays : GigaViewer(
|
||||
"https://comic-days.com",
|
||||
"ja",
|
||||
"https://cdn-img.comic-days.com/public/page",
|
||||
isPaginated = true,
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
|
@ -10,6 +10,7 @@ class ComicGardo : GigaViewer(
|
||||
"https://comic-gardo.com",
|
||||
"ja",
|
||||
"https://cdn-img.comic-gardo.com/public/page",
|
||||
isPaginated = true,
|
||||
) {
|
||||
|
||||
override val supportsLatest: Boolean = false
|
||||
|
@ -12,6 +12,7 @@ class Comiplex : GigaViewer(
|
||||
"https://viewer.heros-web.com",
|
||||
"ja",
|
||||
"https://cdn-img.viewer.heros-web.com/public/page",
|
||||
isPaginated = true,
|
||||
) {
|
||||
|
||||
override val supportsLatest: Boolean = false
|
||||
|
@ -12,6 +12,7 @@ class KurageBunch : GigaViewer(
|
||||
"https://kuragebunch.com",
|
||||
"ja",
|
||||
"https://cdn-img.kuragebunch.com",
|
||||
isPaginated = true,
|
||||
) {
|
||||
|
||||
override val supportsLatest: Boolean = false
|
||||
|
@ -10,6 +10,7 @@ class MagComi : GigaViewer(
|
||||
"https://magcomi.com",
|
||||
"ja",
|
||||
"https://cdn-img.magcomi.com/public/page",
|
||||
isPaginated = true,
|
||||
) {
|
||||
|
||||
override val supportsLatest: Boolean = false
|
||||
|
@ -8,6 +8,7 @@ class ShonenJumpPlus : GigaViewer(
|
||||
"https://shonenjumpplus.com",
|
||||
"ja",
|
||||
"https://cdn-ak-img.shonenjumpplus.com",
|
||||
isPaginated = true,
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
|
@ -10,6 +10,7 @@ class SundayWebEvery : GigaViewer(
|
||||
"https://www.sunday-webry.com",
|
||||
"ja",
|
||||
"https://cdn-img.www.sunday-webry.com/public/page",
|
||||
isPaginated = true,
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
|
@ -10,6 +10,7 @@ class TonariNoYoungJump : GigaViewer(
|
||||
"https://tonarinoyj.jp",
|
||||
"ja",
|
||||
"https://cdn-img.tonarinoyj.jp/public/page",
|
||||
isPaginated = true,
|
||||
) {
|
||||
|
||||
override val supportsLatest: Boolean = false
|
||||
|
Loading…
x
Reference in New Issue
Block a user