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:
parent
e848bea0bf
commit
672c256b1e
3 changed files with 19 additions and 16 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue