musikr: separate immutable/mutable subclasses
This makes it easier for me to centralize certain DI.
This commit is contained in:
parent
194e6b1574
commit
a2e6bcbb7f
3 changed files with 53 additions and 34 deletions
|
@ -25,14 +25,10 @@ import android.database.Cursor
|
|||
import android.net.Uri
|
||||
import android.os.ParcelFileDescriptor
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.oxycblt.auxio.image.covers.MutableSiloedCovers
|
||||
import org.oxycblt.auxio.image.covers.SiloedCoverId
|
||||
import org.oxycblt.musikr.cover.CoverIdentifier
|
||||
import org.oxycblt.auxio.image.covers.SiloedCovers
|
||||
import org.oxycblt.musikr.cover.ObtainResult
|
||||
|
||||
// AndroidManifest.xml addition
|
||||
|
||||
// ImageProvider.java
|
||||
class CoverProvider : ContentProvider() {
|
||||
override fun onCreate(): Boolean = true
|
||||
|
||||
|
@ -42,8 +38,7 @@ class CoverProvider : ContentProvider() {
|
|||
val id = requireNotNull(uri.lastPathSegment) { "No ID in URI: $uri" }
|
||||
val coverId = requireNotNull(SiloedCoverId.parse(id)) { "Invalid ID: $id" }
|
||||
return runBlocking {
|
||||
val siloedCovers =
|
||||
MutableSiloedCovers.from(requireContext(), coverId.silo, CoverIdentifier.md5())
|
||||
val siloedCovers = SiloedCovers.from(requireContext(), coverId.silo)
|
||||
when (val res = siloedCovers.obtain(coverId.id)) {
|
||||
is ObtainResult.Hit -> res.cover.fd()
|
||||
is ObtainResult.Miss -> null
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Auxio Project
|
||||
* MutableSiloedCovers.kt is part of Auxio.
|
||||
* SiloedCovers.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -25,31 +25,42 @@ import kotlinx.coroutines.withContext
|
|||
import org.oxycblt.musikr.cover.Cover
|
||||
import org.oxycblt.musikr.cover.CoverFormat
|
||||
import org.oxycblt.musikr.cover.CoverIdentifier
|
||||
import org.oxycblt.musikr.cover.Covers
|
||||
import org.oxycblt.musikr.cover.FileCover
|
||||
import org.oxycblt.musikr.cover.FileCovers
|
||||
import org.oxycblt.musikr.cover.MutableCovers
|
||||
import org.oxycblt.musikr.cover.MutableFileCovers
|
||||
import org.oxycblt.musikr.cover.ObtainResult
|
||||
import org.oxycblt.musikr.fs.app.AppFiles
|
||||
|
||||
class MutableSiloedCovers
|
||||
private constructor(
|
||||
private val rootDir: File,
|
||||
private val silo: CoverSilo,
|
||||
private val inner: FileCovers
|
||||
) : MutableCovers {
|
||||
open class SiloedCovers(private val silo: CoverSilo, private val fileCovers: FileCovers) : Covers {
|
||||
override suspend fun obtain(id: String): ObtainResult<SiloedCover> {
|
||||
val coverId = SiloedCoverId.parse(id) ?: return ObtainResult.Miss()
|
||||
if (coverId.silo != silo) return ObtainResult.Miss()
|
||||
return when (val result = inner.obtain(coverId.id)) {
|
||||
return when (val result = fileCovers.obtain(coverId.id)) {
|
||||
is ObtainResult.Hit -> ObtainResult.Hit(SiloedCover(silo, result.cover))
|
||||
is ObtainResult.Miss -> ObtainResult.Miss()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun write(data: ByteArray) = SiloedCover(silo, inner.write(data))
|
||||
companion object {
|
||||
suspend fun from(context: Context, silo: CoverSilo): SiloedCovers {
|
||||
val core = SiloCore.from(context, silo)
|
||||
return SiloedCovers(silo, FileCovers(core.files, core.format))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MutableSiloedCovers
|
||||
private constructor(
|
||||
private val rootDir: File,
|
||||
private val silo: CoverSilo,
|
||||
private val fileCovers: MutableFileCovers
|
||||
) : SiloedCovers(silo, fileCovers), MutableCovers {
|
||||
override suspend fun write(data: ByteArray) = SiloedCover(silo, fileCovers.write(data))
|
||||
|
||||
override suspend fun cleanup(excluding: Collection<Cover>) {
|
||||
inner.cleanup(excluding.filterIsInstance<SiloedCover>().map { it.innerCover })
|
||||
fileCovers.cleanup(excluding.filterIsInstance<SiloedCover>().map { it.innerCover })
|
||||
|
||||
// Destroy old revisions no longer being used.
|
||||
withContext(Dispatchers.IO) {
|
||||
|
@ -62,17 +73,11 @@ private constructor(
|
|||
suspend fun from(
|
||||
context: Context,
|
||||
silo: CoverSilo,
|
||||
identifier: CoverIdentifier
|
||||
coverIdentifier: CoverIdentifier
|
||||
): MutableSiloedCovers {
|
||||
val rootDir: File
|
||||
val revisionDir: File
|
||||
withContext(Dispatchers.IO) {
|
||||
rootDir = context.coversDir()
|
||||
revisionDir = rootDir.resolve(silo.toString()).apply { mkdirs() }
|
||||
}
|
||||
val files = AppFiles.at(revisionDir)
|
||||
val format = CoverFormat.jpeg(silo.params)
|
||||
return MutableSiloedCovers(rootDir, silo, FileCovers(files, format, identifier))
|
||||
val core = SiloCore.from(context, silo)
|
||||
return MutableSiloedCovers(
|
||||
core.rootDir, silo, MutableFileCovers(core.files, core.format, coverIdentifier))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,3 +99,19 @@ data class SiloedCoverId(val silo: CoverSilo, val id: String) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class SiloCore(val rootDir: File, val files: AppFiles, val format: CoverFormat) {
|
||||
companion object {
|
||||
suspend fun from(context: Context, silo: CoverSilo): SiloCore {
|
||||
val rootDir: File
|
||||
val revisionDir: File
|
||||
withContext(Dispatchers.IO) {
|
||||
rootDir = context.coversDir()
|
||||
revisionDir = rootDir.resolve(silo.toString()).apply { mkdirs() }
|
||||
}
|
||||
val files = AppFiles.at(revisionDir)
|
||||
val format = CoverFormat.jpeg(silo.params)
|
||||
return SiloCore(rootDir, files, format)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,11 +22,8 @@ import android.os.ParcelFileDescriptor
|
|||
import org.oxycblt.musikr.fs.app.AppFile
|
||||
import org.oxycblt.musikr.fs.app.AppFiles
|
||||
|
||||
class FileCovers(
|
||||
private val appFiles: AppFiles,
|
||||
private val coverFormat: CoverFormat,
|
||||
private val coverIdentifier: CoverIdentifier,
|
||||
) : Covers, MutableCovers {
|
||||
open class FileCovers(private val appFiles: AppFiles, private val coverFormat: CoverFormat) :
|
||||
Covers {
|
||||
override suspend fun obtain(id: String): ObtainResult<FileCover> {
|
||||
val file = appFiles.find(getFileName(id))
|
||||
return if (file != null) {
|
||||
|
@ -36,6 +33,14 @@ class FileCovers(
|
|||
}
|
||||
}
|
||||
|
||||
protected fun getFileName(id: String) = "$id.${coverFormat.extension}"
|
||||
}
|
||||
|
||||
class MutableFileCovers(
|
||||
private val appFiles: AppFiles,
|
||||
private val coverFormat: CoverFormat,
|
||||
private val coverIdentifier: CoverIdentifier
|
||||
) : FileCovers(appFiles, coverFormat), MutableCovers {
|
||||
override suspend fun write(data: ByteArray): FileCover {
|
||||
val id = coverIdentifier.identify(data)
|
||||
val file = appFiles.write(getFileName(id)) { coverFormat.transcodeInto(data, it) }
|
||||
|
@ -46,8 +51,6 @@ class FileCovers(
|
|||
val used = excluding.mapTo(mutableSetOf()) { getFileName(it.id) }
|
||||
appFiles.deleteWhere { it !in used }
|
||||
}
|
||||
|
||||
private fun getFileName(id: String) = "$id.${coverFormat.extension}"
|
||||
}
|
||||
|
||||
interface FileCover : Cover {
|
||||
|
|
Loading…
Reference in a new issue