diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6273ed786..738d9a66e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ at the cost of longer loading times
- Added support for sort tags [#172, dependent on this feature]
- Added support for date tags, including more fine-grained dates [#159, dependent on this feature]
- Added support for release types signifying EPs, Singles, Compilations, and more [#158, dependent on this feature]
+ - Added basic awareness of multi-value vorbis tags [#197, dependent on this feature]
- Added Last Added sorting
- Search now takes sort tags and file names in account [#184]
diff --git a/README.md b/README.md
index 9ad42ddf1..3b2e13ab4 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
A simple, rational music player for android.
-
+
@@ -11,7 +11,7 @@
-
+
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 a0c174ae1..c4d512211 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/Music.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/Music.kt
@@ -493,8 +493,9 @@ sealed class ReleaseType {
}
companion object {
- fun parse(type: String): ReleaseType {
- val types = type.split('+')
+ fun parse(type: String) = parse(type.split('+'))
+
+ fun parse(types: List): ReleaseType {
val primary = types[0].trim()
// Primary types should be the first one in sequence. The spec makes no mention of
@@ -523,8 +524,8 @@ sealed class ReleaseType {
secondary.equals("compilation", true) -> Compilation
secondary.equals("soundtrack", true) -> Soundtrack
secondary.equals("mixtape/street", true) -> Mixtape
- secondary.equals("live", true) -> target(Refinement.REMIX)
- secondary.equals("remix", true) -> target(Refinement.LIVE)
+ secondary.equals("live", true) -> target(Refinement.LIVE)
+ secondary.equals("remix", true) -> target(Refinement.REMIX)
else -> target(null)
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicUtil.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicUtil.kt
index e90c3b5f3..ce4cee322 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/MusicUtil.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/MusicUtil.kt
@@ -103,6 +103,9 @@ fun String.parseSortName() =
/** Shortcut to parse an [ReleaseType] from a string */
fun String.parseReleaseType() = ReleaseType.parse(this)
+/** Shortcut to parse a [ReleaseType] from a list of strings */
+fun List.parseReleaseType() = ReleaseType.parse(this)
+
/**
* Decodes the genre name from an ID3(v2) constant. See [GENRE_TABLE] for the genre constant map
* that Auxio uses.
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 6cfee8e7e..78fd42247 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
@@ -170,7 +170,7 @@ class Task(context: Context, private val audio: MediaStoreBackend.Audio) {
private fun completeAudio(metadata: Metadata) {
val id3v2Tags = mutableMapOf()
- val vorbisTags = mutableMapOf()
+ val vorbisTags = mutableMapOf>()
// ExoPlayer only exposes ID3v2 and Vorbis metadata, which constitutes the vast majority
// of audio formats. Load both of these types of tags into separate maps, letting the
@@ -189,7 +189,11 @@ class Task(context: Context, private val audio: MediaStoreBackend.Audio) {
val id = tag.key.sanitize().uppercase()
val value = tag.value.sanitize()
if (value.isNotEmpty()) {
- vorbisTags[id] = value
+ if (vorbisTags.containsKey(id)) {
+ vorbisTags[id]!!.add(value)
+ } else {
+ vorbisTags[id] = mutableListOf(value)
+ }
}
}
}
@@ -274,16 +278,16 @@ class Task(context: Context, private val audio: MediaStoreBackend.Audio) {
}
}
- private fun populateVorbis(tags: Map) {
+ private fun populateVorbis(tags: Map>) {
// (Sort) Title
- tags["TITLE"]?.let { audio.title = it }
- tags["TITLESORT"]?.let { audio.sortTitle = it }
+ tags["TITLE"]?.let { audio.title = it[0] }
+ tags["TITLESORT"]?.let { audio.sortTitle = it[0] }
// Track
- tags["TRACKNUMBER"]?.parsePositionNum()?.let { audio.track = it }
+ tags["TRACKNUMBER"]?.run { get(0).parsePositionNum() }?.let { audio.track = it }
// Disc
- tags["DISCNUMBER"]?.parsePositionNum()?.let { audio.disc = it }
+ tags["DISCNUMBER"]?.run { get(0).parsePositionNum() }?.let { audio.disc = it }
// Vorbis dates are less complicated, but there are still several types
// Our hierarchy for dates is as such:
@@ -291,24 +295,25 @@ 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!)
- (tags["ORIGINALDATE"]?.parseTimestamp()
- ?: tags["DATE"]?.parseTimestamp() ?: tags["YEAR"]?.parseYear())
+ (tags["ORIGINALDATE"]?.run { get(0).parseTimestamp() }
+ ?: tags["DATE"]?.run { get(0).parseTimestamp() }
+ ?: tags["YEAR"]?.run { get(0).parseYear() })
?.let { audio.date = it }
// (Sort) Album
- tags["ALBUM"]?.let { audio.album = it }
- tags["ALBUMSORT"]?.let { audio.sortAlbum = it }
+ tags["ALBUM"]?.let { audio.album = it.joinToString() }
+ tags["ALBUMSORT"]?.let { audio.sortAlbum = it.joinToString() }
// (Sort) Artist
- tags["ARTIST"]?.let { audio.artist = it }
- tags["ARTISTSORT"]?.let { audio.sortArtist = it }
+ tags["ARTIST"]?.let { audio.artist = it.joinToString() }
+ tags["ARTISTSORT"]?.let { audio.sortArtist = it.joinToString() }
// (Sort) Album artist
- tags["ALBUMARTIST"]?.let { audio.albumArtist = it }
- tags["ALBUMARTISTSORT"]?.let { audio.sortAlbumArtist = it }
+ tags["ALBUMARTIST"]?.let { audio.albumArtist = it.joinToString() }
+ tags["ALBUMARTISTSORT"]?.let { audio.sortAlbumArtist = it.joinToString() }
// Genre, no ID3 rules here
- tags["GENRE"]?.let { audio.genre = it }
+ tags["GENRE"]?.let { audio.genre = it.joinToString() }
// Release type
tags["RELEASETYPE"]?.parseReleaseType()?.let { audio.releaseType = it }