From d880b30ea92822b446800dbe89acc1ce72b2e75d Mon Sep 17 00:00:00 2001 From: Vladimir Dostoyevskiy <99822064+VDostoyevskiy@users.noreply.github.com> Date: Fri, 29 Dec 2023 12:15:24 +0800 Subject: [PATCH] Move to coil NetworkFetcher (#558) * Move to coil NetworkFetcher * Fixup --------- Co-authored-by: GG Bond --- .../com/hippo/ehviewer/EhApplication.kt | 5 +- .../com/hippo/ehviewer/coil/Extensions.kt | 14 +++++ .../hippo/ehviewer/coil/KtorHttpUriFetcher.kt | 60 ------------------- gradle/libs.versions.toml | 3 +- 4 files changed, 19 insertions(+), 63 deletions(-) delete mode 100644 app/src/main/kotlin/com/hippo/ehviewer/coil/KtorHttpUriFetcher.kt diff --git a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt index bf5d21795..ca32e8ecc 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt @@ -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) } } diff --git a/app/src/main/kotlin/com/hippo/ehviewer/coil/Extensions.kt b/app/src/main/kotlin/com/hippo/ehviewer/coil/Extensions.kt index db8f31367..6667e44be 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/coil/Extensions.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/coil/Extensions.kt @@ -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) diff --git a/app/src/main/kotlin/com/hippo/ehviewer/coil/KtorHttpUriFetcher.kt b/app/src/main/kotlin/com/hippo/ehviewer/coil/KtorHttpUriFetcher.kt deleted file mode 100644 index d806aa7c4..000000000 --- a/app/src/main/kotlin/com/hippo/ehviewer/coil/KtorHttpUriFetcher.kt +++ /dev/null @@ -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) -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4327176a4..49c8913da 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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"]