Cache custom covers (close #1492)

This commit is contained in:
Koitharu
2025-07-13 10:04:18 +03:00
parent de1a297338
commit fe3f95d160

View File

@@ -1,23 +1,39 @@
package org.koitharu.kotatsu.settings.override
import android.content.Context
import androidx.core.net.toUri
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withContext
import okio.buffer
import okio.sink
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
import org.koitharu.kotatsu.core.nav.AppRouter
import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.ui.model.MangaOverride
import org.koitharu.kotatsu.core.util.MimeTypes
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.isFileUri
import org.koitharu.kotatsu.core.util.ext.openSource
import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.core.util.ext.toMimeTypeOrNull
import org.koitharu.kotatsu.core.util.ext.toUriOrNull
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.md5
import java.io.File
import javax.inject.Inject
private const val DIR_COVERS = "covers"
@HiltViewModel
class OverrideConfigViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
@ApplicationContext private val context: Context,
private val dataRepository: MangaDataRepository,
) : BaseViewModel() {
@@ -34,9 +50,12 @@ class OverrideConfigViewModel @Inject constructor(
fun save(title: String?) {
launchLoadingJob(Dispatchers.Default) {
val override = checkNotNull(data.value).second.copy(
title = title,
)
val override = checkNotNull(data.value).second.let {
it.copy(
title = title,
coverUrl = it.coverUrl?.cachedFile(),
)
}
dataRepository.setOverride(manga, override)
onSaved.call(Unit)
}
@@ -49,5 +68,33 @@ class OverrideConfigViewModel @Inject constructor(
)
}
private suspend fun String.cachedFile(): String {
val uri = toUriOrNull()
if (uri == null || uri.isFileUri()) {
return this
}
val cacheDir = context.getExternalFilesDir(DIR_COVERS) ?: return this
val cr = context.contentResolver
val ext = cr.getType(uri)?.toMimeTypeOrNull()?.let {
MimeTypes.getExtension(it)
}
val fileName = buildString {
append(this@cachedFile.md5())
if (!ext.isNullOrEmpty()) {
append('.')
append(ext)
}
}
return withContext(Dispatchers.IO) {
val dest = File(cacheDir, fileName)
cr.openSource(uri).use { source ->
dest.sink().buffer().use { sink ->
sink.writeAll(source)
}
}
dest
}.toUri().toString()
}
private fun emptyOverride() = MangaOverride(null, null, null)
}