music: consider settings in equality
Make it so that music items are meaningfully different when they were created under different settings. This resolves an issue where music information would not correctly update when separators or intelligent sorting would change. Resolves #546.
This commit is contained in:
parent
9a67a0d539
commit
881fb58648
3 changed files with 61 additions and 23 deletions
|
@ -1,5 +1,11 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## dev
|
||||||
|
|
||||||
|
#### What's Fixed
|
||||||
|
- Fixed app restart being required when changing intelligent sorting
|
||||||
|
or music separator settings
|
||||||
|
|
||||||
## 3.2.0
|
## 3.2.0
|
||||||
|
|
||||||
#### What's New
|
#### What's New
|
||||||
|
|
|
@ -53,8 +53,8 @@ import org.oxycblt.auxio.util.update
|
||||||
*/
|
*/
|
||||||
class SongImpl(
|
class SongImpl(
|
||||||
private val rawSong: RawSong,
|
private val rawSong: RawSong,
|
||||||
nameFactory: Name.Known.Factory,
|
private val nameFactory: Name.Known.Factory,
|
||||||
separators: Separators
|
private val separators: Separators
|
||||||
) : Song {
|
) : Song {
|
||||||
override val uid =
|
override val uid =
|
||||||
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
||||||
|
@ -110,17 +110,6 @@ class SongImpl(
|
||||||
override val genres: List<Genre>
|
override val genres: List<Genre>
|
||||||
get() = _genres
|
get() = _genres
|
||||||
|
|
||||||
private val hashCode = 31 * uid.hashCode() + rawSong.hashCode()
|
|
||||||
|
|
||||||
override fun hashCode() = hashCode
|
|
||||||
|
|
||||||
// TODO: I cant compare by raw information actually, as it also means that any settings
|
|
||||||
// configuration will be lost as well.
|
|
||||||
override fun equals(other: Any?) =
|
|
||||||
other is SongImpl && uid == other.uid && rawSong == other.rawSong
|
|
||||||
|
|
||||||
override fun toString() = "Song(uid=$uid, name=$name)"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [RawAlbum] instances collated by the [Song]. This can be used to group [Song]s into an
|
* The [RawAlbum] instances collated by the [Song]. This can be used to group [Song]s into an
|
||||||
* [Album].
|
* [Album].
|
||||||
|
@ -140,6 +129,8 @@ class SongImpl(
|
||||||
*/
|
*/
|
||||||
val rawGenres: List<RawGenre>
|
val rawGenres: List<RawGenre>
|
||||||
|
|
||||||
|
private var hashCode: Int = uid.hashCode()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val artistMusicBrainzIds = separators.split(rawSong.artistMusicBrainzIds)
|
val artistMusicBrainzIds = separators.split(rawSong.artistMusicBrainzIds)
|
||||||
val artistNames = separators.split(rawSong.artistNames)
|
val artistNames = separators.split(rawSong.artistNames)
|
||||||
|
@ -190,8 +181,24 @@ class SongImpl(
|
||||||
.mapTo(mutableSetOf()) { RawGenre(it) }
|
.mapTo(mutableSetOf()) { RawGenre(it) }
|
||||||
.toList()
|
.toList()
|
||||||
.ifEmpty { listOf(RawGenre()) }
|
.ifEmpty { listOf(RawGenre()) }
|
||||||
|
|
||||||
|
hashCode = 31 * rawSong.hashCode()
|
||||||
|
hashCode = 31 * nameFactory.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun hashCode() = hashCode
|
||||||
|
|
||||||
|
// Since equality on public-facing music models is not identical to the tag equality,
|
||||||
|
// we just compare raw instances and how they are interpreted.
|
||||||
|
override fun equals(other: Any?) =
|
||||||
|
other is SongImpl &&
|
||||||
|
uid == other.uid &&
|
||||||
|
nameFactory == other.nameFactory &&
|
||||||
|
separators == other.separators &&
|
||||||
|
rawSong == other.rawSong
|
||||||
|
|
||||||
|
override fun toString() = "Song(uid=$uid, name=$name)"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Links this [Song] with a parent [Album].
|
* Links this [Song] with a parent [Album].
|
||||||
*
|
*
|
||||||
|
@ -259,7 +266,10 @@ class SongImpl(
|
||||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class AlbumImpl(grouping: Grouping<RawAlbum, SongImpl>, nameFactory: Name.Known.Factory) : Album {
|
class AlbumImpl(
|
||||||
|
grouping: Grouping<RawAlbum, SongImpl>,
|
||||||
|
private val nameFactory: Name.Known.Factory
|
||||||
|
) : Album {
|
||||||
private val rawAlbum = grouping.raw.inner
|
private val rawAlbum = grouping.raw.inner
|
||||||
|
|
||||||
override val uid =
|
override val uid =
|
||||||
|
@ -322,13 +332,20 @@ class AlbumImpl(grouping: Grouping<RawAlbum, SongImpl>, nameFactory: Name.Known.
|
||||||
dateAdded = earliestDateAdded
|
dateAdded = earliestDateAdded
|
||||||
|
|
||||||
hashCode = 31 * hashCode + rawAlbum.hashCode()
|
hashCode = 31 * hashCode + rawAlbum.hashCode()
|
||||||
|
hashCode = 31 * nameFactory.hashCode()
|
||||||
hashCode = 31 * hashCode + songs.hashCode()
|
hashCode = 31 * hashCode + songs.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode() = hashCode
|
override fun hashCode() = hashCode
|
||||||
|
|
||||||
|
// Since equality on public-facing music models is not identical to the tag equality,
|
||||||
|
// we just compare raw instances and how they are interpreted.
|
||||||
override fun equals(other: Any?) =
|
override fun equals(other: Any?) =
|
||||||
other is AlbumImpl && uid == other.uid && rawAlbum == other.rawAlbum && songs == other.songs
|
other is AlbumImpl &&
|
||||||
|
uid == other.uid &&
|
||||||
|
rawAlbum == other.rawAlbum &&
|
||||||
|
nameFactory == other.nameFactory &&
|
||||||
|
songs == other.songs
|
||||||
|
|
||||||
override fun toString() = "Album(uid=$uid, name=$name)"
|
override fun toString() = "Album(uid=$uid, name=$name)"
|
||||||
|
|
||||||
|
@ -376,7 +393,10 @@ class AlbumImpl(grouping: Grouping<RawAlbum, SongImpl>, nameFactory: Name.Known.
|
||||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class ArtistImpl(grouping: Grouping<RawArtist, Music>, nameFactory: Name.Known.Factory) : Artist {
|
class ArtistImpl(
|
||||||
|
grouping: Grouping<RawArtist, Music>,
|
||||||
|
private val nameFactory: Name.Known.Factory
|
||||||
|
) : Artist {
|
||||||
private val rawArtist = grouping.raw.inner
|
private val rawArtist = grouping.raw.inner
|
||||||
|
|
||||||
override val uid =
|
override val uid =
|
||||||
|
@ -425,6 +445,7 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, nameFactory: Name.Known.F
|
||||||
durationMs = songs.sumOf { it.durationMs }.positiveOrNull()
|
durationMs = songs.sumOf { it.durationMs }.positiveOrNull()
|
||||||
|
|
||||||
hashCode = 31 * hashCode + rawArtist.hashCode()
|
hashCode = 31 * hashCode + rawArtist.hashCode()
|
||||||
|
hashCode = 31 * hashCode + nameFactory.hashCode()
|
||||||
hashCode = 31 * hashCode + songs.hashCode()
|
hashCode = 31 * hashCode + songs.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,10 +453,13 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, nameFactory: Name.Known.F
|
||||||
// the same UID but different songs are not equal.
|
// the same UID but different songs are not equal.
|
||||||
override fun hashCode() = hashCode
|
override fun hashCode() = hashCode
|
||||||
|
|
||||||
|
// Since equality on public-facing music models is not identical to the tag equality,
|
||||||
|
// we just compare raw instances and how they are interpreted.
|
||||||
override fun equals(other: Any?) =
|
override fun equals(other: Any?) =
|
||||||
other is ArtistImpl &&
|
other is ArtistImpl &&
|
||||||
uid == other.uid &&
|
uid == other.uid &&
|
||||||
rawArtist == other.rawArtist &&
|
rawArtist == other.rawArtist &&
|
||||||
|
nameFactory == other.nameFactory &&
|
||||||
songs == other.songs
|
songs == other.songs
|
||||||
|
|
||||||
override fun toString() = "Artist(uid=$uid, name=$name)"
|
override fun toString() = "Artist(uid=$uid, name=$name)"
|
||||||
|
@ -473,7 +497,10 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, nameFactory: Name.Known.F
|
||||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class GenreImpl(grouping: Grouping<RawGenre, SongImpl>, nameFactory: Name.Known.Factory) : Genre {
|
class GenreImpl(
|
||||||
|
grouping: Grouping<RawGenre, SongImpl>,
|
||||||
|
private val nameFactory: Name.Known.Factory
|
||||||
|
) : Genre {
|
||||||
private val rawGenre = grouping.raw.inner
|
private val rawGenre = grouping.raw.inner
|
||||||
|
|
||||||
override val uid = Music.UID.auxio(MusicType.GENRES) { update(rawGenre.name) }
|
override val uid = Music.UID.auxio(MusicType.GENRES) { update(rawGenre.name) }
|
||||||
|
@ -502,13 +529,18 @@ class GenreImpl(grouping: Grouping<RawGenre, SongImpl>, nameFactory: Name.Known.
|
||||||
durationMs = totalDuration
|
durationMs = totalDuration
|
||||||
|
|
||||||
hashCode = 31 * hashCode + rawGenre.hashCode()
|
hashCode = 31 * hashCode + rawGenre.hashCode()
|
||||||
|
hashCode = 31 * nameFactory.hashCode()
|
||||||
hashCode = 31 * hashCode + songs.hashCode()
|
hashCode = 31 * hashCode + songs.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode() = hashCode
|
override fun hashCode() = hashCode
|
||||||
|
|
||||||
override fun equals(other: Any?) =
|
override fun equals(other: Any?) =
|
||||||
other is GenreImpl && uid == other.uid && rawGenre == other.rawGenre && songs == other.songs
|
other is GenreImpl &&
|
||||||
|
uid == other.uid &&
|
||||||
|
rawGenre == other.rawGenre &&
|
||||||
|
nameFactory == other.nameFactory &&
|
||||||
|
songs == other.songs
|
||||||
|
|
||||||
override fun toString() = "Genre(uid=$uid, name=$name)"
|
override fun toString() = "Genre(uid=$uid, name=$name)"
|
||||||
|
|
||||||
|
|
|
@ -95,13 +95,13 @@ sealed interface Name : Comparable<Name> {
|
||||||
* user-defined name configuration.
|
* user-defined name configuration.
|
||||||
*
|
*
|
||||||
* @param settings The [MusicSettings] to use.
|
* @param settings The [MusicSettings] to use.
|
||||||
* @return A new [Factory] instance reflecting the configuration state.
|
* @return A [Factory] instance reflecting the configuration state.
|
||||||
*/
|
*/
|
||||||
fun from(settings: MusicSettings) =
|
fun from(settings: MusicSettings) =
|
||||||
if (settings.intelligentSorting) {
|
if (settings.intelligentSorting) {
|
||||||
IntelligentKnownName.Factory()
|
IntelligentKnownName.Factory
|
||||||
} else {
|
} else {
|
||||||
SimpleKnownName.Factory()
|
SimpleKnownName.Factory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ data class SimpleKnownName(override val raw: String, override val sort: String?)
|
||||||
return SortToken(collationKey, SortToken.Type.LEXICOGRAPHIC)
|
return SortToken(collationKey, SortToken.Type.LEXICOGRAPHIC)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Factory : Name.Known.Factory {
|
data object Factory : Name.Known.Factory {
|
||||||
override fun parse(raw: String, sort: String?) = SimpleKnownName(raw, sort)
|
override fun parse(raw: String, sort: String?) = SimpleKnownName(raw, sort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ data class IntelligentKnownName(override val raw: String, override val sort: Str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Factory : Name.Known.Factory {
|
data object Factory : Name.Known.Factory {
|
||||||
override fun parse(raw: String, sort: String?) = IntelligentKnownName(raw, sort)
|
override fun parse(raw: String, sort: String?) = IntelligentKnownName(raw, sort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue