diff --git a/app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt b/app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt index b53d0a00b..96f4915b7 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt @@ -170,19 +170,21 @@ private class DeviceLibraryImpl(rawSongs: List, settings: MusicSettings } private fun buildSongs(rawSongs: List, settings: MusicSettings): List { + val start = System.currentTimeMillis() val songs = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) .songs(rawSongs.map { SongImpl(it, settings) }.distinctBy { it.uid }) - logD("Successfully built ${songs.size} songs") + logD("Successfully built ${songs.size} songs in ${System.currentTimeMillis() - start}ms") return songs } private fun buildAlbums(songs: List, settings: MusicSettings): List { + val start = System.currentTimeMillis() // Group songs by their singular raw album, then map the raw instances and their // grouped songs to Album values. Album.Raw will handle the actual grouping rules. val songsByAlbum = songs.groupBy { it.rawAlbum.key } val albums = songsByAlbum.map { AlbumImpl(it.key.value, settings, it.value) } - logD("Successfully built ${albums.size} albums") + logD("Successfully built ${albums.size} albums in ${System.currentTimeMillis() - start}ms") return albums } @@ -191,6 +193,7 @@ private class DeviceLibraryImpl(rawSongs: List, settings: MusicSettings albums: List, settings: MusicSettings ): List { + val start = System.currentTimeMillis() // Add every raw artist credited to each Song/Album to the grouping. This way, // different multi-artist combinations are not treated as different artists. // Songs and albums are grouped by artist and album artist respectively. @@ -210,11 +213,13 @@ private class DeviceLibraryImpl(rawSongs: List, settings: MusicSettings // Convert the combined mapping into artist instances. val artists = musicByArtist.map { ArtistImpl(it.key.value, settings, it.value) } - logD("Successfully built ${artists.size} artists") + logD( + "Successfully built ${artists.size} artists in ${System.currentTimeMillis() - start}ms") return artists } private fun buildGenres(songs: List, settings: MusicSettings): List { + val start = System.currentTimeMillis() // Add every raw genre credited to each Song to the grouping. This way, // different multi-genre combinations are not treated as different genres. val songsByGenre = mutableMapOf>() @@ -226,7 +231,7 @@ private class DeviceLibraryImpl(rawSongs: List, settings: MusicSettings // Convert the mapping into genre instances. val genres = songsByGenre.map { GenreImpl(it.key.value, settings, it.value) } - logD("Successfully built ${genres.size} genres") + logD("Successfully built ${genres.size} genres in ${System.currentTimeMillis() - start}ms") return genres } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/device/DeviceMusicImpl.kt b/app/src/main/java/org/oxycblt/auxio/music/device/DeviceMusicImpl.kt index ed73bf885..530f35530 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/device/DeviceMusicImpl.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/device/DeviceMusicImpl.kt @@ -93,7 +93,9 @@ class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Son override val album: Album get() = unlikelyToBeNull(_album) - override fun hashCode() = 31 * uid.hashCode() + rawSong.hashCode() + private val hashCode = 31 * uid.hashCode() + rawSong.hashCode() + + override fun hashCode() = hashCode override fun equals(other: Any?) = other is SongImpl && uid == other.uid && rawSong == other.rawSong override fun toString() = "Song(uid=$uid, name=$name)" @@ -253,22 +255,12 @@ class AlbumImpl( override val durationMs: Long override val dateAdded: Long - override fun hashCode(): Int { - var hashCode = uid.hashCode() - hashCode = 31 * hashCode + rawAlbum.hashCode() - hashCode = 31 * hashCode + songs.hashCode() - return hashCode - } - - override fun equals(other: Any?) = - other is AlbumImpl && uid == other.uid && rawAlbum == other.rawAlbum && songs == other.songs - - override fun toString() = "Album(uid=$uid, name=$name)" - private val _artists = mutableListOf() override val artists: List get() = _artists + private var hashCode = uid.hashCode() + init { var totalDuration: Long = 0 var earliestDateAdded: Long = Long.MAX_VALUE @@ -284,8 +276,16 @@ class AlbumImpl( durationMs = totalDuration dateAdded = earliestDateAdded + + hashCode = 31 * hashCode + rawAlbum.hashCode() + hashCode = 31 * hashCode + songs.hashCode() } + override fun hashCode() = hashCode + override fun equals(other: Any?) = + other is AlbumImpl && uid == other.uid && rawAlbum == other.rawAlbum && songs == other.songs + override fun toString() = "Album(uid=$uid, name=$name)" + /** * The [RawArtist] instances collated by the [Album]. The album artists of the song take * priority, followed by the artists. If there are no artists, this field will be a single @@ -351,25 +351,10 @@ class ArtistImpl( override val implicitAlbums: List override val durationMs: Long? - // Note: Append song contents to MusicParent equality so that artists with - // the same UID but different songs are not equal. - override fun hashCode(): Int { - var hashCode = uid.hashCode() - hashCode = 31 * hashCode + rawArtist.hashCode() - hashCode = 31 * hashCode + songs.hashCode() - return hashCode - } - - override fun equals(other: Any?) = - other is ArtistImpl && - uid == other.uid && - rawArtist == other.rawArtist && - songs == other.songs - - override fun toString() = "Artist(uid=$uid, name=$name)" - override lateinit var genres: List + private var hashCode = uid.hashCode() + init { val distinctSongs = mutableSetOf() val albumMap = mutableMapOf() @@ -396,8 +381,23 @@ class ArtistImpl( explicitAlbums = albums.filter { unlikelyToBeNull(albumMap[it]) } implicitAlbums = albums.filterNot { unlikelyToBeNull(albumMap[it]) } durationMs = songs.sumOf { it.durationMs }.nonZeroOrNull() + + hashCode = 31 * hashCode + rawArtist.hashCode() + hashCode = 31 * hashCode + songs.hashCode() } + // Note: Append song contents to MusicParent equality so that artists with + // the same UID but different songs are not equal. + override fun hashCode() = hashCode + + override fun equals(other: Any?) = + other is ArtistImpl && + uid == other.uid && + rawArtist == other.rawArtist && + songs == other.songs + + override fun toString() = "Artist(uid=$uid, name=$name)" + /** * Returns the original position of this [Artist]'s [RawArtist] within the given [RawArtist] * list. This can be used to create a consistent ordering within child [Artist] lists based on @@ -445,17 +445,7 @@ class GenreImpl( override val artists: List override val durationMs: Long - override fun hashCode(): Int { - var hashCode = uid.hashCode() - hashCode = 31 * hashCode + rawGenre.hashCode() - hashCode = 31 * hashCode + songs.hashCode() - return hashCode - } - - override fun equals(other: Any?) = - other is GenreImpl && uid == other.uid && rawGenre == other.rawGenre && songs == other.songs - - override fun toString() = "Genre(uid=$uid, name=$name)" + private var hashCode = uid.hashCode() init { val distinctAlbums = mutableSetOf() @@ -471,8 +461,17 @@ class GenreImpl( artists = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).artists(distinctArtists) durationMs = totalDuration + hashCode = 31 * hashCode + rawGenre.hashCode() + hashCode = 31 * hashCode + songs.hashCode() } + override fun hashCode() = hashCode + + override fun equals(other: Any?) = + other is GenreImpl && uid == other.uid && rawGenre == other.rawGenre && songs == other.songs + + override fun toString() = "Genre(uid=$uid, name=$name)" + /** * Returns the original position of this [Genre]'s [RawGenre] within the given [RawGenre] list. * This can be used to create a consistent ordering within child [Genre] lists based on the diff --git a/app/src/main/java/org/oxycblt/auxio/music/fs/MediaStoreExtractor.kt b/app/src/main/java/org/oxycblt/auxio/music/fs/MediaStoreExtractor.kt index 4e8faae19..42e29eed2 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/fs/MediaStoreExtractor.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/fs/MediaStoreExtractor.kt @@ -186,8 +186,8 @@ private abstract class BaseMediaStoreExtractor( } } } - logD("Read ${genreNamesMap.size} genres from MediaStore") + logD("Read ${genreNamesMap.values.distinct().size} genres from MediaStore") logD("Finished initialization in ${System.currentTimeMillis() - start}ms") return wrapQuery(cursor, genreNamesMap) } diff --git a/app/src/main/java/org/oxycblt/auxio/music/info/Date.kt b/app/src/main/java/org/oxycblt/auxio/music/info/Date.kt index 1d717ad43..b47f580db 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/info/Date.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/info/Date.kt @@ -73,10 +73,9 @@ class Date private constructor(private val tokens: List) : Comparable return format.format(date) } - override fun hashCode() = tokens.hashCode() - override fun equals(other: Any?) = other is Date && compareTo(other) == 0 - + override fun hashCode() = tokens.hashCode() + override fun toString() = StringBuilder().appendDate().toString() override fun compareTo(other: Date): Int { for (i in 0 until max(tokens.size, other.tokens.size)) { val ai = tokens.getOrNull(i) @@ -97,8 +96,6 @@ class Date private constructor(private val tokens: List) : Comparable return 0 } - override fun toString() = StringBuilder().appendDate().toString() - private fun StringBuilder.appendDate(): StringBuilder { // Construct an ISO-8601 date, dropping precision that doesn't exist. append(year.toStringFixed(4)) diff --git a/app/src/main/java/org/oxycblt/auxio/music/user/PlaylistImpl.kt b/app/src/main/java/org/oxycblt/auxio/music/user/PlaylistImpl.kt index 5f7036c5f..9ad14f411 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/user/PlaylistImpl.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/user/PlaylistImpl.kt @@ -33,6 +33,17 @@ private constructor( override val songs: List ) : Playlist { override val durationMs = songs.sumOf { it.durationMs } + private var hashCode = uid.hashCode() + + init { + hashCode = 31 * hashCode + name.hashCode() + hashCode = 31 * hashCode + songs.hashCode() + } + + override fun equals(other: Any?) = + other is PlaylistImpl && uid == other.uid && name == other.name && songs == other.songs + override fun hashCode() = hashCode + override fun toString() = "Playlist(uid=$uid, name=$name)" /** * Clone the data in this instance to a new [PlaylistImpl] with the given [name]. @@ -57,18 +68,6 @@ private constructor( */ inline fun edit(edits: MutableList.() -> Unit) = edit(songs.toMutableList().apply(edits)) - override fun equals(other: Any?) = - other is PlaylistImpl && uid == other.uid && name == other.name && songs == other.songs - - override fun hashCode(): Int { - var hashCode = uid.hashCode() - hashCode = 31 * hashCode + name.hashCode() - hashCode = 31 * hashCode + songs.hashCode() - return hashCode - } - - override fun toString() = "Playlist(uid=$uid, name=$name)" - companion object { /** * Create a new instance with a novel UID.