music: fix music loading crash with weird genres

Fix an issue where genres consisting only of whitespace crash the genre
parser, and thus the music loader.

Band-aid this by moving the trimming code out of splitEscaped and into
maybeParseSeparators. In a future version I'll need to figure out how I
want to handle these weird edge cases.
This commit is contained in:
Alexander Capehart 2022-12-29 21:09:35 -07:00
parent 6db50a0e45
commit 05cf0f7261
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 23 additions and 21 deletions

View file

@ -51,7 +51,7 @@ audio focus was lost
- Switched to issue forms
- Completed migration to reactive playback system
- Refactor music backends into a unified chain of extractors
- Add bluetooth connection reciever (No functionality in app yet)
- Add bluetooth connection receiver (No functionality in app yet)
## 2.6.4

View file

@ -283,8 +283,8 @@ private class CacheDatabase(context: Context) :
raw.albumMusicBrainzId = cursor.getStringOrNull(albumMusicBrainzIdIndex)
raw.albumName = cursor.getString(albumNameIndex)
raw.albumSortName = cursor.getStringOrNull(albumSortNameIndex)
cursor.getStringOrNull(albumTypesIndex)?.parseSQLMultiValue()?.let {
raw.albumTypes = it
cursor.getStringOrNull(albumTypesIndex)?.let {
raw.albumTypes = it.parseSQLMultiValue()
}
cursor.getStringOrNull(artistMusicBrainzIdsIndex)?.let {
@ -387,7 +387,8 @@ private class CacheDatabase(context: Context) :
* @return A list of strings corresponding to the delimited values present within the original
* string. Escaped delimiters are converted back into their normal forms.
*/
private fun String.parseSQLMultiValue() = splitEscaped { it == ';' }
private fun String.parseSQLMultiValue() =
splitEscaped { it == ';' }
/** Defines the columns used in this database. */
private object Columns {

View file

@ -187,8 +187,8 @@ class Task(context: Context, private val raw: Song.Raw) {
// Map TXXX frames differently so we can specifically index by their
// descriptions.
val id = tag.description?.let { "TXXX:${it.sanitize()}" } ?: tag.id.sanitize()
val values = tag.values.map { it.sanitize() }
if (values.isNotEmpty() && values.all { it.isNotEmpty() }) {
val values = tag.values.map { it.sanitize() }.filter { it.isNotEmpty() }
if (values.isNotEmpty()) {
id3v2Tags[id] = values
}
}

View file

@ -21,6 +21,7 @@ import androidx.core.text.isDigitsOnly
import java.util.UUID
import org.oxycblt.auxio.music.Date
import org.oxycblt.auxio.settings.Settings
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.nonZeroOrNull
/**
@ -88,7 +89,7 @@ inline fun String.splitEscaped(selector: (Char) -> Boolean): List<String> {
if (selector(a)) {
// Non-escaped separator, split the string here, making sure any stray whitespace
// is removed.
split.add(currentString.trim())
split.add(currentString)
currentString = ""
i++
continue
@ -107,8 +108,8 @@ inline fun String.splitEscaped(selector: (Char) -> Boolean): List<String> {
}
if (currentString.isNotEmpty()) {
// Had an in-progress split string that is now terminated, add it..
split.add(currentString.trim())
// Had an in-progress split string that is now terminated, add it.
split.add(currentString)
}
return split
@ -126,7 +127,7 @@ fun List<String>.parseMultiValue(settings: Settings) =
get(0).maybeParseSeparators(settings)
} else {
// Nothing to do.
this
this.map { it.trim() }
}
/**
@ -137,7 +138,7 @@ fun List<String>.parseMultiValue(settings: Settings) =
fun String.maybeParseSeparators(settings: Settings): List<String> {
// Get the separators the user desires. If null, there's nothing to do.
val separators = settings.musicSeparators ?: return listOf(this)
return splitEscaped { separators.contains(it) }
return splitEscaped { separators.contains(it) }.map { it.trim() }
}
/**
@ -179,20 +180,20 @@ fun String.parseId3GenreNames(settings: Settings) =
* @return A named genre if the field is a valid integer, "Cover" or "Remix" if the field is
* "CR"/"RX" respectively, and nothing if the field is not a valid ID3v1 integer genre.
*/
private fun String.parseId3v1Genre(): String? =
when {
// ID3v1 genres are a plain integer value without formatting, so in that case
// try to index the genre table with such.
isDigitsOnly() -> GENRE_TABLE.getOrNull(toInt())
private fun String.parseId3v1Genre(): String? {
// ID3v1 genres are a plain integer value without formatting, so in that case
// try to index the genre table with such. If this fails, then try to compare it
// to some other hard-coded values.
val numeric = toIntOrNull() ?: return when (this) {
// CR and RX are not technically ID3v1, but are formatted similarly to a plain number.
this == "CR" -> "Cover"
this == "RX" -> "Remix"
// Current name is fine.
"CR" -> "Cover"
"RX" -> "Remix"
else -> null
}
return GENRE_TABLE.getOrNull(numeric)
}
/**
* A [Regex] that implements parsing for ID3v2's genre format. Derived from mutagen:
* https://github.com/quodlibet/mutagen