From 5b44c31689bd6d1d825f59c822358cd4ed333893 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Tue, 13 Jun 2023 09:37:18 -0600 Subject: [PATCH] music: sort song information Sort song informtion in all MusicParent instances. This is a temporary hack to band-aid music consistency between reloads, as with the aggressive parallelization song order is no longer consistent. --- .../auxio/music/device/DeviceLibrary.kt | 14 ++--- .../auxio/music/device/DeviceMusicImpl.kt | 52 +++++++++---------- .../oxycblt/auxio/music/device/RawMusic.kt | 16 +++--- 3 files changed, 37 insertions(+), 45 deletions(-) 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 9ec43ee9b..905954fd2 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 @@ -203,7 +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, musicSettings) } for (album in albums) { for (rawArtist in album.rawArtists) { val key = RawArtist.Key(rawArtist) @@ -236,19 +236,11 @@ 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 artists = artistGrouping.values.map { ArtistImpl(it, musicSettings) } + val genres = genreGrouping.values.map { GenreImpl(it, musicSettings) } return DeviceLibraryImpl(songGrouping.values, albums, artists, genres) } - - private data class Grouping( - var raw: PrioritizedRaw, - val music: MutableList - ) - - private data class PrioritizedRaw(val inner: R, val src: M) } class DeviceLibraryImpl( diff --git a/app/src/main/java/org/oxycblt/auxio/music/device/DeviceMusicImpl.kt b/app/src/main/java/org/oxycblt/auxio/music/device/DeviceMusicImpl.kt index 82827b59b..095be1967 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/device/DeviceMusicImpl.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/device/DeviceMusicImpl.kt @@ -231,17 +231,16 @@ class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Son /** * Library-backed implementation of [Album]. * - * @param rawAlbum The [RawAlbum] to derive the member data from. + * @param grouping [Grouping] to derive the member data from. * @param musicSettings [MusicSettings] to for user parsing configuration. - * @param songs The [Song]s that are a part of this [Album]. These items will be linked to this - * [Album]. * @author Alexander Capehart (OxygenCobalt) */ class AlbumImpl( - private val rawAlbum: RawAlbum, + grouping: Grouping, musicSettings: MusicSettings, - override val songs: List ) : Album { + private val rawAlbum = grouping.raw.inner + override val uid = // Attempt to use a MusicBrainz ID first before falling back to a hashed UID. rawAlbum.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ALBUMS, it) } @@ -259,6 +258,7 @@ class AlbumImpl( override val durationMs: Long override val dateAdded: Long + override val songs: List private val _artists = mutableListOf() override val artists: List get() = _artists @@ -272,7 +272,7 @@ class AlbumImpl( var earliestDateAdded: Long = Long.MAX_VALUE // Do linking and value generation in the same loop for efficiency. - for (song in songs) { + for (song in grouping.music) { song.link(this) if (song.date != null) { @@ -298,6 +298,7 @@ class AlbumImpl( dates = if (min != null && max != null) Date.Range(min, max) else null durationMs = totalDuration dateAdded = earliestDateAdded + songs = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).songs(grouping.music) hashCode = 31 * hashCode + rawAlbum.hashCode() hashCode = 31 * hashCode + songs.hashCode() @@ -347,18 +348,13 @@ class AlbumImpl( /** * Library-backed implementation of [Artist]. * - * @param rawArtist The [RawArtist] to derive the member data from. + * @param grouping [Grouping] to derive the member data from. * @param musicSettings [MusicSettings] to for user parsing configuration. - * @param songAlbums A list of the [Song]s and [Album]s that are a part of this [Artist] , either - * through artist or album artist tags. Providing [Song]s to the artist is optional. These - * instances will be linked to this [Artist]. * @author Alexander Capehart (OxygenCobalt) */ -class ArtistImpl( - private val rawArtist: RawArtist, - musicSettings: MusicSettings, - songAlbums: List -) : Artist { +class ArtistImpl(grouping: Grouping, musicSettings: MusicSettings) : Artist { + private val rawArtist = grouping.raw.inner + override val uid = // Attempt to use a MusicBrainz ID first before falling back to a hashed UID. rawArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ARTISTS, it) } @@ -381,7 +377,7 @@ class ArtistImpl( val distinctSongs = mutableSetOf() val albumMap = mutableMapOf() - for (music in songAlbums) { + for (music in grouping.music) { when (music) { is SongImpl -> { music.link(this) @@ -398,7 +394,7 @@ class ArtistImpl( } } - songs = distinctSongs.toList() + songs = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).songs(distinctSongs) albums = Sort(Sort.Mode.ByDate, Sort.Direction.DESCENDING).albums(albumMap.keys) explicitAlbums = albums.filter { unlikelyToBeNull(albumMap[it]) } implicitAlbums = albums.filterNot { unlikelyToBeNull(albumMap[it]) } @@ -449,40 +445,38 @@ class ArtistImpl( /** * Library-backed implementation of [Genre]. * - * @param rawGenre [RawGenre] to derive the member data from. + * @param grouping [Grouping] to derive the member data from. * @param musicSettings [MusicSettings] to for user parsing configuration. - * @param songs Child [SongImpl]s of this instance. * @author Alexander Capehart (OxygenCobalt) */ -class GenreImpl( - private val rawGenre: RawGenre, - musicSettings: MusicSettings, - override val songs: List -) : Genre { +class GenreImpl(grouping: Grouping, musicSettings: MusicSettings) : Genre { + private val rawGenre = grouping.raw.inner + override val uid = Music.UID.auxio(MusicMode.GENRES) { update(rawGenre.name) } override val name = rawGenre.name?.let { Name.Known.from(it, rawGenre.name, musicSettings) } ?: Name.Unknown(R.string.def_genre) + override val songs: List override val artists: List override val durationMs: Long private var hashCode = uid.hashCode() init { - val distinctAlbums = mutableSetOf() val distinctArtists = mutableSetOf() var totalDuration = 0L - for (song in songs) { + for (song in grouping.music) { song.link(this) - distinctAlbums.add(song.album) distinctArtists.addAll(song.artists) totalDuration += song.durationMs } + songs = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).songs(grouping.music) artists = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).artists(distinctArtists) durationMs = totalDuration + hashCode = 31 * hashCode + rawGenre.hashCode() hashCode = 31 * hashCode + songs.hashCode() } @@ -516,3 +510,7 @@ class GenreImpl( return this } } + +data class Grouping(var raw: PrioritizedRaw, val music: MutableList) + +data class PrioritizedRaw(val inner: R, val src: M) diff --git a/app/src/main/java/org/oxycblt/auxio/music/device/RawMusic.kt b/app/src/main/java/org/oxycblt/auxio/music/device/RawMusic.kt index 5828ac75a..b3037b0de 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/device/RawMusic.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/device/RawMusic.kt @@ -25,7 +25,6 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.fs.Directory import org.oxycblt.auxio.music.info.Date import org.oxycblt.auxio.music.info.ReleaseType -import org.oxycblt.auxio.util.logD /** * Raw information about a [SongImpl] obtained from the filesystem/Extractor instances. @@ -120,7 +119,10 @@ data class RawAlbum( ) { val key = Key(this) - /** Exposed information that denotes [RawAlbum] uniqueness. */ + /** + * Allows [RawAlbum]s to be compared by "fundamental" information that is unlikely to change on + * an item-by-item basis. + */ data class Key(private val inner: RawAlbum) { // Albums are grouped as follows: // - If we have a MusicBrainz ID, only group by it. This allows different Albums with the @@ -167,7 +169,7 @@ data class RawArtist( /** * Allows [RawArtist]s to be compared by "fundamental" information that is unlikely to change on - * an item-by-item + * an item-by-item basis. */ data class Key(private val inner: RawArtist) { // Artists are grouped as follows: @@ -179,10 +181,6 @@ data class RawArtist( // Cache the hashCode for HashMap efficiency. val hashCode = inner.musicBrainzId?.hashCode() ?: inner.name?.lowercase().hashCode() - init { - logD("${inner.name} ${inner.name?.lowercase().hashCode()} $hashCode") - } - // Compare names and MusicBrainz IDs in order to differentiate artists with the // same name in large libraries. @@ -216,6 +214,10 @@ data class RawGenre( ) { val key = Key(this) + /** + * Allows [RawGenre]s to be compared by "fundamental" information that is unlikely to change on + * an item-by-item basis. + */ data class Key(private val inner: RawGenre) { // Cache the hashCode for HashMap efficiency. private val hashCode = inner.name?.lowercase().hashCode()