From 0ba5ddce51d5e34a53d25dc581ae8f1b9af3a68d Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Tue, 26 Nov 2024 10:08:07 -0700 Subject: [PATCH] music: re-add library find functionality --- .../oxycblt/auxio/music/MusicRepository.kt | 30 ++++++------ .../org/oxycblt/auxio/music/stack/Indexer.kt | 20 ++++---- .../auxio/music/stack/explore/Explorer.kt | 30 ++++++------ .../music/stack/interpret/Interpreter.kt | 21 +++++---- .../music/stack/interpret/model/Library.kt | 47 +++++++------------ .../music/stack/interpret/prepare/PreMusic.kt | 24 +++++----- 6 files changed, 83 insertions(+), 89 deletions(-) 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 df7a7e803..231da75bf 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -34,7 +34,6 @@ import org.oxycblt.auxio.music.metadata.Separators import org.oxycblt.auxio.music.stack.Indexer import org.oxycblt.auxio.music.stack.interpret.Interpretation import org.oxycblt.auxio.music.stack.interpret.model.MutableLibrary -import kotlin.math.exp import timber.log.Timber as L /** @@ -366,23 +365,24 @@ constructor(private val indexer: Indexer, private val musicSettings: MusicSettin var explored = 0 var loaded = 0 - val newLibrary = indexer.run(listOf(), Interpretation(nameFactory, separators)) { - when (it) { - is Indexer.Event.Discovered -> { - explored = it.amount - emitIndexingProgress(IndexingProgress.Songs(loaded, explored)) - } - is Indexer.Event.Extracted -> { - loaded = it.amount - emitIndexingProgress(IndexingProgress.Songs(loaded, explored)) - } - is Indexer.Event.Interpret -> { - if (explored == loaded) { - emitIndexingProgress(IndexingProgress.Indeterminate) + val newLibrary = + indexer.run(listOf(), Interpretation(nameFactory, separators)) { + when (it) { + is Indexer.Event.Discovered -> { + explored = it.amount + emitIndexingProgress(IndexingProgress.Songs(loaded, explored)) + } + is Indexer.Event.Extracted -> { + loaded = it.amount + emitIndexingProgress(IndexingProgress.Songs(loaded, explored)) + } + is Indexer.Event.Interpret -> { + if (explored == loaded) { + emitIndexingProgress(IndexingProgress.Indeterminate) + } } } } - } // We want to make sure that all reads and writes are synchronized due to the sheer // amount of consumers of MusicRepository. diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/Indexer.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/Indexer.kt index 6e58afa8a..8c3262dce 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/stack/Indexer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/Indexer.kt @@ -31,27 +31,31 @@ import org.oxycblt.auxio.music.stack.interpret.Interpreter import org.oxycblt.auxio.music.stack.interpret.model.MutableLibrary interface Indexer { - suspend fun run(uris: List, interpretation: Interpretation, eventHandler: suspend (Event) -> Unit = {}): MutableLibrary + suspend fun run( + uris: List, + interpretation: Interpretation, + eventHandler: suspend (Event) -> Unit = {} + ): MutableLibrary sealed interface Event { data class Discovered( val amount: Int, ) : Event - data class Extracted( - val amount: Int - ) : Event + data class Extracted(val amount: Int) : Event - data class Interpret( - val amount: Int - ) : Event + data class Interpret(val amount: Int) : Event } } class IndexerImpl @Inject constructor(private val explorer: Explorer, private val interpreter: Interpreter) : Indexer { - override suspend fun run(uris: List, interpretation: Interpretation, eventHandler: suspend (Event) -> Unit) = coroutineScope { + override suspend fun run( + uris: List, + interpretation: Interpretation, + eventHandler: suspend (Event) -> Unit + ) = coroutineScope { val files = explorer.explore(uris, eventHandler) val audioFiles = files.audios.flowOn(Dispatchers.IO).buffer() val playlistFiles = files.playlists.flowOn(Dispatchers.IO).buffer() diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/explore/Explorer.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/explore/Explorer.kt index 305f9e74d..3c2142256 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/stack/explore/Explorer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/explore/Explorer.kt @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package org.oxycblt.auxio.music.stack.explore import android.net.Uri @@ -60,13 +60,15 @@ constructor( @OptIn(ExperimentalCoroutinesApi::class) override fun explore(uris: List, eventHandler: suspend (Indexer.Event) -> Unit): Files { var discovered = 0 - val deviceFiles = deviceFiles.explore(uris.asFlow()) - .onEach { - discovered++ - eventHandler(Indexer.Event.Discovered(discovered)) - } - .flowOn(Dispatchers.IO) - .buffer() + val deviceFiles = + deviceFiles + .explore(uris.asFlow()) + .onEach { + discovered++ + eventHandler(Indexer.Event.Discovered(discovered)) + } + .flowOn(Dispatchers.IO) + .buffer() val tagRead = tagCache.read(deviceFiles).flowOn(Dispatchers.IO).buffer() val (uncachedDeviceFiles, cachedAudioFiles) = tagRead.results() val extractedAudioFiles = @@ -77,10 +79,11 @@ constructor( .flattenMerge() val writtenAudioFiles = tagCache.write(extractedAudioFiles).flowOn(Dispatchers.IO).buffer() var loaded = 0 - val audioFiles = merge(cachedAudioFiles, writtenAudioFiles).onEach { - loaded++ - eventHandler(Indexer.Event.Extracted(loaded)) - } + val audioFiles = + merge(cachedAudioFiles, writtenAudioFiles).onEach { + loaded++ + eventHandler(Indexer.Event.Extracted(loaded)) + } val playlistFiles = storedPlaylists.read() return Files(audioFiles, playlistFiles) } @@ -97,8 +100,7 @@ constructor( val indexed = withIndex() val shared = indexed.shareIn( - CoroutineScope(Dispatchers.Main), SharingStarted.WhileSubscribed(), replay = 0 - ) + CoroutineScope(Dispatchers.Main), SharingStarted.WhileSubscribed(), replay = 0) return Array(n) { shared.filter { it.index % n == 0 }.map { it.value } } } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/Interpreter.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/Interpreter.kt index a3f46a731..a3271fe21 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/Interpreter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/Interpreter.kt @@ -83,7 +83,7 @@ class InterpreterImpl @Inject constructor(private val preparer: Preparer) : Inte .register(artistLinkedSongs) .flowOn(Dispatchers.Main) .onEach { - interpreted++; + interpreted++ eventHandler(Indexer.Event.Interpret(interpreted)) } .map { LinkedSongImpl(it) } @@ -91,16 +91,17 @@ class InterpreterImpl @Inject constructor(private val preparer: Preparer) : Inte val albums = albumLinker.resolve() val uidMap = mutableMapOf() - val songs = albumLinkedSongs.mapNotNull { - val uid = it.preSong.computeUid() - val other = uidMap[uid] - if (other == null) { - SongImpl(it) - } else { - L.d("Song @ $uid already exists at ${other.path}, ignoring") - null + val songs = + albumLinkedSongs.mapNotNull { + val uid = it.preSong.computeUid() + val other = uidMap[uid] + if (other == null) { + SongImpl(it) + } else { + L.d("Song @ $uid already exists at ${other.path}, ignoring") + null + } } - } return LibraryImpl( songs, albums.onEach { it.finalize() }, diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/model/Library.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/model/Library.kt index f7c9e8863..e094b0ee3 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/model/Library.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/model/Library.kt @@ -18,9 +18,6 @@ package org.oxycblt.auxio.music.stack.interpret.model -import org.oxycblt.auxio.music.Album -import org.oxycblt.auxio.music.Artist -import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Library import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Playlist @@ -47,53 +44,43 @@ class LibraryImpl( ) : MutableLibrary { override val playlists = emptySet() - private val songUidMap = songs.associ { it.uid } + private val songUidMap = songs.associateBy { it.uid } + private val albumUidMap = albums.associateBy { it.uid } + private val artistUidMap = artists.associateBy { it.uid } + private val genreUidMap = genres.associateBy { it.uid } + private val playlistUidMap = playlists.associateBy { it.uid } - override fun findSong(uid: Music.UID): Song? { - TODO("Not yet implemented") - } + override fun findSong(uid: Music.UID) = songUidMap[uid] - override fun findSongByPath(path: Path): Song? { - TODO("Not yet implemented") - } + override fun findSongByPath(path: Path) = songs.find { it.path == path } - override fun findAlbum(uid: Music.UID): Album? { - TODO("Not yet implemented") - } + override fun findAlbum(uid: Music.UID) = albumUidMap[uid] - override fun findArtist(uid: Music.UID): Artist? { - TODO("Not yet implemented") - } + override fun findArtist(uid: Music.UID) = artistUidMap[uid] - override fun findGenre(uid: Music.UID): Genre? { - TODO("Not yet implemented") - } + override fun findGenre(uid: Music.UID) = genreUidMap[uid] - override fun findPlaylist(uid: Music.UID): Playlist? { - TODO("Not yet implemented") - } + override fun findPlaylist(uid: Music.UID) = playlistUidMap[uid] - override fun findPlaylistByName(name: String): Playlist? { - TODO("Not yet implemented") - } + override fun findPlaylistByName(name: String) = playlists.find { it.name.raw == name } override suspend fun createPlaylist(name: String, songs: List): MutableLibrary { - TODO("Not yet implemented") + return this } override suspend fun renamePlaylist(playlist: Playlist, name: String): MutableLibrary { - TODO("Not yet implemented") + return this } override suspend fun addToPlaylist(playlist: Playlist, songs: List): MutableLibrary { - TODO("Not yet implemented") + return this } override suspend fun rewritePlaylist(playlist: Playlist, songs: List): MutableLibrary { - TODO("Not yet implemented") + return this } override suspend fun deletePlaylist(playlist: Playlist): MutableLibrary { - TODO("Not yet implemented") + return this } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/prepare/PreMusic.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/prepare/PreMusic.kt index e713037c3..74f8301bf 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/prepare/PreMusic.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/prepare/PreMusic.kt @@ -54,20 +54,20 @@ data class PreSong( ) { fun computeUid() = musicBrainzId?.let { Music.UID.musicBrainz(MusicType.SONGS, it) } - ?: Music.UID.auxio(MusicType.SONGS) { - // Song UIDs are based on the raw data without parsing so that they remain - // consistent across music setting changes. Parents are not held up to the - // same standard since grouping is already inherently linked to settings. - update(rawName) - update(preAlbum.rawName) - update(date) + ?: Music.UID.auxio(MusicType.SONGS) { + // Song UIDs are based on the raw data without parsing so that they remain + // consistent across music setting changes. Parents are not held up to the + // same standard since grouping is already inherently linked to settings. + update(rawName) + update(preAlbum.rawName) + update(date) - update(track) - update(disc?.number) + update(track) + update(disc?.number) - update(preArtists.map { artist -> artist.rawName }) - update(preAlbum.preArtists.map { artist -> artist.rawName }) - } + update(preArtists.map { artist -> artist.rawName }) + update(preAlbum.preArtists.map { artist -> artist.rawName }) + } } data class PreAlbum(