Dynasty: original covers & chapter metadata (#9604)

* original covers & chapter metadata

* use cached cover if new one is same
This commit is contained in:
AwkwardPeak7 2025-07-11 10:20:56 +05:00 committed by Draff
parent ea34656edf
commit aedd777371
Signed by: Draff
GPG Key ID: E8A89F3211677653
5 changed files with 90 additions and 35 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
ext {
extName = 'Dynasty'
extClass = '.DynastyFactory'
extVersionCode = 26
extVersionCode = 27
isNsfw = true
}

View File

@ -74,6 +74,7 @@ class MangaEntry(
class MangaResponse(
val name: String,
val type: String,
val permalink: String,
val tags: List<BrowseTag>,
val cover: String?,
val description: String?,
@ -81,7 +82,15 @@ class MangaResponse(
@Serializable(with = ChapterItemListSerializer::class)
val taggings: List<ChapterItem>,
@SerialName("total_pages") val totalPages: Int = 0,
)
) {
val directory get() = when (type) {
SERIES_TYPE -> SERIES_DIR
ANTHOLOGY_TYPE -> ANTHOLOGIES_DIR
DOUJIN_TYPE -> DOUJINS_DIR
ISSUE_TYPE -> ISSUES_DIR
else -> throw Exception("Unsupported Type for directory: $type")
}
}
@Serializable
sealed class ChapterItem
@ -122,6 +131,7 @@ object ChapterItemListSerializer : JsonTransformingSerializer<List<ChapterItem>>
@Serializable
class ChapterResponse(
val title: String,
val permalink: String,
val tags: List<BrowseTag>,
val pages: List<Page>,
@SerialName("released_on") val releasedOn: String,

View File

@ -50,7 +50,7 @@ open class Dynasty : HttpSource(), ConfigurableSource {
override val client = network.cloudflareClient.newBuilder()
.addInterceptor(::fetchCoverUrlInterceptor)
.addInterceptor(::coverInterceptor)
.rateLimit(1, 2)
.rateLimit(1)
.build()
private val coverClient = network.cloudflareClient
@ -74,7 +74,7 @@ open class Dynasty : HttpSource(), ConfigurableSource {
MangaEntry(
url = "/${tag.directory}/${tag.permalink}",
title = tag.name,
cover = getCoverUrl(tag.directory, tag.permalink),
cover = getCachedCoverUrl(tag.directory, tag.permalink),
).also(entries::add)
// true if an associated series is found
@ -115,7 +115,7 @@ open class Dynasty : HttpSource(), ConfigurableSource {
val entry = MangaEntry(
url = "/$directory/$permalink",
title = permalink.permalinkToTitle(),
cover = getCoverUrl(directory, permalink),
cover = getCachedCoverUrl(directory, permalink),
).toSManga()
return Observable.just(
@ -280,7 +280,7 @@ open class Dynasty : HttpSource(), ConfigurableSource {
val entry = MangaEntry(
url = "/$directory/$permalink",
title = title,
cover = getCoverUrl(directory, permalink),
cover = getCachedCoverUrl(directory, permalink),
)
if (firstEntry == null) {
@ -422,7 +422,29 @@ open class Dynasty : HttpSource(), ConfigurableSource {
.any { publishingStatus.contains(it) } -> SManga.CANCELLED
else -> SManga.UNKNOWN
}
thumbnail_url = data.cover?.let { buildCoverUrl(it) }
// if new cover is same as cached cover, use cached cover
// to avoid making HEAD requests in `getHDCoverUrlIfAvailable`
thumbnail_url = run {
val newCover = data.cover?.let { buildCoverUrl(it) }
val cachedCover = getCachedCoverUrl(data.directory, data.permalink)
if (newCover == null || cachedCover == null) {
newCover?.let { getHDCoverUrlIfAvailable(it) } ?: cachedCover
} else {
val path = cachedCover.toHttpUrl().pathSegments
val tmpSDCover = cachedCover.toHttpUrl().newBuilder().apply {
val file = path.last().substringBeforeLast(".") + ".jpg"
setPathSegment(5, "medium")
setPathSegment(path.size - 1, file)
}.toString()
if (tmpSDCover == newCover) {
cachedCover
} else {
getHDCoverUrlIfAvailable(newCover)
}
}
}
}
}
@ -470,30 +492,15 @@ open class Dynasty : HttpSource(), ConfigurableSource {
}
}
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return if (manga.url.contains("/$CHAPTERS_DIR/")) {
Observable.just(
listOf(
SChapter.create().apply {
url = manga.url
name = "Chapter"
date_upload = dateFormat.tryParse(
manga.description
?.substringAfter("Released:", ""),
)
},
),
)
} else {
super.fetchChapterList(manga)
}
}
override fun chapterListRequest(manga: SManga): Request {
return mangaDetailsRequest(manga)
}
override fun chapterListParse(response: Response): List<SChapter> {
if (response.request.url.pathSegments[0] == CHAPTERS_DIR) {
return listOf(individualChapterParse(response))
}
val data = response.parseAs<MangaResponse>()
val chapters = data.taggings.toMutableList()
@ -542,6 +549,17 @@ open class Dynasty : HttpSource(), ConfigurableSource {
}
}
private fun individualChapterParse(response: Response): SChapter {
val data = response.parseAs<ChapterResponse>()
return SChapter.create().apply {
url = "/$CHAPTERS_DIR/${data.permalink}"
name = "Chapter"
scanlator = data.tags.filter { it.type == "Scanlator" }.joinToString { it.name }
date_upload = dateFormat.tryParse(data.releasedOn)
}
}
override fun getChapterUrl(chapter: SChapter): String {
return baseUrl + chapter.url
}
@ -606,7 +624,7 @@ open class Dynasty : HttpSource(), ConfigurableSource {
.parseAs()
}
private fun getCoverUrl(directory: String?, permalink: String): String? {
private fun getCachedCoverUrl(directory: String?, permalink: String): String? {
directory ?: return null
if (directory == CHAPTERS_DIR) {
@ -619,17 +637,44 @@ open class Dynasty : HttpSource(), ConfigurableSource {
return buildCoverUrl(file)
}
private fun getHDCoverUrlIfAvailable(coverUrl: String): String {
val path = coverUrl.toHttpUrl().pathSegments
if (path.size == 7 && path[5] == "medium") {
listOf("jpg", "png", "jpeg", "webp").forEach { format ->
val newUrl = coverUrl.toHttpUrl().newBuilder().apply {
val file = path.last().substringBeforeLast(".") + ".$format"
setPathSegment(5, "original")
setPathSegment(path.size - 1, file)
}.build()
val request = Request.Builder()
.url(newUrl)
.headers(headers)
.head()
.build()
if (coverClient.newCall(request).execute().isSuccessful) {
return newUrl.toString()
}
}
}
return coverUrl
}
private fun buildCoverUrl(file: String): String {
val path = "$baseUrl$file".toHttpUrl()
.encodedPath
.removePrefix("/")
return baseUrl.toHttpUrl()
.newBuilder()
.addEncodedPathSegments(path)
.fragment(COVER_URL_FRAGMENT)
.build()
.toString()
return baseUrl.toHttpUrl().newBuilder().apply {
if (!path.startsWith("system/")) {
addEncodedPathSegments("system/tag_contents_covers/000")
}
addEncodedPathSegments(path)
fragment(COVER_URL_FRAGMENT)
}.toString()
}
private fun buildChapterCoverFetchUrl(permalink: String): String {