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 0af145490..71c03c78c 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -385,7 +385,7 @@ constructor( val currentRevision = musicSettings.revision val newRevision = currentRevision?.takeIf { withCache } ?: UUID.randomUUID() val cache = if (withCache) storedCache.visible() else storedCache.invisible() - val covers = MutableRevisionedStoredCovers(context, newRevision) + val covers = RevisionedCovers.at(context, newRevision) val storage = Storage(cache, covers, storedPlaylists) val interpretation = Interpretation(nameFactory, separators) @@ -432,7 +432,7 @@ constructor( // Old cover revisions may be lying around, even during a normal refresh due // to really lucky cancellations. Clean those up now that it's impossible for // the rest of the app to be using them. - RevisionedStoredCovers.cleanup(context, newRevision) + RevisionedCovers.cleanup(context, newRevision) } private suspend fun emitIndexingProgress(progress: IndexingProgress) { diff --git a/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt b/app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt similarity index 55% rename from app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt rename to app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt index ad176e28a..0e37a4491 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/RevisionedCovers.kt @@ -1,6 +1,6 @@ /* * Copyright (c) 2024 Auxio Project - * RevisionedLibrary.kt is part of Auxio. + * RevisionedCovers.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 @@ -22,51 +22,50 @@ import android.content.Context import java.util.UUID import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import org.oxycblt.auxio.util.unlikelyToBeNull import org.oxycblt.musikr.cover.Cover +import org.oxycblt.musikr.cover.CoverFiles import org.oxycblt.musikr.cover.CoverFormat import org.oxycblt.musikr.cover.MutableStoredCovers import org.oxycblt.musikr.cover.StoredCovers -open class RevisionedStoredCovers(private val context: Context, private val revision: UUID?) : - StoredCovers { - protected val inner = - revision?.let { StoredCovers.from(context, "covers_$it", CoverFormat.jpeg()) } - +class RevisionedCovers(private val revision: UUID, private val inner: MutableStoredCovers) : + MutableStoredCovers { override suspend fun obtain(id: String): RevisionedCover? { - val split = id.split('@', limit = 2) - if (split.size != 2) return null - val (coverId, coverRevisionStr) = split - val coverRevision = coverRevisionStr.toUuidOrNull() ?: return null - if (revision != null) { - if (coverRevision != revision) { - return null - } - val storedCovers = unlikelyToBeNull(inner) - return storedCovers.obtain(coverId)?.let { RevisionedCover(revision, it) } - } else { - val storedCovers = - StoredCovers.from(context, "covers_$coverRevision", CoverFormat.jpeg()) - return storedCovers.obtain(coverId)?.let { RevisionedCover(coverRevision, it) } - } + val (coverId, coverRevision) = parse(id) ?: return null + if (coverRevision != revision) return null + return inner.obtain(coverId)?.let { RevisionedCover(revision, it) } + } + + override suspend fun write(data: ByteArray): RevisionedCover? { + return inner.write(data)?.let { RevisionedCover(revision, it) } } companion object { + suspend fun at(context: Context, revision: UUID): RevisionedCovers { + val dir = + withContext(Dispatchers.IO) { + context.filesDir.resolve("covers/${revision}").apply { mkdirs() } + } + return RevisionedCovers( + revision, StoredCovers.from(CoverFiles.at(dir, CoverFormat.jpeg()))) + } + suspend fun cleanup(context: Context, exclude: UUID) = withContext(Dispatchers.IO) { + val excludeName = exclude.toString() context.filesDir - .listFiles { file -> - file.name.startsWith("covers_") && file.name != "covers_$exclude" - } + .resolve("covers") + .listFiles { file -> file.name != excludeName } ?.forEach { it.deleteRecursively() } } - } -} -class MutableRevisionedStoredCovers(context: Context, private val revision: UUID) : - RevisionedStoredCovers(context, revision), MutableStoredCovers { - override suspend fun write(data: ByteArray): RevisionedCover? { - return unlikelyToBeNull(inner).write(data)?.let { RevisionedCover(revision, it) } + 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 + } } } 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 86aaf51ef..d71d9f7c4 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt @@ -18,7 +18,6 @@ package org.oxycblt.musikr.cover -import android.content.Context import java.io.File import java.io.IOException import java.io.InputStream @@ -27,18 +26,20 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext -internal interface CoverFiles { +interface CoverFiles { suspend fun find(id: String): CoverFile? suspend fun write(id: String, data: ByteArray): CoverFile? companion object { - fun at(context: Context, path: String, format: CoverFormat): CoverFiles = - CoverFilesImpl(File(context.filesDir, path).also { it.mkdirs() }, format) + suspend fun at(dir: File, format: CoverFormat): CoverFiles { + withContext(Dispatchers.IO) { check(dir.exists() && dir.isDirectory) } + return CoverFilesImpl(dir, format) + } } } -internal interface CoverFile { +interface CoverFile { suspend fun open(): InputStream? } 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 841271ec8..ee09546fd 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt @@ -18,14 +18,12 @@ package org.oxycblt.musikr.cover -import android.content.Context - interface StoredCovers { suspend fun obtain(id: String): Cover? companion object { - fun from(context: Context, path: String, format: CoverFormat): MutableStoredCovers = - FileStoredCovers(CoverIdentifier.md5(), CoverFiles.at(context, path, format)) + fun from(files: CoverFiles): MutableStoredCovers = + FileStoredCovers(CoverIdentifier.md5(), files) } }