PixivComic: Use salt from chapter page (#6561)
This commit is contained in:
parent
3a05d381e5
commit
3ecfb8529c
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Pixiv Comic'
|
extName = 'Pixiv Comic'
|
||||||
extClass = '.PixivComic'
|
extClass = '.PixivComic'
|
||||||
extVersionCode = 2
|
extVersionCode = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -8,8 +8,12 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
@ -39,10 +43,6 @@ class PixivComic : HttpSource() {
|
||||||
randomString()
|
randomString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val timeAndHash by lazy {
|
|
||||||
getTimeAndHash()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val client = network.cloudflareClient.newBuilder()
|
override val client = network.cloudflareClient.newBuilder()
|
||||||
.addInterceptor(ShuffledImageInterceptor(key))
|
.addInterceptor(ShuffledImageInterceptor(key))
|
||||||
.addNetworkInterceptor(::tagInterceptor)
|
.addNetworkInterceptor(::tagInterceptor)
|
||||||
|
@ -244,12 +244,17 @@ class PixivComic : HttpSource() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
|
val doc = client.newCall(GET(getChapterUrl(chapter), headers)).execute().asJsoup()
|
||||||
|
val salt = doc.selectFirst("script#__NEXT_DATA__")!!.data().let {
|
||||||
|
json.decodeFromString<JsonElement>(it).jsonObject["props"]!!.jsonObject["pageProps"]!!
|
||||||
|
.jsonObject["salt"]!!.jsonPrimitive.content
|
||||||
|
}
|
||||||
val url = apiBuilder()
|
val url = apiBuilder()
|
||||||
.addPathSegment("episodes")
|
.addPathSegment("episodes")
|
||||||
.addPathSegment(chapter.url)
|
.addPathSegment(chapter.url)
|
||||||
.addPathSegment("read_v4")
|
.addPathSegment("read_v4")
|
||||||
.build()
|
.build()
|
||||||
|
val timeAndHash = getTimeAndHash(salt)
|
||||||
val header = headers.newBuilder()
|
val header = headers.newBuilder()
|
||||||
.add("X-Client-Time", timeAndHash.first)
|
.add("X-Client-Time", timeAndHash.first)
|
||||||
.add("X-Client-Hash", timeAndHash.second)
|
.add("X-Client-Hash", timeAndHash.second)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.extension.ja.pixivcomic
|
package eu.kanade.tachiyomi.extension.ja.pixivcomic
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
@ -10,8 +11,6 @@ import java.util.Locale
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
private const val TIME_SALT = "M7w5HORvvX-VP4tRj2CFQOQFPocBqLvHTIbhTU36UCo"
|
|
||||||
|
|
||||||
private class NoSuchTagException(message: String) : Exception(message)
|
private class NoSuchTagException(message: String) : Exception(message)
|
||||||
|
|
||||||
internal fun tagInterceptor(chain: Interceptor.Chain): Response {
|
internal fun tagInterceptor(chain: Interceptor.Chain): Response {
|
||||||
|
@ -38,7 +37,7 @@ internal fun randomString(): String {
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
@OptIn(ExperimentalUnsignedTypes::class)
|
||||||
internal fun getTimeAndHash(): Pair<String, String> {
|
internal fun getTimeAndHash(salt: String): Pair<String, String> {
|
||||||
val timeFormatted = if (Build.VERSION.SDK_INT < 24) {
|
val timeFormatted = if (Build.VERSION.SDK_INT < 24) {
|
||||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).format(Date())
|
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).format(Date())
|
||||||
.plus(getCurrentTimeZoneOffsetString())
|
.plus(getCurrentTimeZoneOffsetString())
|
||||||
|
@ -46,7 +45,7 @@ internal fun getTimeAndHash(): Pair<String, String> {
|
||||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH).format(Date())
|
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH).format(Date())
|
||||||
}
|
}
|
||||||
|
|
||||||
val saltedTimeArray = timeFormatted.plus(TIME_SALT).toByteArray()
|
val saltedTimeArray = timeFormatted.plus(salt).toByteArray()
|
||||||
val saltedTimeHash = MessageDigest.getInstance("SHA-256")
|
val saltedTimeHash = MessageDigest.getInstance("SHA-256")
|
||||||
.digest(saltedTimeArray).toUByteArray()
|
.digest(saltedTimeArray).toUByteArray()
|
||||||
val hexadecimalTimeHash = saltedTimeHash.joinToString("") {
|
val hexadecimalTimeHash = saltedTimeHash.joinToString("") {
|
||||||
|
@ -63,6 +62,7 @@ internal fun getTimeAndHash(): Pair<String, String> {
|
||||||
/**
|
/**
|
||||||
* workaround to retrieve time zone offset for android with version lower than 24
|
* workaround to retrieve time zone offset for android with version lower than 24
|
||||||
*/
|
*/
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
private fun getCurrentTimeZoneOffsetString(): String {
|
private fun getCurrentTimeZoneOffsetString(): String {
|
||||||
val timeZone = TimeZone.getDefault()
|
val timeZone = TimeZone.getDefault()
|
||||||
val offsetInMillis = timeZone.rawOffset
|
val offsetInMillis = timeZone.rawOffset
|
||||||
|
|
Loading…
Reference in New Issue