Fix pages loading issues
This commit is contained in:
@@ -136,7 +136,7 @@ dependencies {
|
||||
|
||||
implementation 'io.coil-kt:coil-base:2.7.0'
|
||||
implementation 'io.coil-kt:coil-svg:2.7.0'
|
||||
implementation 'com.github.KotatsuApp:subsampling-scale-image-view:e04098de68'
|
||||
implementation 'com.github.KotatsuApp:subsampling-scale-image-view:ac7360c5e3'
|
||||
implementation 'com.github.solkin:disk-lru-cache:1.4'
|
||||
implementation 'io.noties.markwon:core:4.6.2'
|
||||
|
||||
|
||||
@@ -26,8 +26,10 @@ class ProgressResponseBody(
|
||||
override fun contentType(): MediaType? = delegate.contentType()
|
||||
|
||||
override fun source(): BufferedSource {
|
||||
return bufferedSource ?: ProgressSource(delegate.source(), contentLength(), progressState).buffer().also {
|
||||
bufferedSource = it
|
||||
return bufferedSource ?: synchronized(this) {
|
||||
bufferedSource ?: ProgressSource(delegate.source(), contentLength(), progressState).buffer().also {
|
||||
bufferedSource = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,10 +104,9 @@ class MangaPageFetcher(
|
||||
if (!response.isSuccessful) {
|
||||
throw HttpException(response)
|
||||
}
|
||||
val body = response.requireBody()
|
||||
val mimeType = response.mimeType
|
||||
val file = body.use {
|
||||
pagesCache.put(pageUrl, it.source())
|
||||
val file = response.requireBody().use {
|
||||
pagesCache.put(pageUrl, it.source(), mimeType)
|
||||
}
|
||||
SourceResult(
|
||||
source = ImageSource(
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.local.data
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.os.StatFs
|
||||
import android.webkit.MimeTypeMap
|
||||
import com.tomclaw.cache.DiskLruCache
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -15,7 +16,7 @@ import okio.use
|
||||
import org.koitharu.kotatsu.core.exceptions.NoDataReceivedException
|
||||
import org.koitharu.kotatsu.core.util.FileSize
|
||||
import org.koitharu.kotatsu.core.util.ext.compressToPNG
|
||||
import org.koitharu.kotatsu.core.util.ext.longHashCode
|
||||
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.core.util.ext.subdir
|
||||
import org.koitharu.kotatsu.core.util.ext.takeIfReadable
|
||||
@@ -24,6 +25,7 @@ import org.koitharu.kotatsu.core.util.ext.writeAllCancellable
|
||||
import org.koitharu.kotatsu.parsers.util.SuspendLazy
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@@ -50,15 +52,15 @@ class PagesCache @Inject constructor(@ApplicationContext context: Context) {
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
suspend fun get(url: String): File? {
|
||||
suspend fun get(url: String): File? = withContext(Dispatchers.IO) {
|
||||
val cache = lruCache.get()
|
||||
return runInterruptible(Dispatchers.IO) {
|
||||
runInterruptible {
|
||||
cache.get(url)?.takeIfReadable()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun put(url: String, source: Source): File = withContext(Dispatchers.IO) {
|
||||
val file = File(cacheDir.get().parentFile, url.longHashCode().toString())
|
||||
suspend fun put(url: String, source: Source, mimeType: String?): File = withContext(Dispatchers.IO) {
|
||||
val file = createBufferFile(url, mimeType)
|
||||
try {
|
||||
val bytes = file.sink(append = false).buffer().use {
|
||||
it.writeAllCancellable(source)
|
||||
@@ -66,17 +68,23 @@ class PagesCache @Inject constructor(@ApplicationContext context: Context) {
|
||||
if (bytes == 0L) {
|
||||
throw NoDataReceivedException(url)
|
||||
}
|
||||
lruCache.get().put(url, file)
|
||||
val cache = lruCache.get()
|
||||
runInterruptible {
|
||||
cache.put(url, file)
|
||||
}
|
||||
} finally {
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun put(url: String, bitmap: Bitmap): File = withContext(Dispatchers.IO) {
|
||||
val file = File(cacheDir.get().parentFile, url.longHashCode().toString())
|
||||
val file = createBufferFile(url, "image/png")
|
||||
try {
|
||||
bitmap.compressToPNG(file)
|
||||
lruCache.get().put(url, file)
|
||||
val cache = lruCache.get()
|
||||
runInterruptible {
|
||||
cache.put(url, file)
|
||||
}
|
||||
} finally {
|
||||
file.delete()
|
||||
}
|
||||
@@ -90,12 +98,24 @@ class PagesCache @Inject constructor(@ApplicationContext context: Context) {
|
||||
}
|
||||
|
||||
private suspend fun getAvailableSize(): Long = runCatchingCancellable {
|
||||
val statFs = StatFs(cacheDir.get().absolutePath)
|
||||
statFs.availableBytes
|
||||
val dir = cacheDir.get()
|
||||
runInterruptible(Dispatchers.IO) {
|
||||
val statFs = StatFs(dir.absolutePath)
|
||||
statFs.availableBytes
|
||||
}
|
||||
}.onFailure {
|
||||
it.printStackTraceDebug()
|
||||
}.getOrDefault(SIZE_DEFAULT)
|
||||
|
||||
private suspend fun createBufferFile(url: String, mimeType: String?): File {
|
||||
val ext = mimeType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) }
|
||||
?: MimeTypeMap.getFileExtensionFromUrl(url).ifNullOrEmpty { "dat" }
|
||||
val cacheDir = cacheDir.get()
|
||||
val rootDir = checkNotNull(cacheDir.parentFile) { "Cannot get parent for ${cacheDir.absolutePath}" }
|
||||
val name = UUID.randomUUID().toString() + "." + ext
|
||||
return File(rootDir, name)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
val SIZE_MIN
|
||||
|
||||
@@ -3,8 +3,10 @@ package org.koitharu.kotatsu.reader.domain
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.ImageDecoder
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.annotation.AnyThread
|
||||
import androidx.collection.LongSparseArray
|
||||
import androidx.collection.set
|
||||
@@ -56,6 +58,7 @@ import org.koitharu.kotatsu.local.data.isFileUri
|
||||
import org.koitharu.kotatsu.local.data.isZipUri
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.mimeType
|
||||
import org.koitharu.kotatsu.parsers.util.requireBody
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
||||
@@ -149,9 +152,13 @@ class PageLoader @Inject constructor(
|
||||
cache.put(uri.toString(), bitmap).toUri()
|
||||
} else {
|
||||
val file = uri.toFile()
|
||||
context.ensureRamAtLeast(file.length() * 2)
|
||||
runInterruptible(Dispatchers.IO) {
|
||||
checkBitmapNotNull(BitmapFactory.decodeFile(file.absolutePath))
|
||||
context.ensureRamAtLeast(file.length() * 2)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
ImageDecoder.decodeBitmap(ImageDecoder.createSource(file))
|
||||
} else {
|
||||
checkBitmapNotNull(BitmapFactory.decodeFile(file.absolutePath))
|
||||
}
|
||||
}.use { image ->
|
||||
image.compressToPNG(file)
|
||||
}
|
||||
@@ -235,7 +242,7 @@ class PageLoader @Inject constructor(
|
||||
val request = createPageRequest(pageUrl, page.source)
|
||||
imageProxyInterceptor.interceptPageRequest(request, okHttp).ensureSuccess().use { response ->
|
||||
response.requireBody().withProgress(progress).use {
|
||||
cache.put(pageUrl, it.source())
|
||||
cache.put(pageUrl, it.source(), response.mimeType)
|
||||
}
|
||||
}.toUri()
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ class PageHolderDelegate(
|
||||
} catch (ce: CancellationException) {
|
||||
throw ce
|
||||
} catch (e2: Throwable) {
|
||||
e2.printStackTrace()
|
||||
e.addSuppressed(e2)
|
||||
state = State.ERROR
|
||||
callback.onError(e)
|
||||
|
||||
Reference in New Issue
Block a user