music: group albums by raw artist keys

Properly group albums by raw artist keys, instead of by raw artist
instances.

This was an accidental regression in 3.1.1 that resulted in duplicate
albums in some circumstances.

Resolves #475.
This commit is contained in:
Alexander Capehart 2023-06-08 20:40:09 -06:00
parent e848bea0bf
commit 672c256b1e
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 19 additions and 16 deletions

View file

@ -38,7 +38,6 @@ import org.oxycblt.auxio.music.info.ReleaseType
import org.oxycblt.auxio.music.metadata.parseId3GenreNames
import org.oxycblt.auxio.music.metadata.parseMultiValue
import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.nonZeroOrNull
import org.oxycblt.auxio.util.toUuidOrNull
import org.oxycblt.auxio.util.unlikelyToBeNull
@ -92,16 +91,13 @@ class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Son
override val durationMs = requireNotNull(rawSong.durationMs) { "Invalid raw: No duration" }
override val replayGainAdjustment =
if (rawSong.replayGainTrackAdjustment != null &&
rawSong.replayGainAlbumAdjustment != null) {
ReplayGainAdjustment(
track = unlikelyToBeNull(rawSong.replayGainTrackAdjustment),
album = unlikelyToBeNull(rawSong.replayGainAlbumAdjustment))
} else {
null
}
.also {
logD("${rawSong.replayGainTrackAdjustment} ${rawSong.replayGainAlbumAdjustment}}")
}
rawSong.replayGainAlbumAdjustment != null) {
ReplayGainAdjustment(
track = unlikelyToBeNull(rawSong.replayGainTrackAdjustment),
album = unlikelyToBeNull(rawSong.replayGainAlbumAdjustment))
} else {
null
}
override val dateAdded = requireNotNull(rawSong.dateAdded) { "Invalid raw: No date added" }
private var _album: AlbumImpl? = null
override val album: Album

View file

@ -25,6 +25,7 @@ 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.
@ -128,10 +129,12 @@ data class RawAlbum(
// artist name. This allows for case-insensitive artist/album grouping, which can be common
// for albums/artists that have different naming (ex. "RAMMSTEIN" vs. "Rammstein").
private val artistKeys = inner.rawArtists.map { it.key }
// Cache the hash-code for HashMap efficiency.
private val hashCode =
inner.musicBrainzId?.hashCode()
?: (31 * inner.name.lowercase().hashCode() + inner.rawArtists.hashCode())
?: (31 * inner.name.lowercase().hashCode() + artistKeys.hashCode())
override fun hashCode() = hashCode
@ -141,8 +144,7 @@ data class RawAlbum(
inner.musicBrainzId != null && other.inner.musicBrainzId != null ->
inner.musicBrainzId == other.inner.musicBrainzId
inner.musicBrainzId == null && other.inner.musicBrainzId == null ->
inner.name.equals(other.inner.name, true) &&
inner.rawArtists == other.inner.rawArtists
inner.name.equals(other.inner.name, true) && artistKeys == other.artistKeys
else -> false
}
}
@ -176,7 +178,11 @@ data class RawArtist(
// grouping to be case-insensitive.
// Cache the hashCode for HashMap efficiency.
private val hashCode = inner.musicBrainzId?.hashCode() ?: inner.name?.lowercase().hashCode()
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.

View file

@ -203,7 +203,8 @@ private data class IntelligentKnownName(override val raw: String, override val s
// Separate each token into their numeric and lexicographic counterparts.
if (token.first().isDigit()) {
// The digit string comparison breaks with preceding zero digits, remove those
val digits = token.trimStart { Character.getNumericValue(it) == 0 }.ifEmpty { token }
val digits =
token.trimStart { Character.getNumericValue(it) == 0 }.ifEmpty { token }
// Other languages have other types of digit strings, still use collation keys
collationKey = COLLATOR.getCollationKey(digits)
type = SortToken.Type.NUMERIC