diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt index 1e57a5390..c24dff5ee 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -28,6 +28,8 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.withContext import kotlinx.coroutines.yield import org.oxycblt.auxio.music.MusicRepository.IndexingWorker +import org.oxycblt.auxio.music.covers.CoverSilo +import org.oxycblt.auxio.music.covers.SiloedCovers import org.oxycblt.musikr.IndexingProgress import org.oxycblt.musikr.Interpretation import org.oxycblt.musikr.Library @@ -38,6 +40,7 @@ import org.oxycblt.musikr.Playlist import org.oxycblt.musikr.Song import org.oxycblt.musikr.Storage import org.oxycblt.musikr.cache.StoredCache +import org.oxycblt.musikr.cover.CoverParams import org.oxycblt.musikr.playlist.db.StoredPlaylists import org.oxycblt.musikr.tag.interpret.Naming import org.oxycblt.musikr.tag.interpret.Separators @@ -385,7 +388,7 @@ constructor( val currentRevision = musicSettings.revision val newRevision = currentRevision?.takeIf { withCache } ?: UUID.randomUUID() val cache = if (withCache) storedCache.visible() else storedCache.invisible() - val covers = RevisionedCovers.at(context, newRevision) + val covers = SiloedCovers.at(context, CoverSilo(newRevision, CoverParams.of(750, 80))) val storage = Storage(cache, covers, storedPlaylists) val interpretation = Interpretation(nameFactory, separators) diff --git a/app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt b/app/src/main/java/org/oxycblt/auxio/music/covers/SiloedCovers.kt similarity index 50% rename from app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt rename to app/src/main/java/org/oxycblt/auxio/music/covers/SiloedCovers.kt index b43b386b7..ac67a5363 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/covers/SiloedCovers.kt @@ -1,6 +1,6 @@ /* * Copyright (c) 2024 Auxio Project - * RevisionedCovers.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 @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music +package org.oxycblt.auxio.music.covers import android.content.Context import java.io.File @@ -31,19 +31,19 @@ import org.oxycblt.musikr.cover.CoverParams import org.oxycblt.musikr.cover.MutableStoredCovers import org.oxycblt.musikr.cover.StoredCovers -class RevisionedCovers( +class SiloedCovers( private val rootDir: File, - private val revision: UUID, + private val silo: CoverSilo, private val inner: MutableStoredCovers ) : MutableStoredCovers { - override suspend fun obtain(id: String): RevisionedCover? { - val (coverId, coverRevision) = parse(id) ?: return null - if (coverRevision != revision) return null - return inner.obtain(coverId)?.let { RevisionedCover(revision, it) } + override suspend fun obtain(id: String): SiloedCover? { + val coverId = SiloedCoverId.parse(id) ?: return null + if (coverId.silo != silo) return null + return inner.obtain(coverId.id)?.let { SiloedCover(coverId.silo, it) } } - override suspend fun write(data: ByteArray): RevisionedCover? { - return inner.write(data)?.let { RevisionedCover(revision, it) } + override suspend fun write(data: ByteArray): SiloedCover? { + return inner.write(data)?.let { SiloedCover(silo, it) } } override suspend fun cleanup(assuming: Library) { @@ -51,37 +51,57 @@ class RevisionedCovers( // Destroy old revisions no longer being used. withContext(Dispatchers.IO) { - val exclude = revision.toString() + val exclude = silo.toString() rootDir.listFiles { file -> file.name != exclude }?.forEach { it.deleteRecursively() } } } companion object { - suspend fun at(context: Context, revision: UUID): RevisionedCovers { + suspend fun at(context: Context, silo: CoverSilo): SiloedCovers { val rootDir: File val revisionDir: File withContext(Dispatchers.IO) { rootDir = context.filesDir.resolve("covers").apply { mkdirs() } - revisionDir = rootDir.resolve(revision.toString()).apply { mkdirs() } + revisionDir = rootDir.resolve(silo.toString()).apply { mkdirs() } } val files = CoverFiles.at(revisionDir) - val format = CoverFormat.jpeg(CoverParams.of(750, 80)) - return RevisionedCovers(rootDir, revision, StoredCovers.from(files, format)) - } - - private fun parse(id: String): Pair? { - val split = id.split('@', limit = 2) - if (split.size != 2) return null - val (coverId, coverRevisionStr) = split - val coverRevision = coverRevisionStr.toUuidOrNull() ?: return null - return coverId to coverRevision + val format = CoverFormat.jpeg(silo.params) + return SiloedCovers(rootDir, silo, StoredCovers.from(files, format)) } } } -class RevisionedCover(private val revision: UUID, val inner: Cover) : Cover by inner { - override val id: String - get() = "${inner.id}@${revision}" +data class CoverSilo(val revision: UUID, val params: CoverParams) { + override fun toString() = "${revision}.${params.resolution}.${params.quality}" + + companion object { + fun parse(silo: String): CoverSilo? { + val parts = silo.split('.') + if (parts.size != 3) return null + val revision = parts[0].toUuidOrNull() ?: return null + val resolution = parts[1].toIntOrNull() ?: return null + val quality = parts[2].toIntOrNull() ?: return null + return CoverSilo(revision, CoverParams.of(resolution, quality)) + } + } +} + +class SiloedCover(silo: CoverSilo, private val innerCover: Cover) : Cover by innerCover { + private val innerId = SiloedCoverId(silo, innerCover.id) + override val id = innerId.toString() +} + +data class SiloedCoverId(val silo: CoverSilo, val id: String) { + override fun toString() = "$id@$silo" + + companion object { + fun parse(id: String): SiloedCoverId? { + val parts = id.split('@') + if (parts.size != 2) return null + val silo = CoverSilo.parse(parts[1]) ?: return null + return SiloedCoverId(silo, parts[0]) + } + } } private fun String.toUuidOrNull(): UUID? = diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverParams.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverParams.kt index 28e73c640..4397b6302 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverParams.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverParams.kt @@ -18,7 +18,7 @@ package org.oxycblt.musikr.cover -class CoverParams private constructor(internal val resolution: Int, internal val quality: Int) { +class CoverParams private constructor(val resolution: Int, val quality: Int) { companion object { fun of(resolution: Int, quality: Int): CoverParams { check(resolution > 0) { "Resolution must be positive" }