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.
This commit is contained in:
Alexander Capehart 2023-06-13 09:37:18 -06:00
parent 530e427b79
commit 5b44c31689
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 37 additions and 45 deletions

View file

@ -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<R, M : Music>(
var raw: PrioritizedRaw<R, M>,
val music: MutableList<M>
)
private data class PrioritizedRaw<R, M : Music>(val inner: R, val src: M)
}
class DeviceLibraryImpl(

View file

@ -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<RawAlbum, SongImpl>,
musicSettings: MusicSettings,
override val songs: List<SongImpl>
) : 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<Song>
private val _artists = mutableListOf<ArtistImpl>()
override val artists: List<Artist>
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<Music>
) : Artist {
class ArtistImpl(grouping: Grouping<RawArtist, Music>, 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<Song>()
val albumMap = mutableMapOf<Album, Boolean>()
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<SongImpl>
) : Genre {
class GenreImpl(grouping: Grouping<RawGenre, SongImpl>, 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<Song>
override val artists: List<Artist>
override val durationMs: Long
private var hashCode = uid.hashCode()
init {
val distinctAlbums = mutableSetOf<Album>()
val distinctArtists = mutableSetOf<Artist>()
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<R, M : Music>(var raw: PrioritizedRaw<R, M>, val music: MutableList<M>)
data class PrioritizedRaw<R, M : Music>(val inner: R, val src: M)

View file

@ -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()