music: fix grouping regressions

Fix regressions in grouping, mostly around the kind of music that is
prioritized and sort naming.
This commit is contained in:
Alexander Capehart 2023-06-15 11:53:24 -06:00
parent 31d647123f
commit 839861b6b8
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 37 additions and 19 deletions

View file

@ -3,8 +3,8 @@
## dev
#### What's Improved
- Tags formatted as `artistssort` or `albumartistssort` are now recognized by Auxio
- Non-english digit strings are now sorted better
- `artistssort`, `albumartistssort`, and `album_artists` tags are now recognized
- Non-english digit strings are sorted more correctly
- Reduced visual loading time
#### What's Fixed
@ -12,6 +12,7 @@
- Fixed selection not updating when playlists are changed
- Fixed duplicate albums appearing in certain cases
- Fixed ReplayGain adjustment not applying at the start of a song in certain cases
- Music cache is no longer migrated between devices
## 3.1.1

View file

@ -23,9 +23,10 @@ import android.net.Uri
/**
* Bundle of [Uri] information used in [CoverExtractor] to ensure consistent [Uri] use when loading
* images.
*
* @param mediaStore The album cover [Uri] obtained from MediaStore.
* @param song The [Uri] of the first song (by track) of the album, which can also be used to
* obtain an album cover.
* @param song The [Uri] of the first song (by track) of the album, which can also be used to obtain
* an album cover.
* @author Alexander Capehart (OxygenCobalt)
*/
data class CoverUri(val mediaStore: Uri, val song: Uri)

View file

@ -123,6 +123,8 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
val artistGrouping = mutableMapOf<RawArtist.Key, Grouping<RawArtist, Music>>()
val genreGrouping = mutableMapOf<RawGenre.Key, Grouping<RawGenre, SongImpl>>()
// TODO: Use comparators here
// All music information is grouped as it is indexed by other components.
for (rawSong in rawSongs) {
val song = SongImpl(rawSong, musicSettings)
@ -150,11 +152,13 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
// Since albums are grouped fuzzily, we pick the song with the earliest track to
// use for album information to ensure consistent metadata and UIDs. Fall back to
// the name otherwise.
val trackLower =
val higherPriority =
song.track != null &&
(prioritized.track == null || song.track < prioritized.track)
val nameLower = song.name < prioritized.name
if (trackLower || nameLower) {
(prioritized.track == null ||
song.track < prioritized.track ||
(song.track == prioritized.track && song.name < prioritized.name))
if (higherPriority) {
albumBody.raw = PrioritizedRaw(song.rawAlbum, song)
}
} else {
@ -187,8 +191,8 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
// Genre information from higher songs in ascending alphabetical order are
// prioritized.
val prioritized = genreBody.raw.src
val nameLower = song.name < prioritized.name
if (nameLower) {
val higherPriority = song.name < prioritized.name
if (higherPriority) {
genreBody.raw = PrioritizedRaw(rawGenre, song)
}
} else {
@ -217,11 +221,14 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
// 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 =
val prioritize =
album.dates != null &&
(prioritized.dates == null || album.dates < prioritized.dates)
val nameLower = album.name < prioritized.name
if (dateEarlier || nameLower) {
(prioritized.dates == null ||
album.dates > prioritized.dates ||
(album.dates == prioritized.dates &&
album.name < prioritized.name))
if (prioritize) {
body.raw = PrioritizedRaw(rawArtist, album)
}
}
@ -243,6 +250,8 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
}
}
// TODO: Avoid redundant data creation
class DeviceLibraryImpl(
override val songs: Set<SongImpl>,
override val albums: Set<AlbumImpl>,

View file

@ -141,7 +141,9 @@ private class TagWorkerImpl(
textFrames["TALB"]?.let { rawSong.albumName = it.first() }
textFrames["TSOA"]?.let { rawSong.albumSortName = it.first() }
(textFrames["TXXX:musicbrainz album type"]
?: textFrames["TXXX:releasetype"] ?: textFrames["GRP1"])
?: textFrames["TXXX:releasetype"] ?:
// This is a non-standard iTunes extension
textFrames["GRP1"])
?.let { rawSong.releaseTypes = it }
// Artist
@ -158,15 +160,17 @@ private class TagWorkerImpl(
rawSong.albumArtistNames = it
}
(textFrames["TXXX:albumartistssort"]
?: textFrames["TXXX:albumartists_sort"] ?: textFrames["TSO2"])
?: textFrames["TXXX:albumartists_sort"] ?: textFrames["TXXX:albumartistsort"]
// This is a non-standard iTunes extension
?: textFrames["TSO2"])
?.let { rawSong.albumArtistSortNames = it }
// Genre
textFrames["TCON"]?.let { rawSong.genreNames = it }
// Compilation Flag
(textFrames["TCMP"]
?: textFrames["TXXX:compilation"] ?: textFrames["TXXX:itunescompilation"])
(textFrames["TCMP"] // This is a non-standard itunes extension
?: textFrames["TXXX:compilation"] ?: textFrames["TXXX:itunescompilation"])
?.let {
// Ignore invalid instances of this tag
if (it.size != 1 || it[0] != "1") return@let
@ -175,6 +179,7 @@ private class TagWorkerImpl(
rawSong.albumArtistNames.ifEmpty { COMPILATION_ALBUM_ARTISTS }
rawSong.releaseTypes = rawSong.releaseTypes.ifEmpty { COMPILATION_RELEASE_TYPES }
}
// ReplayGain information
textFrames["TXXX:replaygain_track_gain"]?.parseReplayGainAdjustment()?.let {
rawSong.replayGainTrackAdjustment = it
@ -262,7 +267,9 @@ private class TagWorkerImpl(
// Album artist
comments["musicbrainz_albumartistid"]?.let { rawSong.albumArtistMusicBrainzIds = it }
(comments["albumartists"] ?: comments["albumartist"])?.let { rawSong.albumArtistNames = it }
(comments["albumartists"] ?: comments["album_artists"] ?: comments["albumartist"])?.let {
rawSong.albumArtistNames = it
}
(comments["albumartistssort"]
?: comments["albumartists_sort"] ?: comments["albumartistsort"])
?.let { rawSong.albumArtistSortNames = it }