Fix chapters download in VIZ due to expiration time (#16085)
Fix chapters download due to expiration time.
This commit is contained in:
parent
64edb4a916
commit
a912752ea5
|
@ -6,7 +6,7 @@ ext {
|
|||
extName = 'VIZ Shonen Jump'
|
||||
pkgNameSuffix = 'en.vizshonenjump'
|
||||
extClass = '.VizShonenJump'
|
||||
extVersionCode = 15
|
||||
extVersionCode = 16
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
|
@ -4,32 +4,62 @@ import android.graphics.Bitmap
|
|||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import com.drew.imaging.ImageMetadataReader
|
||||
import com.drew.imaging.jpeg.JpegMetadataReader
|
||||
import com.drew.metadata.exif.ExifSubIFDDirectory
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Headers
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
||||
class VizImageInterceptor : Interceptor {
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val response = chain.proceed(chain.request())
|
||||
|
||||
if (chain.request().url.queryParameter(SIGNATURE) == null) {
|
||||
if (!chain.request().url.toString().contains(IMAGE_URL_ENDPOINT)) {
|
||||
return response
|
||||
}
|
||||
|
||||
val image = response.body.byteStream().decodeImage()
|
||||
val imageUrl = imageUrlParse(response)
|
||||
val imageResponse = chain.proceed(imageRequest(imageUrl))
|
||||
|
||||
val image = imageResponse.body.byteStream().decodeImage()
|
||||
val body = image.toResponseBody(MEDIA_TYPE)
|
||||
return response.newBuilder()
|
||||
|
||||
return imageResponse.newBuilder()
|
||||
.body(body)
|
||||
.header("Content-Type", MEDIA_TYPE.toString())
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun imageUrlParse(response: Response): String {
|
||||
return response.use { json.decodeFromString<VizPageUrlDto>(it.body.string()) }
|
||||
.data?.values?.firstOrNull() ?: throw IOException(FAILED_TO_FETCH_PAGE_URL)
|
||||
}
|
||||
|
||||
private fun imageRequest(url: String): Request {
|
||||
val headers = Headers.Builder()
|
||||
.add("Accept", "*/*")
|
||||
.add("Origin", "https://www.viz.com")
|
||||
.add("Referer", "https://www.viz.com/")
|
||||
.add("User-Agent", VizShonenJump.USER_AGENT)
|
||||
.build()
|
||||
|
||||
return GET(url, headers)
|
||||
}
|
||||
|
||||
private fun InputStream.decodeImage(): ByteArray {
|
||||
// See: https://stackoverflow.com/a/5924132
|
||||
// See: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/2678#issuecomment-645857603
|
||||
|
@ -110,7 +140,7 @@ class VizImageInterceptor : Interceptor {
|
|||
}
|
||||
|
||||
val output = ByteArrayOutputStream()
|
||||
result.compress(Bitmap.CompressFormat.PNG, 100, output)
|
||||
result.compress(Bitmap.CompressFormat.JPEG, 95, output)
|
||||
return output.toByteArray()
|
||||
}
|
||||
|
||||
|
@ -129,7 +159,7 @@ class VizImageInterceptor : Interceptor {
|
|||
}
|
||||
|
||||
private fun ByteArrayInputStream.getImageData(): ImageData? {
|
||||
val metadata = ImageMetadataReader.readMetadata(this)
|
||||
val metadata = JpegMetadataReader.readMetadata(this)
|
||||
|
||||
val sizeDir = metadata.directories.firstOrNull {
|
||||
it.containsTag(ExifSubIFDDirectory.TAG_IMAGE_WIDTH) &&
|
||||
|
@ -155,8 +185,10 @@ class VizImageInterceptor : Interceptor {
|
|||
}
|
||||
|
||||
companion object {
|
||||
private const val SIGNATURE = "Signature"
|
||||
private val MEDIA_TYPE = "image/png".toMediaTypeOrNull()
|
||||
private const val IMAGE_URL_ENDPOINT = "get_manga_url"
|
||||
private val MEDIA_TYPE = "image/jpeg".toMediaType()
|
||||
|
||||
private const val FAILED_TO_FETCH_PAGE_URL = "Something went wrong while trying to fetch page."
|
||||
|
||||
private const val CELL_WIDTH_COUNT = 10
|
||||
private const val CELL_HEIGHT_COUNT = 15
|
||||
|
|
|
@ -228,55 +228,30 @@ class VizShonenJump : ParsedHttpSource() {
|
|||
.addQueryParameter("device_id", "3")
|
||||
.addQueryParameter("manga_id", mangaId)
|
||||
.addQueryParameter("pages", it.toString())
|
||||
.addEncodedQueryParameter("referer", document.location())
|
||||
.toString()
|
||||
|
||||
Page(it, imageUrl)
|
||||
// The image URL is actually fetched in the interceptor to avoid the short
|
||||
// time expiration it have. Using the interceptor will guarantee the requests
|
||||
// always follow the expected order, even when downloading:
|
||||
// imageUrlRequest -> imageRequest -> decryption
|
||||
// By using the url field of page, while downloading through the app it will
|
||||
// do a batch call to get all imageUrl's first and then starts downloading it,
|
||||
// but this takes time and the imageUrl's will be already expired. The reader
|
||||
// doesn't face this issue as it follows the expected request order.
|
||||
Page(it, imageUrl = imageUrl)
|
||||
}
|
||||
}
|
||||
|
||||
override fun imageUrlRequest(page: Page): Request {
|
||||
val url = page.url.toHttpUrlOrNull()!!
|
||||
val referer = url.queryParameter("referer")!!
|
||||
val newUrl = url.newBuilder()
|
||||
.removeAllEncodedQueryParameters("referer")
|
||||
.toString()
|
||||
|
||||
val newHeaders = headersBuilder()
|
||||
.add("Accept", ACCEPT_JSON)
|
||||
.add("X-Client-Login", (loggedIn ?: false).toString())
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.set("Referer", referer)
|
||||
.build()
|
||||
|
||||
return GET(newUrl, newHeaders)
|
||||
}
|
||||
|
||||
override fun imageUrlParse(response: Response): String {
|
||||
val referer = response.request.header("Referer")!!
|
||||
val pageUrl = response.parseAs<VizPageUrlDto>()
|
||||
.data?.values?.firstOrNull() ?: throw Exception(FAILED_TO_FETCH_PAGE_URL)
|
||||
|
||||
return pageUrl.toHttpUrl().newBuilder()
|
||||
.addEncodedQueryParameter("referer", referer)
|
||||
.toString()
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val imageUrl = page.imageUrl!!.toHttpUrlOrNull()!!
|
||||
val referer = imageUrl.queryParameter("referer")!!
|
||||
val newImageUrl = imageUrl.newBuilder()
|
||||
.removeAllEncodedQueryParameters("referer")
|
||||
.toString()
|
||||
|
||||
val newHeaders = headersBuilder()
|
||||
.add("Accept", "*/*")
|
||||
.set("Referer", referer)
|
||||
.add("Accept", ACCEPT_JSON)
|
||||
.add("X-Client-Login", (loggedIn ?: false).toString())
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.build()
|
||||
|
||||
return GET(newImageUrl, newHeaders)
|
||||
return GET(page.imageUrl!!, newHeaders)
|
||||
}
|
||||
|
||||
private fun checkIfIsLoggedIn(chain: Interceptor.Chain? = null) {
|
||||
|
@ -354,8 +329,8 @@ class VizShonenJump : ParsedHttpSource() {
|
|||
|
||||
companion object {
|
||||
private const val ACCEPT_JSON = "application/json, text/javascript, */*; q=0.01"
|
||||
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
|
||||
const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"
|
||||
|
||||
private val DATE_FORMATTER by lazy {
|
||||
SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH)
|
||||
|
@ -364,7 +339,6 @@ class VizShonenJump : ParsedHttpSource() {
|
|||
private const val COUNTRY_NOT_SUPPORTED = "Your country is not supported by the service."
|
||||
private const val SESSION_EXPIRED = "Your session has expired, please log in through WebView again."
|
||||
private const val AUTH_CHECK_FAILED = "Something went wrong in the auth check."
|
||||
private const val FAILED_TO_FETCH_PAGE_URL = "Something went wrong while trying to fetch page."
|
||||
|
||||
private const val REFRESH_LOGIN_LINKS_URL = "account/refresh_login_links"
|
||||
private const val MANGA_AUTH_CHECK_URL = "manga/auth"
|
||||
|
|
Loading…
Reference in New Issue