Move to coil NetworkFetcher (#558)

* Move to coil NetworkFetcher

* Fixup

---------

Co-authored-by: GG Bond <whatever@tagkong.com>
This commit is contained in:
Vladimir DostoyevskiyandGG Bond authored and GitHub committed 2023-12-29 04:15:24 +00:00
1 parent 0e2ca4e150
commit d880b30ea9
4 files changed
+19 -63

No files matched your search

@@ -29,6 +29,7 @@ import androidx.lifecycle.coroutineScope
import coil3.SingletonImageLoader
import coil3.asCoilImage
import coil3.decode.ImageDecoderDecoder
import coil3.fetch.NetworkFetcher
import coil3.request.crossfade
import coil3.util.DebugLogger
import com.hippo.ehviewer.client.EhCookieStore
@@ -36,7 +37,6 @@ import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.client.data.GalleryDetail
import com.hippo.ehviewer.coil.DownloadThumbInterceptor
import com.hippo.ehviewer.coil.MergeInterceptor
import com.hippo.ehviewer.coil.installKtorHttpUriFetcher
import com.hippo.ehviewer.dailycheck.checkDawn
import com.hippo.ehviewer.dao.SearchDatabase
import com.hippo.ehviewer.download.DownloadManager
@@ -56,6 +56,7 @@ import com.hippo.ehviewer.util.isAtLeastQ
import com.hippo.ehviewer.util.isAtLeastS
import com.hippo.ehviewer.util.isCronetAvailable
import com.hippo.ehviewer.util.resettableLazy
import com.hippo.ehviewer.util.unsafeLazy
import eu.kanade.tachiyomi.network.interceptor.UncaughtExceptionInterceptor
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withUIContext
@@ -181,7 +182,7 @@ class EhApplication : Application(), SingletonImageLoader.Factory {
override fun newImageLoader() = imageLoader {
components {
installKtorHttpUriFetcher()
add(NetworkFetcher.Factory(unsafeLazy { ktorClient }))
if (isAtLeastP) {
add { result, options, _ -> ImageDecoderDecoder(result.source, options, false) }
}
@@ -7,18 +7,31 @@ import coil3.decode.DecodeResult
import coil3.decode.Decoder
import coil3.request.CachePolicy
import coil3.request.ImageRequest
import coil3.request.httpHeaders
import coil3.size.Size
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.client.CHROME_ACCEPT
import com.hippo.ehviewer.client.CHROME_ACCEPT_LANGUAGE
import com.hippo.ehviewer.client.data.GalleryInfo
import com.hippo.ehviewer.client.data.GalleryPreview
import com.hippo.ehviewer.client.data.NormalGalleryPreview
import com.hippo.ehviewer.client.url
import com.hippo.ehviewer.spider.DownloadInfoMagics.encodeMagicRequestOrUrl
import io.ktor.http.HttpHeaders
import io.ktor.http.headers
private val header = headers {
append(HttpHeaders.UserAgent, Settings.userAgent)
append(HttpHeaders.Accept, CHROME_ACCEPT)
append(HttpHeaders.AcceptLanguage, CHROME_ACCEPT_LANGUAGE)
}
fun ImageRequest.Builder.ehUrl(info: GalleryInfo) = apply {
val key = info.thumbKey!!
data(encodeMagicRequestOrUrl(info))
memoryCacheKey(key)
diskCacheKey(key)
httpHeaders(header)
}
fun ImageRequest.Builder.ehPreview(preview: GalleryPreview) = apply {
@@ -26,6 +39,7 @@ fun ImageRequest.Builder.ehPreview(preview: GalleryPreview) = apply {
memoryCacheKey(preview.imageKey)
diskCacheKey(preview.imageKey)
if (preview is NormalGalleryPreview) size(Size.ORIGINAL)
httpHeaders(header)
}
private val stubImage = ColorDrawable(Color.BLACK).asCoilImage(true)
@@ -1,60 +0,0 @@
@file:Suppress("BlockingMethodInNonBlockingContext")
package com.hippo.ehviewer.coil
import android.webkit.MimeTypeMap
import coil3.ComponentRegistry
import coil3.ImageLoader
import coil3.Uri
import coil3.decode.DataSource
import coil3.decode.ImageSource
import coil3.fetch.FetchResult
import coil3.fetch.Fetcher
import coil3.fetch.SourceFetchResult
import coil3.request.Options
import com.hippo.ehviewer.client.ehRequest
import com.hippo.ehviewer.util.copyTo
import io.ktor.client.statement.bodyAsChannel
/**
* A HttpUriFetcher impl use Ktor (Will do jvmheapless IO when backing engine is Cronet)
* cacheHeader is never respected | recorded since thumb is immutable
*/
class KtorHttpUriFetcher(private val data: String, private val options: Options, private val imageLoader: ImageLoader) : Fetcher {
override suspend fun fetch(): FetchResult {
val diskCacheKey = options.diskCacheKey ?: data
val diskCache = requireNotNull(imageLoader.diskCache)
val snapshot = diskCache.openSnapshot(diskCacheKey) ?: run {
val success = ehRequest(data, verbose = false).execute {
diskCache.suspendEdit(diskCacheKey) {
it.bodyAsChannel().copyTo(data.toFile())
}
}
check(success)
// diskcache snapshot MUST exist here
requireNotNull(diskCache.openSnapshot(diskCacheKey))
}
return SourceFetchResult(
source = ImageSource(snapshot.data, diskCache.fileSystem, diskCacheKey, snapshot),
mimeType = getMimeType(data),
dataSource = DataSource.DISK,
)
}
}
fun ComponentRegistry.Builder.installKtorHttpUriFetcher() = add { data: Uri, options, loader ->
if (data.scheme != "http" && data.scheme != "https") return@add null
KtorHttpUriFetcher(data.toString(), options, loader)
}
private fun getMimeType(url: String) = MimeTypeMap.getSingleton().getMimeTypeFromUrl(url)
private fun MimeTypeMap.getMimeTypeFromUrl(url: String?): String? {
if (url.isNullOrBlank()) return null
val extension = url
.substringBeforeLast('#') // Strip the fragment.
.substringBeforeLast('?') // Strip the query.
.substringAfterLast('/') // Get the last path segment.
.substringAfterLast('.', missingDelimiterValue = "") // Get the file extension.
return getMimeTypeFromExtension(extension)
}
+2 -1
View File
@@ -64,6 +64,7 @@ arrow-stack = { module = "io.arrow-kt:arrow-stack", version.ref = "arrow" }
coil-bom = { module = "io.coil-kt.coil3:coil-bom", version.ref = "coil" }
coil-compose = { module = "io.coil-kt.coil3:coil-compose" }
coil-gif = { module = "io.coil-kt.coil3:coil-gif" }
coil-network = { module = "io.coil-kt.coil3:coil-network" }
compose-bom = { module = "dev.chrisbanes.compose:compose-bom", version.ref = "compose-bom" }
# For renovate
@@ -119,7 +120,7 @@ splitties-systemservices = { module = "com.louiscad.splitties:splitties-systemse
[bundles]
androidx-navigation = ["androidx-navigation-compose", "androidx-navigation-ui"]
coil = ["coil-compose", "coil-gif"]
coil = ["coil-compose", "coil-gif", "coil-network"]
compose = ["compose-foundation", "compose-material-icons-extended", "compose-material3", "compose-material3-windowsizeclass", "compose-ui-util"]
cronet = ["cronet-api", "cronet-gms"]
kotlinx-serialization = ["kotlinx-serialization-cbor", "kotlinx-serialization-json", "kotlinx-serialization-json-okio"]