musikr: hide unstable internals

Hypothetically I'd open these up into a broader API once I can confirm
they are safely extensible.
This commit is contained in:
Alexander Capehart 2024-12-21 11:31:14 -05:00
parent b9c8933021
commit 2ec3bbbe8c
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
12 changed files with 35 additions and 34 deletions

View file

@ -23,12 +23,13 @@ import androidx.media3.common.util.Log
import java.util.UUID
import org.oxycblt.auxio.util.unlikelyToBeNull
import org.oxycblt.musikr.cover.Cover
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.at(context, "covers_$it") }
protected val inner = revision?.let { StoredCovers.from(context, "covers_$it", CoverFormat.jpeg()) }
override suspend fun obtain(id: String): RevisionedCover? {
val split = id.split('@', limit = 2)
@ -43,7 +44,7 @@ open class RevisionedStoredCovers(private val context: Context, private val revi
val storedCovers = unlikelyToBeNull(inner)
return storedCovers.obtain(coverId)?.let { RevisionedCover(revision, it) }
} else {
val storedCovers = StoredCovers.at(context, "covers_$coverRevision")
val storedCovers = StoredCovers.from(context, "covers_$coverRevision", CoverFormat.jpeg())
return storedCovers.obtain(coverId)?.let { RevisionedCover(coverRevision, it) }
}
}

View file

@ -22,10 +22,10 @@ import org.oxycblt.musikr.cover.StoredCovers
import org.oxycblt.musikr.fs.DeviceFile
import org.oxycblt.musikr.pipeline.RawSong
interface Cache {
suspend fun read(file: DeviceFile, storedCovers: StoredCovers): CacheResult
abstract class Cache {
internal abstract suspend fun read(file: DeviceFile, storedCovers: StoredCovers): CacheResult
suspend fun write(song: RawSong)
internal abstract suspend fun write(song: RawSong)
companion object {
fun full(db: CacheDatabase): Cache = FullCache(db.cachedSongsDao())
@ -34,13 +34,13 @@ interface Cache {
}
}
sealed interface CacheResult {
internal sealed interface CacheResult {
data class Hit(val song: RawSong) : CacheResult
data class Miss(val file: DeviceFile) : CacheResult
}
private class FullCache(private val cacheInfoDao: CacheInfoDao) : Cache {
private class FullCache(private val cacheInfoDao: CacheInfoDao) : Cache() {
override suspend fun read(file: DeviceFile, storedCovers: StoredCovers) =
cacheInfoDao.selectSong(file.uri.toString(), file.lastModified)?.let {
CacheResult.Hit(it.intoRawSong(file, storedCovers))
@ -50,7 +50,7 @@ private class FullCache(private val cacheInfoDao: CacheInfoDao) : Cache {
cacheInfoDao.updateSong(CachedSong.fromRawSong(song))
}
private class WriteOnlyCache(private val cacheInfoDao: CacheInfoDao) : Cache {
private class WriteOnlyCache(private val cacheInfoDao: CacheInfoDao) : Cache() {
override suspend fun read(file: DeviceFile, storedCovers: StoredCovers) = CacheResult.Miss(file)
override suspend fun write(song: RawSong) =

View file

@ -27,18 +27,18 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
interface CoverFiles {
internal interface CoverFiles {
suspend fun find(id: String): CoverFile?
suspend fun write(id: String, data: ByteArray): CoverFile?
companion object {
fun at(context: Context, path: String): CoverFiles =
CoverFilesImpl(File(context.filesDir, path).also { it.mkdirs() }, CoverFormat.jpeg())
fun at(context: Context, path: String, format: CoverFormat): CoverFiles =
CoverFilesImpl(File(context.filesDir, path).also { it.mkdirs() }, format)
}
}
interface CoverFile {
internal interface CoverFile {
suspend fun open(): InputStream?
}

View file

@ -22,10 +22,10 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import java.io.OutputStream
internal interface CoverFormat {
val extension: String
abstract class CoverFormat {
internal abstract val extension: String
fun transcodeInto(data: ByteArray, output: OutputStream): Boolean
internal abstract fun transcodeInto(data: ByteArray, output: OutputStream): Boolean
companion object {
// Enable if perhaps you want to try other formats.
@ -50,7 +50,7 @@ private class CoverFormatImpl(
val size: Int,
val quality: Int,
val format: Bitmap.CompressFormat,
) : CoverFormat {
) : CoverFormat() {
override fun transcodeInto(data: ByteArray, output: OutputStream) =
BitmapFactory.Options().run {
inJustDecodeBounds = true

View file

@ -24,8 +24,8 @@ interface StoredCovers {
suspend fun obtain(id: String): Cover.Single?
companion object {
fun at(context: Context, path: String): MutableStoredCovers =
FileStoredCovers(CoverIdentifier.md5(), CoverFiles.at(context, path))
fun from(context: Context, path: String, format: CoverFormat): MutableStoredCovers =
FileStoredCovers(CoverIdentifier.md5(), CoverFiles.at(context, path, format))
}
}

View file

@ -20,7 +20,7 @@ package org.oxycblt.musikr.fs
import android.net.Uri
data class DeviceFile(
internal data class DeviceFile(
val uri: Uri,
val mimeType: String,
val path: Path,

View file

@ -53,7 +53,7 @@ internal data class Metadata(
}
}
data class Properties(
internal data class Properties(
val mimeType: String,
val durationMs: Long,
val bitrateKbps: Int,

View file

@ -159,7 +159,7 @@ private class ExtractStepImpl(
private data class FileWith<T>(val file: DeviceFile, val with: T)
}
data class RawSong(
internal data class RawSong(
val file: DeviceFile,
val properties: Properties,
val tags: ParsedTags,

View file

@ -21,18 +21,18 @@ package org.oxycblt.musikr.playlist
import org.oxycblt.musikr.Music
import org.oxycblt.musikr.Song
data class PlaylistFile(
internal data class PlaylistFile(
val name: String,
val songPointers: List<SongPointer>,
val handle: PlaylistHandle
)
sealed interface SongPointer {
internal sealed interface SongPointer {
data class UID(val uid: Music.UID) : SongPointer
// data class Path(val options: List<Path>) : SongPointer
}
interface PlaylistHandle {
internal interface PlaylistHandle {
val uid: Music.UID
suspend fun rename(name: String)

View file

@ -24,10 +24,10 @@ import org.oxycblt.musikr.playlist.PlaylistFile
import org.oxycblt.musikr.playlist.PlaylistHandle
import org.oxycblt.musikr.playlist.SongPointer
interface StoredPlaylists {
suspend fun new(name: String, songs: List<Song>): PlaylistHandle
abstract class StoredPlaylists {
internal abstract suspend fun new(name: String, songs: List<Song>): PlaylistHandle
suspend fun read(): List<PlaylistFile>
internal abstract suspend fun read(): List<PlaylistFile>
companion object {
fun from(database: PlaylistDatabase): StoredPlaylists =
@ -35,7 +35,7 @@ interface StoredPlaylists {
}
}
private class StoredPlaylistsImpl(private val playlistDao: PlaylistDao) : StoredPlaylists {
private class StoredPlaylistsImpl(private val playlistDao: PlaylistDao) : StoredPlaylists() {
override suspend fun new(name: String, songs: List<Song>): PlaylistHandle {
val info = PlaylistInfo(Music.UID.auxio(Music.UID.Item.PLAYLIST), name)
playlistDao.insertPlaylist(RawPlaylist(info, songs.map { PlaylistSong(it.uid) }))

View file

@ -41,7 +41,7 @@ import org.oxycblt.musikr.util.unlikelyToBeNull
*
* @author Alexander Capehart (OxygenCobalt)
*/
interface M3U {
abstract class M3U {
/**
* Reads an M3U file from the given [stream] and returns a [ImportedPlaylist] containing the
* paths to the files listed in the M3U file.
@ -51,7 +51,7 @@ interface M3U {
* resolve relative paths.
* @return An [ImportedPlaylist] containing the paths to the files listed in the M3U file,
*/
fun read(stream: InputStream, workingDirectory: Path): ImportedPlaylist?
internal abstract fun read(stream: InputStream, workingDirectory: Path): ImportedPlaylist?
/**
* Writes the given [playlist] to the given [outputStream] in the M3U format,.
@ -62,7 +62,7 @@ interface M3U {
* create relative paths to where the M3U file is assumed to be stored.
* @param config The configuration to use when exporting the playlist.
*/
fun write(
internal abstract fun write(
playlist: Playlist,
outputStream: OutputStream,
workingDirectory: Path,
@ -73,11 +73,11 @@ interface M3U {
/** The mime type used for M3U files by the android system. */
const val MIME_TYPE = "audio/x-mpegurl"
fun from(context: Context): M3U = M3UImpl(VolumeManager.from(context))
internal fun from(context: Context): M3U = M3UImpl(VolumeManager.from(context))
}
}
private class M3UImpl(private val volumeManager: VolumeManager) : M3U {
private class M3UImpl(private val volumeManager: VolumeManager) : M3U() {
override fun read(stream: InputStream, workingDirectory: Path): ImportedPlaylist? {
val volumes = volumeManager.getVolumes()
val reader = BufferedReader(InputStreamReader(stream))

View file

@ -20,7 +20,7 @@ package org.oxycblt.musikr.tag.parse
import org.oxycblt.musikr.tag.Date
data class ParsedTags(
internal data class ParsedTags(
val durationMs: Long,
val replayGainTrackAdjustment: Float? = null,
val replayGainAlbumAdjustment: Float? = null,