From a37df594e74c4caabf1b8e0488c6e3c1b8bc31ce Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Thu, 1 Jun 2023 20:13:52 -0600 Subject: [PATCH] music: fix song build bottleneck Fix redundant separator parsing obliterating loading performance. If there are no separators configured, the parsing function would not short-circuit and instead do a useless O(n) iteraton (including escaping!), massively reducing performance. Song build performance still isn't the best (blame intelligent sorting), but it's definitely better now. --- CHANGELOG.md | 1 + .../main/java/org/oxycblt/auxio/music/MusicRepository.kt | 4 ++++ .../java/org/oxycblt/auxio/music/device/DeviceLibrary.kt | 7 +++++-- app/src/main/java/org/oxycblt/auxio/music/info/Name.kt | 2 ++ .../main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt | 4 +++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adec5f29e..8239410b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Albums implicitly linked only via "artist" tags are now placed in a special "appears on" section in the artist view - Album covers that are not 1:1 aspect ratio are no longer cropped +- Optimized library creation phase of the music loading process #### What's Fixed - Prevented options such as "Add to queue" from being selected on empty artists and playlists diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt index 8d890b218..36133c94c 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -365,6 +365,10 @@ constructor( throw NoAudioPermissionException() } + // TODO: Parallelize this even more aggressively. I can hypothetically connect all + // finalization steps (library, cache, playlists) into a single pipeline would need + // to change how I indicate progress however + // Start initializing the extractors. Use an indeterminate state, as there is no ETA on // how long a media database query will take. emitLoading(IndexingProgress.Indeterminate) 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 9add74b28..ef846c18d 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 @@ -177,9 +177,12 @@ private class DeviceLibraryImpl(rawSongs: List, settings: MusicSettings * @return A sorted list of [SongImpl]s derived from the [RawSong] that should be suitable for * grouping. */ - private fun buildSongs(rawSongs: List, settings: MusicSettings) = - Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) + private fun buildSongs(rawSongs: List, settings: MusicSettings): List { + val songs = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING) .songs(rawSongs.map { SongImpl(it, settings) }.distinctBy { it.uid }) + logD("Successfully built ${songs.size} songs") + return songs + } /** * Build a list of [Album]s from the given [Song]s. diff --git a/app/src/main/java/org/oxycblt/auxio/music/info/Name.kt b/app/src/main/java/org/oxycblt/auxio/music/info/Name.kt index 6b508f56a..838f8f5d5 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/info/Name.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/info/Name.kt @@ -174,6 +174,8 @@ private data class IntelligentKnownName(override val raw: String, override val s override val sortTokens = parseTokens(sort ?: raw) private fun parseTokens(name: String): List { + // TODO: This routine is consuming much of the song building runtime, find a way to + // optimize it val stripped = name // Remove excess punctuation from the string, as those u diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt index 62f19c61b..c4f20df4a 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagUtil.kt @@ -39,6 +39,8 @@ fun List.parseMultiValue(settings: MusicSettings) = this } +// TODO: Remove the escaping checks, it's too expensive to do this for every single tag. + /** * Split a [String] by the given selector, automatically handling escaped characters that satisfy * the selector. @@ -106,7 +108,7 @@ fun List.correctWhitespace() = mapNotNull { it.correctWhitespace() } * @return A list of one or more [String]s that were split up by the user-defined separators. */ private fun String.maybeParseBySeparators(settings: MusicSettings): List { - // Get the separators the user desires. If null, there's nothing to do. + if (settings.multiValueSeparators.isEmpty()) return listOf(this) return splitEscaped { settings.multiValueSeparators.contains(it) }.correctWhitespace() }