From 80c97cbea198223ac190942b9a7a65871a456157 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Thu, 26 Dec 2024 19:29:57 -0500 Subject: [PATCH] musikr: separate cover files/format --- .../oxycblt/auxio/music/RevisionedCovers.kt | 2 +- .../org/oxycblt/musikr/cover/CoverFiles.kt | 30 ++++++++----------- .../oxycblt/musikr/cover/CoverIdentifier.kt | 2 +- .../org/oxycblt/musikr/cover/StoredCovers.kt | 25 +++++++++++----- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt b/app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt index 0e37a4491..f2eeafd83 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt @@ -47,7 +47,7 @@ class RevisionedCovers(private val revision: UUID, private val inner: MutableSto context.filesDir.resolve("covers/${revision}").apply { mkdirs() } } return RevisionedCovers( - revision, StoredCovers.from(CoverFiles.at(dir, CoverFormat.jpeg()))) + revision, StoredCovers.from(CoverFiles.at(dir), CoverFormat.jpeg())) } suspend fun cleanup(context: Context, exclude: UUID) = diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt index d71d9f7c4..91a694759 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt @@ -21,20 +21,21 @@ package org.oxycblt.musikr.cover import java.io.File import java.io.IOException import java.io.InputStream +import java.io.OutputStream import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext interface CoverFiles { - suspend fun find(id: String): CoverFile? + suspend fun find(name: String): CoverFile? - suspend fun write(id: String, data: ByteArray): CoverFile? + suspend fun write(name: String, block: suspend (OutputStream) -> Unit): CoverFile? companion object { - suspend fun at(dir: File, format: CoverFormat): CoverFiles { + suspend fun at(dir: File): CoverFiles { withContext(Dispatchers.IO) { check(dir.exists() && dir.isDirectory) } - return CoverFilesImpl(dir, format) + return CoverFilesImpl(dir) } } } @@ -43,8 +44,7 @@ interface CoverFile { suspend fun open(): InputStream? } -private class CoverFilesImpl(private val dir: File, private val coverFormat: CoverFormat) : - CoverFiles { +private class CoverFilesImpl(private val dir: File) : CoverFiles { private val fileMutexes = mutableMapOf() private val mapMutex = Mutex() @@ -52,25 +52,25 @@ private class CoverFilesImpl(private val dir: File, private val coverFormat: Cov return mapMutex.withLock { fileMutexes.getOrPut(file) { Mutex() } } } - override suspend fun find(id: String): CoverFile? = + override suspend fun find(name: String): CoverFile? = withContext(Dispatchers.IO) { try { - File(dir, getTargetFilePath(id)).takeIf { it.exists() }?.let { CoverFileImpl(it) } + File(dir, name).takeIf { it.exists() }?.let { CoverFileImpl(it) } } catch (e: IOException) { null } } - override suspend fun write(id: String, data: ByteArray): CoverFile? { - val fileMutex = getMutexForFile(id) + override suspend fun write(name: String, block: suspend (OutputStream) -> Unit): CoverFile? { + val fileMutex = getMutexForFile(name) return fileMutex.withLock { - val targetFile = File(dir, getTargetFilePath(id)) + val targetFile = File(dir, name) if (!targetFile.exists()) { withContext(Dispatchers.IO) { - val tempFile = File(dir, getTempFilePath(id)) + val tempFile = File(dir, "$name.tmp") try { - tempFile.outputStream().use { coverFormat.transcodeInto(data, it) } + block(tempFile.outputStream()) tempFile.renameTo(targetFile) CoverFileImpl(targetFile) } catch (e: IOException) { @@ -83,10 +83,6 @@ private class CoverFilesImpl(private val dir: File, private val coverFormat: Cov } } } - - private fun getTargetFilePath(name: String) = "cover_${name}.${coverFormat.extension}" - - private fun getTempFilePath(name: String) = "${getTargetFilePath(name)}.tmp" } private class CoverFileImpl(private val file: File) : CoverFile { diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverIdentifier.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverIdentifier.kt index 7fa3b50fc..ef0917e05 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverIdentifier.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverIdentifier.kt @@ -20,7 +20,7 @@ package org.oxycblt.musikr.cover import java.security.MessageDigest -internal interface CoverIdentifier { +interface CoverIdentifier { suspend fun identify(data: ByteArray): String companion object { diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt index ee09546fd..5b7452a20 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt @@ -22,8 +22,11 @@ interface StoredCovers { suspend fun obtain(id: String): Cover? companion object { - fun from(files: CoverFiles): MutableStoredCovers = - FileStoredCovers(CoverIdentifier.md5(), files) + fun from( + coverFiles: CoverFiles, + coverFormat: CoverFormat, + identifier: CoverIdentifier = CoverIdentifier.md5() + ): MutableStoredCovers = FileStoredCovers(coverFiles, coverFormat, identifier) } } @@ -32,15 +35,21 @@ interface MutableStoredCovers : StoredCovers { } private class FileStoredCovers( + private val coverFiles: CoverFiles, + private val coverFormat: CoverFormat, private val coverIdentifier: CoverIdentifier, - private val coverFiles: CoverFiles ) : StoredCovers, MutableStoredCovers { - override suspend fun obtain(id: String) = coverFiles.find(id)?.let { FileCover(id, it) } + override suspend fun obtain(id: String) = + coverFiles.find(getFileName(id))?.let { FileCover(id, it) } - override suspend fun write(data: ByteArray) = - coverIdentifier.identify(data).let { id -> - coverFiles.write(id, data)?.let { FileCover(id, it) } - } + override suspend fun write(data: ByteArray): Cover? { + val id = coverIdentifier.identify(data) + return coverFiles + .write(getFileName(id)) { coverFormat.transcodeInto(data, it) } + ?.let { FileCover(id, it) } + } + + private fun getFileName(id: String) = "$id.${coverFormat.extension}" } private class FileCover(override val id: String, private val coverFile: CoverFile) : Cover {