From e8f94564b7f35d1d6eb3608eb2240e4ef6377c29 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Wed, 13 Jul 2022 14:51:10 -0600 Subject: [PATCH] music: prepare sort tags Prepare support for sort tags by reworking how sortName is structured. Instead of rawName and sortName, music must now implement rawName and rawSortName. rawSortName will be checked first, followed by will falling back to rawName.withoutArticle. This allows hard-coded tags to be neatly implemented while avoiding an immediate copy. --- .../auxio/home/list/AlbumListFragment.kt | 2 +- .../auxio/home/list/SongListFragment.kt | 4 +-- .../java/org/oxycblt/auxio/music/Music.kt | 30 ++++++++++++------- .../auxio/music/system/ExoPlayerBackend.kt | 16 +++++----- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt index d47a23744..53031221d 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt @@ -58,7 +58,7 @@ class AlbumListFragment : HomeListFragment() { // Change how we display the popup depending on the mode. return when (homeModel.getSortForDisplay(DisplayMode.SHOW_ALBUMS).mode) { // By Name -> Use Name - is Sort.Mode.ByName -> album.sortName.first().uppercase() + is Sort.Mode.ByName -> album.sortName?.run { first().uppercase() } // By Artist -> Use Artist Name is Sort.Mode.ByArtist -> album.artist.sortName?.run { first().uppercase() } diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt index f4ccddda4..aa314b5bb 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt @@ -62,13 +62,13 @@ class SongListFragment : HomeListFragment() { // based off the names of the parent objects and not the child objects. return when (homeModel.getSortForDisplay(DisplayMode.SHOW_SONGS).mode) { // Name -> Use name - is Sort.Mode.ByName -> song.sortName.first().uppercase() + is Sort.Mode.ByName -> song.sortName?.run { first().uppercase() } // Artist -> Use Artist Name is Sort.Mode.ByArtist -> song.album.artist.sortName?.run { first().uppercase() } // Album -> Use Album Name - is Sort.Mode.ByAlbum -> song.album.sortName.first().uppercase() + is Sort.Mode.ByAlbum -> song.album.sortName?.run { first().uppercase() } // Year -> Use Full Year is Sort.Mode.ByYear -> song.album.year?.toString() diff --git a/app/src/main/java/org/oxycblt/auxio/music/Music.kt b/app/src/main/java/org/oxycblt/auxio/music/Music.kt index 3950b0607..83db4421c 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Music.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Music.kt @@ -33,8 +33,18 @@ sealed class Music : Item() { /** The raw name of this item. Null if unknown. */ abstract val rawName: String? - /** The name of this item used for sorting. Null if unknown. */ - abstract val sortName: String? + /** The raw sorting name of this item. Null if not present. */ + abstract val rawSortName: String? + + /** + * The name of this item used for sorting. This will first use the sort tag for the item, + * followed by the name without a preceding article (The/A/An). In the case that the item has no + * name, this returns null. + * + * This should not be used outside of sorting and fast-scrolling. + */ + val sortName: String? + get() = rawSortName ?: rawName?.withoutArticle /** * Resolve a name from it's raw form to a form suitable to be shown in a ui. Ex. "unknown" would @@ -99,8 +109,8 @@ data class Song( return result } - override val sortName: String - get() = rawName.withoutArticle + override val rawSortName: String? + get() = null override fun resolveName(context: Context) = rawName @@ -196,8 +206,8 @@ data class Album( return result } - override val sortName: String - get() = rawName.withoutArticle + override val rawSortName: String? + get() = null override fun resolveName(context: Context) = rawName @@ -238,8 +248,8 @@ data class Artist( override val id: Long get() = (rawName ?: MediaStore.UNKNOWN_STRING).hashCode().toLong() - override val sortName: String? - get() = rawName?.withoutArticle + override val rawSortName: String? + get() = null override fun resolveName(context: Context) = rawName ?: context.getString(R.string.def_artist) @@ -258,8 +268,8 @@ data class Genre(override val rawName: String?, override val songs: List) override val id: Long get() = (rawName ?: MediaStore.UNKNOWN_STRING).hashCode().toLong() - override val sortName: String? - get() = rawName + override val rawSortName: String? + get() = null override fun resolveName(context: Context) = rawName ?: context.getString(R.string.def_genre) } diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/ExoPlayerBackend.kt b/app/src/main/java/org/oxycblt/auxio/music/system/ExoPlayerBackend.kt index e4a953184..f0da4f46e 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/ExoPlayerBackend.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/ExoPlayerBackend.kt @@ -183,7 +183,8 @@ class Task(context: Context, private val audio: MediaStoreBackend.Audio) { } } is VorbisComment -> { - val id = tag.key.sanitize() + // Vorbis comment keys can be in any case, make them uppercase for simplicity. + val id = tag.key.sanitize().uppercase() val value = tag.value.sanitize() if (value.isNotEmpty()) { vorbisTags[id] = value @@ -223,9 +224,10 @@ class Task(context: Context, private val audio: MediaStoreBackend.Audio) { // 3. ID3v2.4 Release Date, as it is the second most common date type // 4. ID3v2.3 Original Date, as it is like #1 // 5. ID3v2.3 Release Year, as it is the most common date type - audio.year - ?: tags["TDOR"]?.iso8601year ?: tags["TDRC"]?.iso8601year ?: tags["TDRL"]?.iso8601year - ?: tags["TORY"]?.year ?: tags["TYER"]?.year + (tags["TDOR"]?.iso8601year + ?: tags["TDRC"]?.iso8601year ?: tags["TDRL"]?.iso8601year ?: tags["TORY"]?.year + ?: tags["TYER"]?.year) + ?.let { audio.year = it } // Album tags["TALB"]?.let { audio.album = it } @@ -256,8 +258,8 @@ class Task(context: Context, private val audio: MediaStoreBackend.Audio) { // 2. Date, as it is the most common date type // 3. Year, as old vorbis tags tended to use this (I know this because it's the only // tag that android supports, so it must be 15 years old or more!) - audio.year = - tags["ORIGINALDATE"]?.iso8601year ?: tags["DATE"]?.iso8601year ?: tags["YEAR"]?.year + (tags["ORIGINALDATE"]?.iso8601year ?: tags["DATE"]?.iso8601year ?: tags["YEAR"]?.year) + ?.let { audio.year = it } // Album tags["ALBUM"]?.let { audio.album = it } @@ -268,7 +270,7 @@ class Task(context: Context, private val audio: MediaStoreBackend.Audio) { // Album artist. This actually comes into two flavors: // 1. ALBUMARTIST, which is the most common // 2. ALBUM ARTIST, which is present on older vorbis tags - audio.albumArtist = tags["ALBUMARTIST"] ?: tags["ALBUM ARTIST"] + (tags["ALBUMARTIST"] ?: tags["ALBUM ARTIST"])?.let { audio.albumArtist = it } // Genre, no ID3 rules here tags["GENRE"]?.let { audio.genre = it }