[Hitomi.La] Fix cover images (#1795)

master
Naga 11 months ago committed by GitHub
parent 34a1dabae4
commit 30a06b67d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -23,7 +23,9 @@ import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
import java.security.MessageDigest import java.security.MessageDigest
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.EnumSet
import java.util.LinkedList
import java.util.Locale
import kotlin.math.min import kotlin.math.min
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
@ -49,33 +51,32 @@ internal class HitomiLaParser(context: MangaLoaderContext) : LegacyMangaParser(c
) )
private val localeMap: Map<Locale, String> = mapOf( private val localeMap: Map<Locale, String> = mapOf(
Locale("id") to "indonesian", Locale.forLanguageTag("id") to "indonesian",
Locale("jv") to "javanese", Locale.forLanguageTag("jv") to "javanese",
Locale("ca") to "catalan", Locale.forLanguageTag("ca") to "catalan",
Locale("ceb") to "cebuano", Locale.forLanguageTag("ceb") to "cebuano",
Locale("cs") to "czech", Locale.forLanguageTag("cs") to "czech",
Locale("da") to "danish", Locale.forLanguageTag("da") to "danish",
Locale("de") to "german", Locale.forLanguageTag("de") to "german",
Locale("et") to "estonian", Locale.forLanguageTag("et") to "estonian",
Locale.ENGLISH to "english", Locale.ENGLISH to "english",
Locale("es") to "spanish", Locale.forLanguageTag("es") to "spanish",
Locale("eo") to "esperanto", Locale.forLanguageTag("eo") to "esperanto",
Locale("fr") to "french", Locale.forLanguageTag("fr") to "french",
Locale("it") to "italian", Locale.forLanguageTag("it") to "italian",
Locale("hi") to "hindi", Locale.forLanguageTag("hi") to "hindi",
Locale("hu") to "hungarian", Locale.forLanguageTag("hu") to "hungarian",
Locale("pl") to "polish", Locale.forLanguageTag("pl") to "polish",
Locale("pt") to "portuguese", Locale.forLanguageTag("pt") to "portuguese",
Locale("vi") to "vietnamese", Locale.forLanguageTag("vi") to "vietnamese",
Locale("tr") to "turkish", Locale.forLanguageTag("tr") to "turkish",
Locale("ru") to "russian", Locale.forLanguageTag("ru") to "russian",
Locale("uk") to "ukrainian", Locale.forLanguageTag("uk") to "ukrainian",
Locale("ar") to "arabic", Locale.forLanguageTag("ar") to "arabic",
Locale.KOREAN to "korean", Locale.KOREAN to "korean",
Locale.CHINESE to "chinese", Locale.CHINESE to "chinese",
Locale.JAPANESE to "japanese", Locale.JAPANESE to "japanese",
) )
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
@ -553,7 +554,6 @@ internal class HitomiLaParser(context: MangaLoaderContext) : LegacyMangaParser(c
largeCoverUrl = largeCoverUrl =
json.getJSONArray("files").getJSONObject(0).let { json.getJSONArray("files").getJSONObject(0).let {
val hash = it.getString("hash") val hash = it.getString("hash")
val commonId = commonImageId()
val imageId = imageIdFromHash(hash) val imageId = imageIdFromHash(hash)
val subDomain = 'a' + subdomainOffset(imageId) val subDomain = 'a' + subdomainOffset(imageId)
@ -718,32 +718,51 @@ internal class HitomiLaParser(context: MangaLoaderContext) : LegacyMangaParser(c
return hash.replace(Regex("""^.*(..)(.)$"""), "$2/$1") return hash.replace(Regex("""^.*(..)(.)$"""), "$2/$1")
} }
private suspend fun subdomainFromURL(url: String, base: String?): String { // rewrite_tn_paths <-- common.js
var retval = "b" private suspend fun rewriteTnPaths(html: String): String {
val thumbUrlRegex = Regex(
"""(?<protocol>//)(?<host>[a-z0-9.-]+\.(?:hitomi\.la|${Regex.escape(cdnDomain)}))/(?<pathAfterHost>(?:avif|webp)?(?:small)?(?:big|small|medium)tn/[0-9a-f]/[0-9a-f]{2}/[0-9a-f]{64}\.(?:webp|avif|gif|png|jpe?g))""",
)
if (!base.isNullOrBlank()) { var resultHtml = html
retval = base thumbUrlRegex.findAll(html).forEach { matchResult ->
} val originalUrl = matchResult.value
val groups = matchResult.groups
val regex = Regex("""/[0-9a-f]{61}([0-9a-f]{2})([0-9a-f])""") val pathAfterHost = groups["pathAfterHost"]?.value ?: return@forEach
val hashMatch = regex.find(url) ?: return "a" val newTnSubdomain = subdomainFromURL(originalUrl, "tn")
val imageId = hashMatch.groupValues.let { it[2] + it[1] }.toIntOrNull(16) val correctedUrl = "${groups["protocol"]!!.value}$newTnSubdomain.$cdnDomain/$pathAfterHost"
if (imageId != null) { if (originalUrl != correctedUrl) {
retval = ('a' + subdomainOffset(imageId)).toString() + retval resultHtml = resultHtml.replace(originalUrl, correctedUrl)
}
} }
return resultHtml
return retval
} }
// rewrite_tn_paths <-- common.js private suspend fun subdomainFromURL(url: String, base: String?): String {
private suspend fun rewriteTnPaths(html: String): String { val resultSubdomain = base ?: "b"
val tnRegex = Regex("""//tn\.hitomi\.la/[^/]+/[0-9a-f]/[0-9a-f]{2}/[0-9a-f]{64}""")
val url = tnRegex.find(html)?.value ?: return html // This regex extracts the last 3 hex characters from the hash in the URL
val newSubdomain = subdomainFromURL(url, "tn") // The hash is 64 characters, so we look for the 61st character onward
val newUrl = url.replace(Regex("""//..?\.hitomi\.la/"""), "//${getDomain(newSubdomain)}/") val hashRegex = Regex("""/([0-9a-f]{61}[0-9a-f]{3})[./]""")
val fullHashMatch = hashRegex.find(url)
?: // If no hash is found, default to "a" + base (typically "atn")
return "a$resultSubdomain"
val fullHash = fullHashMatch.groupValues[1]
return html.replace(tnRegex, newUrl) val lastThreeChars = fullHash.takeLast(3)
val lastDigit = lastThreeChars.last()
val lastTwoDigits = lastThreeChars.take(2)
val imageId = "$lastDigit$lastTwoDigits".toIntOrNull(16)
return if (imageId != null) {
('a' + subdomainOffset(imageId)).toString() + resultSubdomain
} else {
"a$resultSubdomain"
}
} }
private fun String.toTagTitle(): String { private fun String.toTagTitle(): String {

Loading…
Cancel
Save