From a9a6d1ccc1e6d52fc8d4f5448dd50a4618e7e1ae Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Wed, 7 Jun 2023 20:08:57 -0600 Subject: [PATCH] music: cleanup Clean up parts of the music loader. --- .../oxycblt/auxio/music/MusicRepository.kt | 2 +- .../auxio/music/device/DeviceLibrary.kt | 36 ++++++++++++------- .../oxycblt/auxio/music/user/UserLibrary.kt | 4 +-- 3 files changed, 26 insertions(+), 16 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 ab8bb16cb..6fa6801fb 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -372,7 +372,6 @@ constructor( // Do the initial query of the cache and media databases in parallel. logD("Starting MediaStore query") val mediaStoreQueryJob = worker.scope.tryAsync { mediaStoreExtractor.query() } - val userLibraryQueryJob = worker.scope.tryAsync { userLibraryFactory.query() } val cache = if (withCache) { logD("Reading cache") @@ -431,6 +430,7 @@ constructor( logD("Discovered ${rawSongs.size} songs, starting finalization") emitLoading(IndexingProgress.Indeterminate) logD("Starting UserLibrary query") + val userLibraryQueryJob = worker.scope.tryAsync { userLibraryFactory.query() } if (cache == null || cache.invalidated) { logD("Writing cache [why=${cache?.invalidated}]") cacheRepository.writeCache(rawSongs) diff --git a/app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt b/app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt index f53a87ea2..08e312ed5 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt @@ -97,6 +97,14 @@ interface DeviceLibrary { /** Constructs a [DeviceLibrary] implementation in an asynchronous manner. */ interface Factory { + /** + * Creates a new [DeviceLibrary] instance asynchronously based on the incoming stream of + * [RawSong] instances. + * + * @param rawSongs A stream of [RawSong] instances to process. + * @param processedSongs A stream of [RawSong] instances that will have been processed by + * the instance. + */ suspend fun create( rawSongs: Channel, processedSongs: Channel @@ -123,8 +131,11 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu // causing severe issues elsewhere. if (songGrouping.containsKey(song.uid)) { logW( - "Duplicate song found: ${song.path} in " + + "Duplicate song found: ${song.path} " + "collides with ${unlikelyToBeNull(songGrouping[song.uid]).path}") + // We still want to say that we "processed" the song so that the user doesn't + // get confused at why the bar was only partly filled by the end of the loading + // process. processedSongs.send(rawSong) continue } @@ -140,9 +151,9 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu // use for album information to ensure consistent metadata and UIDs. Fall back to // the name otherwise. val trackLower = - song.track != null && (prioritized.track == null || song.track < prioritized.track) - val nameLower = - song.name < prioritized.name + song.track != null && + (prioritized.track == null || song.track < prioritized.track) + val nameLower = song.name < prioritized.name if (trackLower || nameLower) { albumBody.raw = PrioritizedRaw(song.rawAlbum, song) } @@ -192,8 +203,7 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu // Now that all songs are processed, also process albums and group them into their // respective artists. - val albums = - albumGrouping.values.map { AlbumImpl(it.raw.inner, musicSettings, it.music) } + val albums = albumGrouping.values.map { AlbumImpl(it.raw.inner, musicSettings, it.music) } for (album in albums) { for (rawArtist in album.rawArtists) { val key = RawArtist.Key(rawArtist) @@ -204,13 +214,14 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu // Immediately replace any songs that initially held the priority position. is SongImpl -> body.raw = PrioritizedRaw(rawArtist, album) is AlbumImpl -> { - // Album information from later dates is prioritized, as it is more likely to + // Album information from later dates is prioritized, as it is more + // likely to // contain the "modern" name of the artist if the information really is // in-consistent. Fall back to the name otherwise. val dateEarlier = - album.dates != null && (prioritized.dates == null || album.dates < prioritized.dates) - val nameLower = - album.name < prioritized.name + album.dates != null && + (prioritized.dates == null || album.dates < prioritized.dates) + val nameLower = album.name < prioritized.name if (dateEarlier || nameLower) { body.raw = PrioritizedRaw(rawArtist, album) } @@ -228,8 +239,7 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu // Artists and genres do not need to be grouped and can be processed immediately. val artists = artistGrouping.values.map { ArtistImpl(it.raw.inner, musicSettings, it.music) } - val genres = - genreGrouping.values.map { GenreImpl(it.raw.inner, musicSettings, it.music) } + val genres = genreGrouping.values.map { GenreImpl(it.raw.inner, musicSettings, it.music) } return DeviceLibraryImpl(songGrouping.values, albums, artists, genres) } @@ -259,7 +269,7 @@ class DeviceLibraryImpl( override fun hashCode() = songs.hashCode() override fun toString() = "DeviceLibrary(songs=${songs.size}, albums=${albums.size}, " + - "artists=${artists.size}, genres=${genres.size})" + "artists=${artists.size}, genres=${genres.size})" override fun findSong(uid: Music.UID): Song? = songUidMap[uid] override fun findAlbum(uid: Music.UID): Album? = albumUidMap[uid] diff --git a/app/src/main/java/org/oxycblt/auxio/music/user/UserLibrary.kt b/app/src/main/java/org/oxycblt/auxio/music/user/UserLibrary.kt index a66bfd69a..1be916cf0 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/user/UserLibrary.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/user/UserLibrary.kt @@ -36,9 +36,9 @@ import org.oxycblt.auxio.util.logE * is also not backed by library information, rather an app database with in-memory caching. It is * generally not expected to create this yourself, and instead rely on MusicRepository. * - * TODO: Communicate errors - * * @author Alexander Capehart + * + * TODO: Communicate errors */ interface UserLibrary { /** The current user-defined playlists. */