Maybe fix the JPEG EXIF parsing in VIZ (#16096)
* Maybe fix the JPEG EXIF parsing in VIZ. * Handle the common HTTP 403 case while getting the image.
This commit is contained in:
parent
42abcb20b9
commit
5c6d6a8201
|
@ -6,7 +6,7 @@ ext {
|
||||||
extName = 'VIZ Shonen Jump'
|
extName = 'VIZ Shonen Jump'
|
||||||
pkgNameSuffix = 'en.vizshonenjump'
|
pkgNameSuffix = 'en.vizshonenjump'
|
||||||
extClass = '.VizShonenJump'
|
extClass = '.VizShonenJump'
|
||||||
extVersionCode = 16
|
extVersionCode = 17
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import com.drew.imaging.jpeg.JpegMetadataReader
|
import com.drew.imaging.ImageMetadataReader
|
||||||
import com.drew.metadata.exif.ExifSubIFDDirectory
|
import com.drew.metadata.exif.ExifSubIFDDirectory
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
|
@ -14,12 +14,12 @@ import okhttp3.Interceptor
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import okhttp3.ResponseBody
|
||||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class VizImageInterceptor : Interceptor {
|
class VizImageInterceptor : Interceptor {
|
||||||
|
|
||||||
|
@ -35,12 +35,15 @@ class VizImageInterceptor : Interceptor {
|
||||||
val imageUrl = imageUrlParse(response)
|
val imageUrl = imageUrlParse(response)
|
||||||
val imageResponse = chain.proceed(imageRequest(imageUrl))
|
val imageResponse = chain.proceed(imageRequest(imageUrl))
|
||||||
|
|
||||||
val image = imageResponse.body.byteStream().decodeImage()
|
if (!imageResponse.isSuccessful) {
|
||||||
val body = image.toResponseBody(MEDIA_TYPE)
|
imageResponse.close()
|
||||||
|
throw IOException(FAILED_TO_FETCH_PAGE_URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
val imageBody = imageResponse.decodeImage()
|
||||||
|
|
||||||
return imageResponse.newBuilder()
|
return imageResponse.newBuilder()
|
||||||
.body(body)
|
.body(imageBody)
|
||||||
.header("Content-Type", MEDIA_TYPE.toString())
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,17 +63,18 @@ class VizImageInterceptor : Interceptor {
|
||||||
return GET(url, headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun InputStream.decodeImage(): ByteArray {
|
private fun Response.decodeImage(): ResponseBody {
|
||||||
// See: https://stackoverflow.com/a/5924132
|
// See: https://stackoverflow.com/a/5924132
|
||||||
// See: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/2678#issuecomment-645857603
|
// See: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/2678#issuecomment-645857603
|
||||||
val byteOutputStream = ByteArrayOutputStream()
|
val byteOutputStream = ByteArrayOutputStream()
|
||||||
copyTo(byteOutputStream)
|
.apply { body.byteStream().copyTo(this) }
|
||||||
|
val contentType = headers["Content-Type"]?.toMediaType()
|
||||||
|
|
||||||
val byteInputStreamForImage = ByteArrayInputStream(byteOutputStream.toByteArray())
|
val byteInputStreamForImage = ByteArrayInputStream(byteOutputStream.toByteArray())
|
||||||
val byteInputStreamForMetadata = ByteArrayInputStream(byteOutputStream.toByteArray())
|
val byteInputStreamForMetadata = ByteArrayInputStream(byteOutputStream.toByteArray())
|
||||||
|
|
||||||
val imageData = byteInputStreamForMetadata.getImageData()
|
val imageData = byteInputStreamForMetadata.getImageData().getOrNull()
|
||||||
?: return byteOutputStream.toByteArray()
|
?: return byteOutputStream.toByteArray().toResponseBody(contentType)
|
||||||
|
|
||||||
val input = BitmapFactory.decodeStream(byteInputStreamForImage)
|
val input = BitmapFactory.decodeStream(byteInputStreamForImage)
|
||||||
val width = input.width
|
val width = input.width
|
||||||
|
@ -139,9 +143,10 @@ class VizImageInterceptor : Interceptor {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val output = ByteArrayOutputStream()
|
return ByteArrayOutputStream()
|
||||||
result.compress(Bitmap.CompressFormat.JPEG, 95, output)
|
.apply { result.compress(Bitmap.CompressFormat.JPEG, 95, this) }
|
||||||
return output.toByteArray()
|
.toByteArray()
|
||||||
|
.toResponseBody(JPEG_MEDIA_TYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Canvas.drawImage(
|
private fun Canvas.drawImage(
|
||||||
|
@ -158,8 +163,13 @@ class VizImageInterceptor : Interceptor {
|
||||||
drawBitmap(from, srcRect, dstRect, null)
|
drawBitmap(from, srcRect, dstRect, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ByteArrayInputStream.getImageData(): ImageData? {
|
private fun ByteArrayInputStream.getImageData(): Result<ImageData?> = runCatching {
|
||||||
val metadata = JpegMetadataReader.readMetadata(this)
|
val metadata = ImageMetadataReader.readMetadata(this)
|
||||||
|
|
||||||
|
val keyDir = metadata.directories
|
||||||
|
.firstOrNull { it.containsTag(ExifSubIFDDirectory.TAG_IMAGE_UNIQUE_ID) }
|
||||||
|
val metaUniqueId = keyDir?.getString(ExifSubIFDDirectory.TAG_IMAGE_UNIQUE_ID)
|
||||||
|
?: return@runCatching null
|
||||||
|
|
||||||
val sizeDir = metadata.directories.firstOrNull {
|
val sizeDir = metadata.directories.firstOrNull {
|
||||||
it.containsTag(ExifSubIFDDirectory.TAG_IMAGE_WIDTH) &&
|
it.containsTag(ExifSubIFDDirectory.TAG_IMAGE_WIDTH) &&
|
||||||
|
@ -168,13 +178,7 @@ class VizImageInterceptor : Interceptor {
|
||||||
val metaWidth = sizeDir?.getInt(ExifSubIFDDirectory.TAG_IMAGE_WIDTH) ?: COMMON_WIDTH
|
val metaWidth = sizeDir?.getInt(ExifSubIFDDirectory.TAG_IMAGE_WIDTH) ?: COMMON_WIDTH
|
||||||
val metaHeight = sizeDir?.getInt(ExifSubIFDDirectory.TAG_IMAGE_HEIGHT) ?: COMMON_HEIGHT
|
val metaHeight = sizeDir?.getInt(ExifSubIFDDirectory.TAG_IMAGE_HEIGHT) ?: COMMON_HEIGHT
|
||||||
|
|
||||||
val keyDir = metadata.directories.firstOrNull {
|
ImageData(metaWidth, metaHeight, metaUniqueId)
|
||||||
it.containsTag(ExifSubIFDDirectory.TAG_IMAGE_UNIQUE_ID)
|
|
||||||
}
|
|
||||||
val metaUniqueId = keyDir?.getString(ExifSubIFDDirectory.TAG_IMAGE_UNIQUE_ID)
|
|
||||||
?: return null
|
|
||||||
|
|
||||||
return ImageData(metaWidth, metaHeight, metaUniqueId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class ImageData(val width: Int, val height: Int, val uniqueId: String) {
|
private data class ImageData(val width: Int, val height: Int, val uniqueId: String) {
|
||||||
|
@ -186,9 +190,9 @@ class VizImageInterceptor : Interceptor {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val IMAGE_URL_ENDPOINT = "get_manga_url"
|
private const val IMAGE_URL_ENDPOINT = "get_manga_url"
|
||||||
private val MEDIA_TYPE = "image/jpeg".toMediaType()
|
private val JPEG_MEDIA_TYPE = "image/jpeg".toMediaType()
|
||||||
|
|
||||||
private const val FAILED_TO_FETCH_PAGE_URL = "Something went wrong while trying to fetch page."
|
private const val FAILED_TO_FETCH_PAGE_URL = "Something went wrong while trying to fetch the page."
|
||||||
|
|
||||||
private const val CELL_WIDTH_COUNT = 10
|
private const val CELL_WIDTH_COUNT = 10
|
||||||
private const val CELL_HEIGHT_COUNT = 15
|
private const val CELL_HEIGHT_COUNT = 15
|
||||||
|
|
Loading…
Reference in New Issue