musikr: cleanup
This commit is contained in:
parent
6feee93438
commit
22249cc95b
10 changed files with 57 additions and 49 deletions
|
@ -24,13 +24,13 @@ import javax.inject.Inject
|
||||||
import org.oxycblt.auxio.image.CoverMode
|
import org.oxycblt.auxio.image.CoverMode
|
||||||
import org.oxycblt.auxio.image.ImageSettings
|
import org.oxycblt.auxio.image.ImageSettings
|
||||||
import org.oxycblt.musikr.covers.Cover
|
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.CoverIdentifier
|
||||||
import org.oxycblt.musikr.covers.internal.CoverParams
|
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.internal.FileCover
|
||||||
import org.oxycblt.musikr.covers.fs.FSCovers
|
|
||||||
import org.oxycblt.musikr.covers.MutableCovers
|
|
||||||
import org.oxycblt.musikr.covers.fs.MutableFSCovers
|
|
||||||
|
|
||||||
interface SettingCovers {
|
interface SettingCovers {
|
||||||
suspend fun mutate(context: Context, revision: UUID): MutableCovers<out Cover>
|
suspend fun mutate(context: Context, revision: UUID): MutableCovers<out Cover>
|
||||||
|
@ -57,6 +57,5 @@ constructor(private val imageSettings: ImageSettings, private val identifier: Co
|
||||||
private suspend fun siloedCovers(context: Context, revision: UUID, with: CoverParams?) =
|
private suspend fun siloedCovers(context: Context, revision: UUID, with: CoverParams?) =
|
||||||
MutableCovers.chain(
|
MutableCovers.chain(
|
||||||
MutableSiloedCovers.from(context, CoverSilo(revision, with), identifier),
|
MutableSiloedCovers.from(context, CoverSilo(revision, with), identifier),
|
||||||
MutableFSCovers(context)
|
MutableFSCovers(context))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,13 @@ import java.io.File
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.oxycblt.musikr.covers.Cover
|
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.CoverResult
|
||||||
import org.oxycblt.musikr.covers.Covers
|
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.FileCover
|
||||||
import org.oxycblt.musikr.covers.internal.InternalCovers
|
import org.oxycblt.musikr.covers.internal.InternalCovers
|
||||||
import org.oxycblt.musikr.covers.MutableCovers
|
|
||||||
import org.oxycblt.musikr.covers.internal.MutableInternalCovers
|
import org.oxycblt.musikr.covers.internal.MutableInternalCovers
|
||||||
import org.oxycblt.musikr.fs.app.AppFS
|
import org.oxycblt.musikr.fs.app.AppFS
|
||||||
import org.oxycblt.musikr.fs.device.DeviceFile
|
import org.oxycblt.musikr.fs.device.DeviceFile
|
||||||
|
@ -96,8 +96,7 @@ private constructor(
|
||||||
): MutableSiloedCovers {
|
): MutableSiloedCovers {
|
||||||
val core = SiloCore.from(context, silo)
|
val core = SiloCore.from(context, silo)
|
||||||
return MutableSiloedCovers(
|
return MutableSiloedCovers(
|
||||||
core.rootDir, silo, MutableInternalCovers(core.files, core.format, coverIdentifier)
|
core.rootDir, silo, MutableInternalCovers(core.files, core.format, coverIdentifier))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ import org.oxycblt.musikr.tag.interpret.Separators
|
||||||
/** Side-effect laden [Storage] for use during music loading and [MutableLibrary] operation. */
|
/** Side-effect laden [Storage] for use during music loading and [MutableLibrary] operation. */
|
||||||
data class Storage(
|
data class Storage(
|
||||||
/**
|
/**
|
||||||
* A factory producing a repository of cached metadata to read and write from over the course of
|
* A repository of cached metadata to read and write from over the course of music loading. This
|
||||||
* music loading. This will only be used during music loading.
|
* will only be used during music loading.
|
||||||
*/
|
*/
|
||||||
val cache: MutableCache,
|
val cache: MutableCache,
|
||||||
|
|
||||||
|
@ -57,5 +57,5 @@ data class Interpretation(
|
||||||
val separators: Separators,
|
val separators: Separators,
|
||||||
|
|
||||||
/** Whether to ignore hidden files and directories (those starting with a dot). */
|
/** Whether to ignore hidden files and directories (those starting with a dot). */
|
||||||
val ignoreHidden: Boolean = true
|
val ignoreHidden: Boolean
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package org.oxycblt.musikr.covers
|
package org.oxycblt.musikr.covers
|
||||||
|
|
||||||
|
import android.os.ParcelFileDescriptor
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import org.oxycblt.musikr.fs.device.DeviceFile
|
import org.oxycblt.musikr.fs.device.DeviceFile
|
||||||
import org.oxycblt.musikr.metadata.Metadata
|
import org.oxycblt.musikr.metadata.Metadata
|
||||||
|
@ -94,6 +95,10 @@ interface Cover {
|
||||||
override fun hashCode(): Int
|
override fun hashCode(): Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FDCover : Cover {
|
||||||
|
suspend fun fd(): ParcelFileDescriptor?
|
||||||
|
}
|
||||||
|
|
||||||
class CoverCollection private constructor(val covers: List<Cover>) {
|
class CoverCollection private constructor(val covers: List<Cover>) {
|
||||||
override fun hashCode() = covers.hashCode()
|
override fun hashCode() = covers.hashCode()
|
||||||
|
|
||||||
|
|
|
@ -29,20 +29,19 @@ import kotlinx.coroutines.withContext
|
||||||
import org.oxycblt.musikr.covers.Cover
|
import org.oxycblt.musikr.covers.Cover
|
||||||
import org.oxycblt.musikr.covers.CoverResult
|
import org.oxycblt.musikr.covers.CoverResult
|
||||||
import org.oxycblt.musikr.covers.Covers
|
import org.oxycblt.musikr.covers.Covers
|
||||||
|
import org.oxycblt.musikr.covers.FDCover
|
||||||
import org.oxycblt.musikr.covers.MutableCovers
|
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.DeviceDirectory
|
||||||
import org.oxycblt.musikr.fs.device.DeviceFile
|
import org.oxycblt.musikr.fs.device.DeviceFile
|
||||||
import org.oxycblt.musikr.metadata.Metadata
|
import org.oxycblt.musikr.metadata.Metadata
|
||||||
|
|
||||||
open class FSCovers(private val context: Context) : Covers<FolderCover> {
|
open class FSCovers(private val context: Context) : Covers<FDCover> {
|
||||||
override suspend fun obtain(id: String): CoverResult<FolderCover> {
|
override suspend fun obtain(id: String): CoverResult<FDCover> {
|
||||||
// Parse the ID to get the directory URI
|
// Parse the ID to get the directory URI
|
||||||
if (!id.startsWith("folder:")) {
|
if (!id.startsWith("folder:")) {
|
||||||
return CoverResult.Miss()
|
return CoverResult.Miss()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check if the dir actually exists still to avoid stale uris
|
|
||||||
val directoryUri = id.substring("folder:".length)
|
val directoryUri = id.substring("folder:".length)
|
||||||
val uri = Uri.parse(directoryUri)
|
val uri = Uri.parse(directoryUri)
|
||||||
|
|
||||||
|
@ -65,9 +64,8 @@ open class FSCovers(private val context: Context) : Covers<FolderCover> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MutableFSCovers(private val context: Context) :
|
class MutableFSCovers(private val context: Context) : FSCovers(context), MutableCovers<FDCover> {
|
||||||
FSCovers(context), MutableCovers<FolderCover> {
|
override suspend fun create(file: DeviceFile, metadata: Metadata): CoverResult<FDCover> {
|
||||||
override suspend fun create(file: DeviceFile, metadata: Metadata): CoverResult<FolderCover> {
|
|
||||||
val parent = file.parent
|
val parent = file.parent
|
||||||
val coverFile = findCoverInDirectory(parent) ?: return CoverResult.Miss()
|
val coverFile = findCoverInDirectory(parent) ?: return CoverResult.Miss()
|
||||||
return CoverResult.Hit(FolderCoverImpl(context, coverFile.uri))
|
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 filename = requireNotNull(file.path.name).lowercase()
|
||||||
val mimeType = file.mimeType.lowercase()
|
val mimeType = file.mimeType.lowercase()
|
||||||
|
|
||||||
// Check if the file is an image
|
|
||||||
if (!mimeType.startsWith("image/")) {
|
if (!mimeType.startsWith("image/")) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common cover art filenames
|
|
||||||
val coverNames =
|
val coverNames =
|
||||||
listOf(
|
listOf(
|
||||||
"cover",
|
"cover",
|
||||||
|
@ -103,11 +99,8 @@ class MutableFSCovers(private val context: Context) :
|
||||||
"front",
|
"front",
|
||||||
"artwork",
|
"artwork",
|
||||||
"art",
|
"art",
|
||||||
"folder",
|
"folder")
|
||||||
"cover")
|
|
||||||
|
|
||||||
// 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 filenameWithoutExt = filename.substringBeforeLast(".")
|
||||||
val extension = filename.substringAfterLast(".", "")
|
val extension = filename.substringAfterLast(".", "")
|
||||||
|
|
||||||
|
@ -120,12 +113,10 @@ class MutableFSCovers(private val context: Context) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FolderCover : FileCover
|
|
||||||
|
|
||||||
private data class FolderCoverImpl(
|
private data class FolderCoverImpl(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val uri: Uri,
|
private val uri: Uri,
|
||||||
) : FolderCover {
|
) : FDCover {
|
||||||
override val id = "folder:$uri"
|
override val id = "folder:$uri"
|
||||||
|
|
||||||
override suspend fun fd(): ParcelFileDescriptor? =
|
override suspend fun fd(): ParcelFileDescriptor? =
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.oxycblt.musikr.covers.internal
|
package org.oxycblt.musikr.covers.internal
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2025 Auxio Project
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,22 +18,22 @@
|
||||||
|
|
||||||
package org.oxycblt.musikr.covers.internal
|
package org.oxycblt.musikr.covers.internal
|
||||||
|
|
||||||
import android.os.ParcelFileDescriptor
|
|
||||||
import org.oxycblt.musikr.covers.Cover
|
import org.oxycblt.musikr.covers.Cover
|
||||||
import org.oxycblt.musikr.covers.CoverResult
|
import org.oxycblt.musikr.covers.CoverResult
|
||||||
import org.oxycblt.musikr.covers.Covers
|
import org.oxycblt.musikr.covers.Covers
|
||||||
|
import org.oxycblt.musikr.covers.FDCover
|
||||||
import org.oxycblt.musikr.covers.MutableCovers
|
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.AppFS
|
||||||
|
import org.oxycblt.musikr.fs.app.AppFile
|
||||||
import org.oxycblt.musikr.fs.device.DeviceFile
|
import org.oxycblt.musikr.fs.device.DeviceFile
|
||||||
import org.oxycblt.musikr.metadata.Metadata
|
import org.oxycblt.musikr.metadata.Metadata
|
||||||
|
|
||||||
open class InternalCovers(private val appFS: AppFS, private val coverFormat: CoverFormat) :
|
open class InternalCovers(private val appFS: AppFS, private val coverFormat: CoverFormat) :
|
||||||
Covers<FileCover> {
|
Covers<FDCover> {
|
||||||
override suspend fun obtain(id: String): CoverResult<FileCover> {
|
override suspend fun obtain(id: String): CoverResult<FDCover> {
|
||||||
val file = appFS.find(getFileName(id))
|
val file = appFS.find(getFileName(id))
|
||||||
return if (file != null) {
|
return if (file != null) {
|
||||||
CoverResult.Hit(FileCoverImpl(id, file))
|
CoverResult.Hit(InternalCoverImpl(id, file))
|
||||||
} else {
|
} else {
|
||||||
CoverResult.Miss()
|
CoverResult.Miss()
|
||||||
}
|
}
|
||||||
|
@ -46,12 +46,12 @@ class MutableInternalCovers(
|
||||||
private val appFS: AppFS,
|
private val appFS: AppFS,
|
||||||
private val coverFormat: CoverFormat,
|
private val coverFormat: CoverFormat,
|
||||||
private val coverIdentifier: CoverIdentifier
|
private val coverIdentifier: CoverIdentifier
|
||||||
) : InternalCovers(appFS, coverFormat), MutableCovers<FileCover> {
|
) : InternalCovers(appFS, coverFormat), MutableCovers<FDCover> {
|
||||||
override suspend fun create(file: DeviceFile, metadata: Metadata): CoverResult<FileCover> {
|
override suspend fun create(file: DeviceFile, metadata: Metadata): CoverResult<FDCover> {
|
||||||
val data = metadata.cover ?: return CoverResult.Miss()
|
val data = metadata.cover ?: return CoverResult.Miss()
|
||||||
val id = coverIdentifier.identify(data)
|
val id = coverIdentifier.identify(data)
|
||||||
val coverFile = appFS.write(getFileName(id)) { coverFormat.transcodeInto(data, it) }
|
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<Cover>) {
|
override suspend fun cleanup(excluding: Collection<Cover>) {
|
||||||
|
@ -60,12 +60,8 @@ class MutableInternalCovers(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FileCover : Cover {
|
private data class InternalCoverImpl(override val id: String, private val appFile: AppFile) :
|
||||||
suspend fun fd(): ParcelFileDescriptor?
|
FDCover {
|
||||||
}
|
|
||||||
|
|
||||||
private data class FileCoverImpl(override val id: String, private val appFile: AppFile) :
|
|
||||||
FileCover {
|
|
||||||
override suspend fun fd() = appFile.fd()
|
override suspend fun fd() = appFile.fd()
|
||||||
|
|
||||||
override suspend fun open() = appFile.open()
|
override suspend fun open() = appFile.open()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2024 Auxio Project
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2024 Auxio Project
|
* 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
|
* 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
|
* 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
|
import org.oxycblt.musikr.fs.Path
|
||||||
|
|
||||||
internal interface DeviceFS {
|
internal interface DeviceFS {
|
||||||
fun explore(locations: Flow<MusicLocation>, ignoreHidden: Boolean = true): Flow<DeviceNode>
|
fun explore(locations: Flow<MusicLocation>, ignoreHidden: Boolean): Flow<DeviceNode>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun from(context: Context): DeviceFS = DeviceFSImpl(context.contentResolverSafe)
|
fun from(context: Context): DeviceFS = DeviceFSImpl(context.contentResolverSafe)
|
||||||
|
|
|
@ -38,8 +38,8 @@ import org.oxycblt.musikr.covers.CoverResult
|
||||||
import org.oxycblt.musikr.covers.Covers
|
import org.oxycblt.musikr.covers.Covers
|
||||||
import org.oxycblt.musikr.fs.MusicLocation
|
import org.oxycblt.musikr.fs.MusicLocation
|
||||||
import org.oxycblt.musikr.fs.device.DeviceDirectory
|
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.DeviceFS
|
||||||
|
import org.oxycblt.musikr.fs.device.DeviceFile
|
||||||
import org.oxycblt.musikr.fs.device.DeviceNode
|
import org.oxycblt.musikr.fs.device.DeviceNode
|
||||||
import org.oxycblt.musikr.playlist.db.StoredPlaylists
|
import org.oxycblt.musikr.playlist.db.StoredPlaylists
|
||||||
import org.oxycblt.musikr.playlist.m3u.M3U
|
import org.oxycblt.musikr.playlist.m3u.M3U
|
||||||
|
|
Loading…
Reference in a new issue