Asura Scans: support high quality chapter images (#6657)

* Asura Scans: support high quality chapter images

* Only rewrite chapter images, add fallback if broken - explained in ext settings
This commit is contained in:
Vetle Ledaal 2024-12-19 12:45:29 +01:00 committed by Draff
parent 0382073769
commit f03fd3c5f7
No known key found for this signature in database
GPG Key ID: E8A89F3211677653
2 changed files with 56 additions and 2 deletions

View File

@ -1,7 +1,7 @@
ext {
extName = 'Asura Scans'
extClass = '.AsuraScans'
extVersionCode = 44
extVersionCode = 45
}
apply from: "$rootDir/common.gradle"

View File

@ -17,6 +17,8 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
@ -66,9 +68,35 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
private val json: Json by injectLazy()
override val client = network.cloudflareClient.newBuilder()
.addInterceptor(::forceHighQualityInterceptor)
.rateLimit(1, 3)
.build()
private var failedHighQuality = false
private fun forceHighQualityInterceptor(chain: Interceptor.Chain): Response {
val request = chain.request()
if (preferences.forceHighQuality() && !failedHighQuality && request.url.fragment == "pageListParse") {
OPTIMIZED_IMAGE_PATH_REGEX.find(request.url.encodedPath)?.also { match ->
val (id, page) = match.destructured
val newUrl = request.url.newBuilder()
.encodedPath("/storage/media/$id/$page.webp")
.build()
val response = chain.proceed(request.newBuilder().url(newUrl).build())
if (response.code != 404) {
return response
} else {
failedHighQuality = true
response.close()
}
}
}
return chain.proceed(request)
}
override fun headersBuilder() = super.headersBuilder()
.add("Referer", "$baseUrl/")
@ -272,7 +300,16 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
.joinToString("") { it.data().substringAfter("\"").substringBeforeLast("\"") }
val pagesData = PAGES_REGEX.find(scriptData)?.groupValues?.get(1) ?: throw Exception("Failed to find chapter pages")
val pageList = json.decodeFromString<List<PageDto>>(pagesData.unescape()).sortedBy { it.order }
return pageList.mapIndexed { i, page -> Page(i, imageUrl = page.url) }
return pageList.mapIndexed { i, page ->
val newUrl = page.url.toHttpUrlOrNull()?.run {
newBuilder()
.fragment("pageListParse")
.build()
.toString()
}
Page(i, imageUrl = newUrl ?: page.url)
}
}
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
@ -296,6 +333,16 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
summary = "Hides the chapters that require a subscription to view"
setDefaultValue(true)
}.let(screen::addPreference)
SwitchPreferenceCompat(screen.context).apply {
key = PREF_FORCE_HIGH_QUALITY
title = "Force high quality chapter images"
summary = "Attempt to use high quality chapter images.\nWill increase bandwidth by ~50%."
if (failedHighQuality) {
summary = "$summary\n*DISABLED* because of missing high quality images."
}
setDefaultValue(false)
}.let(screen::addPreference)
}
private var SharedPreferences.slugMap: MutableMap<String, String>
@ -318,6 +365,10 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
PREF_HIDE_PREMIUM_CHAPTERS,
true,
)
private fun SharedPreferences.forceHighQuality(): Boolean = getBoolean(
PREF_FORCE_HIGH_QUALITY,
false,
)
private fun String.toPermSlugIfNeeded(): String {
if (!preferences.dynamicUrl()) return this
@ -337,8 +388,11 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
private val CLEAN_DATE_REGEX = """(\d+)(st|nd|rd|th)""".toRegex()
private val OLD_FORMAT_MANGA_REGEX = """^/manga/(\d+-)?([^/]+)/?$""".toRegex()
private val OLD_FORMAT_CHAPTER_REGEX = """^/(\d+-)?[^/]*-chapter-\d+(-\d+)*/?$""".toRegex()
private val OPTIMIZED_IMAGE_PATH_REGEX = """^/storage/media/(\d+)/conversions/(.*)-optimized\.webp$""".toRegex()
private const val PREF_SLUG_MAP = "pref_slug_map_2"
private const val PREF_DYNAMIC_URL = "pref_dynamic_url"
private const val PREF_HIDE_PREMIUM_CHAPTERS = "pref_hide_premium_chapters"
private const val PREF_FORCE_HIGH_QUALITY = "pref_force_high_quality"
}
}