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 1deaae968..72c97e4d0 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 @@ -24,13 +24,13 @@ import javax.inject.Inject import org.oxycblt.auxio.image.CoverMode import org.oxycblt.auxio.image.ImageSettings import org.oxycblt.musikr.covers.Cover +import org.oxycblt.musikr.covers.Covers +import org.oxycblt.musikr.covers.MutableCovers +import org.oxycblt.musikr.covers.fs.FSCovers +import org.oxycblt.musikr.covers.fs.MutableFSCovers import org.oxycblt.musikr.covers.internal.CoverIdentifier import org.oxycblt.musikr.covers.internal.CoverParams -import org.oxycblt.musikr.covers.Covers import org.oxycblt.musikr.covers.internal.FileCover -import org.oxycblt.musikr.covers.fs.FSCovers -import org.oxycblt.musikr.covers.MutableCovers -import org.oxycblt.musikr.covers.fs.MutableFSCovers interface SettingCovers { suspend fun mutate(context: Context, revision: UUID): MutableCovers @@ -57,6 +57,5 @@ constructor(private val imageSettings: ImageSettings, private val identifier: Co private suspend fun siloedCovers(context: Context, revision: UUID, with: CoverParams?) = MutableCovers.chain( MutableSiloedCovers.from(context, CoverSilo(revision, with), identifier), - MutableFSCovers(context) - ) + MutableFSCovers(context)) } 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 08a89f7da..c8f5288aa 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,13 +23,13 @@ import java.io.File import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.oxycblt.musikr.covers.Cover -import org.oxycblt.musikr.covers.internal.CoverFormat -import org.oxycblt.musikr.covers.internal.CoverIdentifier import org.oxycblt.musikr.covers.CoverResult import org.oxycblt.musikr.covers.Covers +import org.oxycblt.musikr.covers.MutableCovers +import org.oxycblt.musikr.covers.internal.CoverFormat +import org.oxycblt.musikr.covers.internal.CoverIdentifier import org.oxycblt.musikr.covers.internal.FileCover import org.oxycblt.musikr.covers.internal.InternalCovers -import org.oxycblt.musikr.covers.MutableCovers import org.oxycblt.musikr.covers.internal.MutableInternalCovers import org.oxycblt.musikr.fs.app.AppFS import org.oxycblt.musikr.fs.device.DeviceFile @@ -96,8 +96,7 @@ private constructor( ): MutableSiloedCovers { val core = SiloCore.from(context, silo) return MutableSiloedCovers( - core.rootDir, silo, MutableInternalCovers(core.files, core.format, coverIdentifier) - ) + core.rootDir, silo, MutableInternalCovers(core.files, core.format, coverIdentifier)) } } } diff --git a/musikr/src/main/java/org/oxycblt/musikr/Config.kt b/musikr/src/main/java/org/oxycblt/musikr/Config.kt index df51be932..e07eae2bd 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/Config.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/Config.kt @@ -28,8 +28,8 @@ import org.oxycblt.musikr.tag.interpret.Separators /** Side-effect laden [Storage] for use during music loading and [MutableLibrary] operation. */ data class Storage( /** - * A factory producing a repository of cached metadata to read and write from over the course of - * music loading. This will only be used during music loading. + * A repository of cached metadata to read and write from over the course of music loading. This + * will only be used during music loading. */ val cache: MutableCache, @@ -57,5 +57,5 @@ data class Interpretation( val separators: Separators, /** Whether to ignore hidden files and directories (those starting with a dot). */ - val ignoreHidden: Boolean = true + val ignoreHidden: Boolean ) diff --git a/musikr/src/main/java/org/oxycblt/musikr/covers/Covers.kt b/musikr/src/main/java/org/oxycblt/musikr/covers/Covers.kt index b1e266673..adef4cf44 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/covers/Covers.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/covers/Covers.kt @@ -18,6 +18,7 @@ package org.oxycblt.musikr.covers +import android.os.ParcelFileDescriptor import java.io.InputStream import org.oxycblt.musikr.fs.device.DeviceFile import org.oxycblt.musikr.metadata.Metadata @@ -94,6 +95,10 @@ interface Cover { override fun hashCode(): Int } +interface FDCover : Cover { + suspend fun fd(): ParcelFileDescriptor? +} + class CoverCollection private constructor(val covers: List) { override fun hashCode() = covers.hashCode() diff --git a/musikr/src/main/java/org/oxycblt/musikr/covers/fs/FSCovers.kt b/musikr/src/main/java/org/oxycblt/musikr/covers/fs/FSCovers.kt index 229b5b673..2ae18666c 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/covers/fs/FSCovers.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/covers/fs/FSCovers.kt @@ -29,20 +29,19 @@ import kotlinx.coroutines.withContext import org.oxycblt.musikr.covers.Cover import org.oxycblt.musikr.covers.CoverResult import org.oxycblt.musikr.covers.Covers +import org.oxycblt.musikr.covers.FDCover import org.oxycblt.musikr.covers.MutableCovers -import org.oxycblt.musikr.covers.internal.FileCover import org.oxycblt.musikr.fs.device.DeviceDirectory import org.oxycblt.musikr.fs.device.DeviceFile import org.oxycblt.musikr.metadata.Metadata -open class FSCovers(private val context: Context) : Covers { - override suspend fun obtain(id: String): CoverResult { +open class FSCovers(private val context: Context) : Covers { + override suspend fun obtain(id: String): CoverResult { // Parse the ID to get the directory URI if (!id.startsWith("folder:")) { return CoverResult.Miss() } - // TODO: Check if the dir actually exists still to avoid stale uris val directoryUri = id.substring("folder:".length) val uri = Uri.parse(directoryUri) @@ -65,9 +64,8 @@ open class FSCovers(private val context: Context) : Covers { } } -class MutableFSCovers(private val context: Context) : - FSCovers(context), MutableCovers { - override suspend fun create(file: DeviceFile, metadata: Metadata): CoverResult { +class MutableFSCovers(private val context: Context) : FSCovers(context), MutableCovers { + override suspend fun create(file: DeviceFile, metadata: Metadata): CoverResult { val parent = file.parent val coverFile = findCoverInDirectory(parent) ?: return CoverResult.Miss() return CoverResult.Hit(FolderCoverImpl(context, coverFile.uri)) @@ -88,12 +86,10 @@ class MutableFSCovers(private val context: Context) : val filename = requireNotNull(file.path.name).lowercase() val mimeType = file.mimeType.lowercase() - // Check if the file is an image if (!mimeType.startsWith("image/")) { return false } - // Common cover art filenames val coverNames = listOf( "cover", @@ -103,11 +99,8 @@ class MutableFSCovers(private val context: Context) : "front", "artwork", "art", - "folder", - "cover") + "folder") - // Check if the filename matches any common cover art names - // Also check for case variations (e.g., Cover.jpg, COVER.JPG) val filenameWithoutExt = filename.substringBeforeLast(".") val extension = filename.substringAfterLast(".", "") @@ -120,12 +113,10 @@ class MutableFSCovers(private val context: Context) : } } -interface FolderCover : FileCover - private data class FolderCoverImpl( private val context: Context, private val uri: Uri, -) : FolderCover { +) : FDCover { override val id = "folder:$uri" override suspend fun fd(): ParcelFileDescriptor? = diff --git a/musikr/src/main/java/org/oxycblt/musikr/covers/internal/CoverFormat.kt b/musikr/src/main/java/org/oxycblt/musikr/covers/internal/CoverFormat.kt index 292f8ff3e..d64bc5f49 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/covers/internal/CoverFormat.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/covers/internal/CoverFormat.kt @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2025 Auxio Project + * CoverFormat.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.covers.internal import android.graphics.Bitmap diff --git a/musikr/src/main/java/org/oxycblt/musikr/covers/internal/InternalCovers.kt b/musikr/src/main/java/org/oxycblt/musikr/covers/internal/InternalCovers.kt index 9d641a1d3..4d2f47bfc 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/covers/internal/InternalCovers.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/covers/internal/InternalCovers.kt @@ -1,6 +1,6 @@ /* * Copyright (c) 2025 Auxio Project - * FileCovers.kt is part of Auxio. + * InternalCovers.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 @@ -18,22 +18,22 @@ package org.oxycblt.musikr.covers.internal -import android.os.ParcelFileDescriptor import org.oxycblt.musikr.covers.Cover import org.oxycblt.musikr.covers.CoverResult import org.oxycblt.musikr.covers.Covers +import org.oxycblt.musikr.covers.FDCover import org.oxycblt.musikr.covers.MutableCovers -import org.oxycblt.musikr.fs.app.AppFile import org.oxycblt.musikr.fs.app.AppFS +import org.oxycblt.musikr.fs.app.AppFile import org.oxycblt.musikr.fs.device.DeviceFile import org.oxycblt.musikr.metadata.Metadata open class InternalCovers(private val appFS: AppFS, private val coverFormat: CoverFormat) : - Covers { - override suspend fun obtain(id: String): CoverResult { + Covers { + override suspend fun obtain(id: String): CoverResult { val file = appFS.find(getFileName(id)) return if (file != null) { - CoverResult.Hit(FileCoverImpl(id, file)) + CoverResult.Hit(InternalCoverImpl(id, file)) } else { CoverResult.Miss() } @@ -46,12 +46,12 @@ class MutableInternalCovers( private val appFS: AppFS, private val coverFormat: CoverFormat, private val coverIdentifier: CoverIdentifier -) : InternalCovers(appFS, coverFormat), MutableCovers { - override suspend fun create(file: DeviceFile, metadata: Metadata): CoverResult { +) : InternalCovers(appFS, coverFormat), MutableCovers { + override suspend fun create(file: DeviceFile, metadata: Metadata): CoverResult { val data = metadata.cover ?: return CoverResult.Miss() val id = coverIdentifier.identify(data) val coverFile = appFS.write(getFileName(id)) { coverFormat.transcodeInto(data, it) } - return CoverResult.Hit(FileCoverImpl(id, coverFile)) + return CoverResult.Hit(InternalCoverImpl(id, coverFile)) } override suspend fun cleanup(excluding: Collection) { @@ -60,12 +60,8 @@ class MutableInternalCovers( } } -interface FileCover : Cover { - suspend fun fd(): ParcelFileDescriptor? -} - -private data class FileCoverImpl(override val id: String, private val appFile: AppFile) : - FileCover { +private data class InternalCoverImpl(override val id: String, private val appFile: AppFile) : + FDCover { override suspend fun fd() = appFile.fd() override suspend fun open() = appFile.open() diff --git a/musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFS.kt b/musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFS.kt index 77de81796..50b423c08 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/fs/app/AppFS.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 diff --git a/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFS.kt b/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFS.kt index 99a9bd8f3..925a38a09 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/fs/device/DeviceFS.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 @@ -31,7 +31,7 @@ import org.oxycblt.musikr.fs.MusicLocation import org.oxycblt.musikr.fs.Path internal interface DeviceFS { - fun explore(locations: Flow, ignoreHidden: Boolean = true): Flow + fun explore(locations: Flow, ignoreHidden: Boolean): Flow companion object { fun from(context: Context): DeviceFS = DeviceFSImpl(context.contentResolverSafe) 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 7866a6d6f..17367fb5d 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExploreStep.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExploreStep.kt @@ -38,8 +38,8 @@ import org.oxycblt.musikr.covers.CoverResult import org.oxycblt.musikr.covers.Covers import org.oxycblt.musikr.fs.MusicLocation import org.oxycblt.musikr.fs.device.DeviceDirectory -import org.oxycblt.musikr.fs.device.DeviceFile import org.oxycblt.musikr.fs.device.DeviceFS +import org.oxycblt.musikr.fs.device.DeviceFile import org.oxycblt.musikr.fs.device.DeviceNode import org.oxycblt.musikr.playlist.db.StoredPlaylists import org.oxycblt.musikr.playlist.m3u.M3U