diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/CoverModule.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/CoverModule.kt index 48f5d1052..8c7d668be 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/covers/CoverModule.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/covers/CoverModule.kt @@ -23,7 +23,7 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import org.oxycblt.musikr.cover.CoverIdentifier +import org.oxycblt.musikr.cover.fs.CoverIdentifier @Module @InstallIn(SingletonComponent::class) diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/CoverSilo.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/CoverSilo.kt index 9d7413f65..b6330303f 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/covers/CoverSilo.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/covers/CoverSilo.kt @@ -19,7 +19,7 @@ package org.oxycblt.auxio.image.covers import java.util.UUID -import org.oxycblt.musikr.cover.CoverParams +import org.oxycblt.musikr.cover.fs.CoverParams data class CoverSilo(val revision: UUID, val params: CoverParams) { override fun toString() = "${revision}.${params.resolution}.${params.quality}" diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/SettingCovers.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/SettingCovers.kt index 63e1dfd8d..ec3718a73 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/covers/SettingCovers.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/covers/SettingCovers.kt @@ -23,9 +23,9 @@ import java.util.UUID import javax.inject.Inject import org.oxycblt.auxio.image.CoverMode import org.oxycblt.auxio.image.ImageSettings -import org.oxycblt.musikr.cover.CoverIdentifier -import org.oxycblt.musikr.cover.CoverParams import org.oxycblt.musikr.cover.MutableCovers +import org.oxycblt.musikr.cover.fs.CoverIdentifier +import org.oxycblt.musikr.cover.fs.CoverParams interface SettingCovers { suspend fun create(context: Context, revision: UUID): MutableCovers diff --git a/app/src/main/java/org/oxycblt/auxio/image/covers/SiloedCovers.kt b/app/src/main/java/org/oxycblt/auxio/image/covers/SiloedCovers.kt index 253d0dacf..895ff01b8 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/covers/SiloedCovers.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/covers/SiloedCovers.kt @@ -23,21 +23,21 @@ import java.io.File import kotlinx.coroutines.Dispatchers 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 +import org.oxycblt.musikr.cover.fs.CoverFormat +import org.oxycblt.musikr.cover.fs.CoverIdentifier +import org.oxycblt.musikr.cover.fs.FSCovers +import org.oxycblt.musikr.cover.fs.FileCover +import org.oxycblt.musikr.cover.fs.MutableFSCovers +import org.oxycblt.musikr.fs.app.AppFS -open class SiloedCovers(private val silo: CoverSilo, private val fileCovers: FileCovers) : Covers { +open class SiloedCovers(private val silo: CoverSilo, private val FSCovers: FSCovers) : Covers { override suspend fun obtain(id: String): ObtainResult { val coverId = SiloedCoverId.parse(id) ?: return ObtainResult.Miss() if (coverId.silo != silo) return ObtainResult.Miss() - return when (val result = fileCovers.obtain(coverId.id)) { + return when (val result = FSCovers.obtain(coverId.id)) { is ObtainResult.Hit -> ObtainResult.Hit(SiloedCover(silo, result.cover)) is ObtainResult.Miss -> ObtainResult.Miss() } @@ -46,7 +46,7 @@ open class SiloedCovers(private val silo: CoverSilo, private val fileCovers: Fil companion object { suspend fun from(context: Context, silo: CoverSilo): SiloedCovers { val core = SiloCore.from(context, silo) - return SiloedCovers(silo, FileCovers(core.files, core.format)) + return SiloedCovers(silo, FSCovers(core.files, core.format)) } } } @@ -55,7 +55,7 @@ class MutableSiloedCovers private constructor( private val rootDir: File, private val silo: CoverSilo, - private val fileCovers: MutableFileCovers + private val fileCovers: MutableFSCovers ) : SiloedCovers(silo, fileCovers), MutableCovers { override suspend fun write(data: ByteArray) = SiloedCover(silo, fileCovers.write(data)) @@ -77,7 +77,7 @@ private constructor( ): MutableSiloedCovers { val core = SiloCore.from(context, silo) return MutableSiloedCovers( - core.rootDir, silo, MutableFileCovers(core.files, core.format, coverIdentifier)) + core.rootDir, silo, MutableFSCovers(core.files, core.format, coverIdentifier)) } } } @@ -101,7 +101,7 @@ data class SiloedCoverId(val silo: CoverSilo, val id: String) { } } -private data class SiloCore(val rootDir: File, val files: AppFiles, val format: CoverFormat) { +private data class SiloCore(val rootDir: File, val files: AppFS, val format: CoverFormat) { companion object { suspend fun from(context: Context, silo: CoverSilo): SiloCore { val rootDir: File @@ -110,7 +110,7 @@ private data class SiloCore(val rootDir: File, val files: AppFiles, val format: rootDir = context.coversDir() revisionDir = rootDir.resolve(silo.toString()).apply { mkdirs() } } - val files = AppFiles.at(revisionDir) + val files = AppFS.at(revisionDir) val format = CoverFormat.jpeg(silo.params) return SiloCore(rootDir, files, format) } diff --git a/app/src/main/java/org/oxycblt/auxio/music/shim/MusikrShimModule.kt b/app/src/main/java/org/oxycblt/auxio/music/shim/MusikrShimModule.kt index 7516cf3f3..19e6f6d7a 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/shim/MusikrShimModule.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/shim/MusikrShimModule.kt @@ -25,7 +25,7 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import javax.inject.Singleton -import org.oxycblt.musikr.cache.DBSongCache +import org.oxycblt.musikr.cache.DatabaseSongCache import org.oxycblt.musikr.cache.SongCache import org.oxycblt.musikr.playlist.db.StoredPlaylists @@ -34,7 +34,7 @@ import org.oxycblt.musikr.playlist.db.StoredPlaylists class MusikrShimModule { @Singleton @Provides - fun songCache(@ApplicationContext context: Context): SongCache = DBSongCache.from(context) + fun songCache(@ApplicationContext context: Context): SongCache = DatabaseSongCache.from(context) @Singleton @Provides diff --git a/musikr/src/main/java/org/oxycblt/musikr/cache/DBSongCache.kt b/musikr/src/main/java/org/oxycblt/musikr/cache/db/DBSongCache.kt similarity index 96% rename from musikr/src/main/java/org/oxycblt/musikr/cache/DBSongCache.kt rename to musikr/src/main/java/org/oxycblt/musikr/cache/db/DBSongCache.kt index d69b3e07b..cf0186da5 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cache/DBSongCache.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cache/db/DBSongCache.kt @@ -16,10 +16,13 @@ * along with this program. If not, see . */ -package org.oxycblt.musikr.cache +package org.oxycblt.musikr.cache.db import android.content.Context import org.oxycblt.musikr.Song +import org.oxycblt.musikr.cache.CacheResult +import org.oxycblt.musikr.cache.CachedSong +import org.oxycblt.musikr.cache.MutableSongCache import org.oxycblt.musikr.fs.device.DeviceFile import org.oxycblt.musikr.metadata.Properties import org.oxycblt.musikr.tag.parse.ParsedTags diff --git a/musikr/src/main/java/org/oxycblt/musikr/cache/SongCacheDatabase.kt b/musikr/src/main/java/org/oxycblt/musikr/cache/db/SongCacheDatabase.kt similarity index 99% rename from musikr/src/main/java/org/oxycblt/musikr/cache/SongCacheDatabase.kt rename to musikr/src/main/java/org/oxycblt/musikr/cache/db/SongCacheDatabase.kt index 95dbc2a87..a9fe59bfb 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cache/SongCacheDatabase.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cache/db/SongCacheDatabase.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.musikr.cache +package org.oxycblt.musikr.cache.db import android.content.Context import androidx.room.Dao diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/Covers.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/Covers.kt index e3f41b386..f3ba46821 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/Covers.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/Covers.kt @@ -20,22 +20,6 @@ package org.oxycblt.musikr.cover import java.io.InputStream -interface Covers { - suspend fun obtain(id: String): ObtainResult -} - -interface MutableCovers : Covers { - suspend fun write(data: ByteArray): Cover - - suspend fun cleanup(excluding: Collection) -} - -sealed interface ObtainResult { - data class Hit(val cover: T) : ObtainResult - - class Miss : ObtainResult -} - interface Cover { val id: String @@ -58,3 +42,19 @@ class CoverCollection private constructor(val covers: List) { .map { it.value.first() }) } } + +interface Covers { + suspend fun obtain(id: String): ObtainResult +} + +interface MutableCovers : Covers { + suspend fun write(data: ByteArray): Cover + + suspend fun cleanup(excluding: Collection) +} + +sealed interface ObtainResult { + data class Hit(val cover: T) : ObtainResult + + class Miss : ObtainResult +} diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFormat.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverFormat.kt similarity index 98% rename from musikr/src/main/java/org/oxycblt/musikr/cover/CoverFormat.kt rename to musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverFormat.kt index 52f9e15e3..496fd9609 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFormat.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverFormat.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.musikr.cover +package org.oxycblt.musikr.cover.fs import android.graphics.Bitmap import android.graphics.BitmapFactory diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverIdentifier.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverIdentifier.kt similarity index 97% rename from musikr/src/main/java/org/oxycblt/musikr/cover/CoverIdentifier.kt rename to musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverIdentifier.kt index ef0917e05..f99e84b00 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverIdentifier.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverIdentifier.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.musikr.cover +package org.oxycblt.musikr.cover.fs import java.security.MessageDigest diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverParams.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverParams.kt similarity index 97% rename from musikr/src/main/java/org/oxycblt/musikr/cover/CoverParams.kt rename to musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverParams.kt index 1b26dc63f..d85c4226c 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverParams.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/fs/CoverParams.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.musikr.cover +package org.oxycblt.musikr.cover.fs class CoverParams private constructor(val resolution: Int, val quality: Int) { override fun hashCode() = 31 * resolution + quality diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/FileCovers.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/fs/FSCovers.kt similarity index 72% rename from musikr/src/main/java/org/oxycblt/musikr/cover/FileCovers.kt rename to musikr/src/main/java/org/oxycblt/musikr/cover/fs/FSCovers.kt index 4c8390869..743378f39 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/FileCovers.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/fs/FSCovers.kt @@ -1,6 +1,6 @@ /* * Copyright (c) 2025 Auxio Project - * FileCovers.kt is part of Auxio. + * FSCovers.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,16 +16,19 @@ * along with this program. If not, see . */ -package org.oxycblt.musikr.cover +package org.oxycblt.musikr.cover.fs import android.os.ParcelFileDescriptor +import org.oxycblt.musikr.cover.Cover +import org.oxycblt.musikr.cover.Covers +import org.oxycblt.musikr.cover.MutableCovers +import org.oxycblt.musikr.cover.ObtainResult +import org.oxycblt.musikr.fs.app.AppFS import org.oxycblt.musikr.fs.app.AppFile -import org.oxycblt.musikr.fs.app.AppFiles -open class FileCovers(private val appFiles: AppFiles, private val coverFormat: CoverFormat) : - Covers { +open class FSCovers(private val appFS: AppFS, private val coverFormat: CoverFormat) : Covers { override suspend fun obtain(id: String): ObtainResult { - val file = appFiles.find(getFileName(id)) + val file = appFS.find(getFileName(id)) return if (file != null) { ObtainResult.Hit(FileCoverImpl(id, file)) } else { @@ -36,20 +39,20 @@ open class FileCovers(private val appFiles: AppFiles, private val coverFormat: C protected fun getFileName(id: String) = "$id.${coverFormat.extension}" } -class MutableFileCovers( - private val appFiles: AppFiles, +class MutableFSCovers( + private val appFS: AppFS, private val coverFormat: CoverFormat, private val coverIdentifier: CoverIdentifier -) : FileCovers(appFiles, coverFormat), MutableCovers { +) : FSCovers(appFS, coverFormat), MutableCovers { override suspend fun write(data: ByteArray): FileCover { val id = coverIdentifier.identify(data) - val file = appFiles.write(getFileName(id)) { coverFormat.transcodeInto(data, it) } + val file = appFS.write(getFileName(id)) { coverFormat.transcodeInto(data, it) } return FileCoverImpl(id, file) } override suspend fun cleanup(excluding: Collection) { val used = excluding.mapTo(mutableSetOf()) { getFileName(it.id) } - appFiles.deleteWhere { it !in used } + appFS.deleteWhere { it !in used } } } diff --git a/musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFiles.kt b/musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFS.kt similarity index 94% rename from musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFiles.kt rename to musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFS.kt index 9c8f2a407..50b423c08 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFiles.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFS.kt @@ -1,6 +1,6 @@ /* * Copyright (c) 2024 Auxio Project - * AppFiles.kt is part of Auxio. + * AppFS.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 @@ -28,7 +28,7 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext -interface AppFiles { +interface AppFS { suspend fun find(name: String): AppFile? suspend fun write(name: String, block: suspend (OutputStream) -> Unit): AppFile @@ -36,9 +36,9 @@ interface AppFiles { suspend fun deleteWhere(block: (String) -> Boolean) companion object { - suspend fun at(dir: File): AppFiles { + suspend fun at(dir: File): AppFS { withContext(Dispatchers.IO) { check(dir.exists() && dir.isDirectory) } - return AppFilesImpl(dir) + return AppFSImpl(dir) } } } @@ -49,7 +49,7 @@ interface AppFile { suspend fun open(): InputStream? } -private class AppFilesImpl(private val dir: File) : AppFiles { +private class AppFSImpl(private val dir: File) : AppFS { private val fileMutexes = mutableMapOf() private val mapMutex = Mutex() diff --git a/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFiles.kt b/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFS.kt similarity index 92% rename from musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFiles.kt rename to musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFS.kt index b2cb69ee8..25a7c0f61 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFiles.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFS.kt @@ -1,6 +1,6 @@ /* * Copyright (c) 2024 Auxio Project - * DeviceFiles.kt is part of Auxio. + * DeviceFS.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 @@ -32,16 +32,24 @@ import kotlinx.coroutines.flow.flow import org.oxycblt.musikr.fs.MusicLocation import org.oxycblt.musikr.fs.Path -internal interface DeviceFiles { +internal interface DeviceFS { fun explore(locations: Flow): Flow companion object { - fun from(context: Context): DeviceFiles = DeviceFilesImpl(context.contentResolverSafe) + fun from(context: Context): DeviceFS = DeviceFSImpl(context.contentResolverSafe) } } +data class DeviceFile( + val uri: Uri, + val mimeType: String, + val path: Path, + val size: Long, + val modifiedMs: Long +) + @OptIn(ExperimentalCoroutinesApi::class) -private class DeviceFilesImpl(private val contentResolver: ContentResolver) : DeviceFiles { +private class DeviceFSImpl(private val contentResolver: ContentResolver) : DeviceFS { override fun explore(locations: Flow): Flow = locations.flatMapMerge { location -> exploreImpl( diff --git a/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFile.kt b/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFile.kt deleted file mode 100644 index 4c9153c4a..000000000 --- a/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFile.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * DeviceFile.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 - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.oxycblt.musikr.fs.device - -import android.net.Uri -import org.oxycblt.musikr.fs.Path - -data class DeviceFile( - val uri: Uri, - val mimeType: String, - val path: Path, - val size: Long, - val modifiedMs: Long -) diff --git a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExploreStep.kt b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExploreStep.kt index 663220c43..676b7676b 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExploreStep.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExploreStep.kt @@ -35,7 +35,7 @@ import org.oxycblt.musikr.cache.SongCache import org.oxycblt.musikr.cover.Covers import org.oxycblt.musikr.cover.ObtainResult import org.oxycblt.musikr.fs.MusicLocation -import org.oxycblt.musikr.fs.device.DeviceFiles +import org.oxycblt.musikr.fs.device.DeviceFS import org.oxycblt.musikr.playlist.db.StoredPlaylists import org.oxycblt.musikr.playlist.m3u.M3U @@ -45,19 +45,19 @@ internal interface ExploreStep { companion object { fun from(context: Context, storage: Storage): ExploreStep = ExploreStepImpl( - DeviceFiles.from(context), storage.storedPlaylists, storage.cache, storage.covers) + DeviceFS.from(context), storage.storedPlaylists, storage.cache, storage.covers) } } private class ExploreStepImpl( - private val deviceFiles: DeviceFiles, + private val deviceFS: DeviceFS, private val storedPlaylists: StoredPlaylists, private val songCache: SongCache, private val covers: Covers ) : ExploreStep { override fun explore(locations: List): Flow { val audioFiles = - deviceFiles + deviceFS .explore(locations.asFlow()) .filter { it.mimeType.startsWith("audio/") || it.mimeType == M3U.MIME_TYPE } .flowOn(Dispatchers.IO)