Improve genre compatibility

Add a new range of Winamp 5.6+ genres to further improve compatibility with old genres.
This commit is contained in:
OxygenCobalt 2021-03-05 11:20:22 -07:00
parent 58ec1ce293
commit fab377eba4
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 52 additions and 32 deletions

View file

@ -28,6 +28,7 @@ android {
applicationIdSuffix = '.debug' applicationIdSuffix = '.debug'
versionNameSuffix = "-DEBUG" versionNameSuffix = "-DEBUG"
} }
release { release {
minifyEnabled true minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
@ -62,7 +63,7 @@ dependencies {
// General // General
implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.activity:activity-ktx:1.3.0-alpha02' implementation 'androidx.activity:activity-ktx:1.3.0-alpha03'
implementation 'androidx.fragment:fragment-ktx:1.3.0' implementation 'androidx.fragment:fragment-ktx:1.3.0'
// Layout // Layout

View file

@ -26,11 +26,13 @@ sealed class Parent : BaseModel() {
/** /**
* The data object for a song. Inherits [BaseModel]. * The data object for a song. Inherits [BaseModel].
* @property fileName The raw filename for this track * @property fileName The raw filename for this track
* @property albumId The Song's Album ID. Never use this outside of when attaching a song to its album. * @property albumId The Song's Album ID.
* Never use this outside of when attaching a song to its album.
* @property track The Song's Track number * @property track The Song's Track number
* @property duration The duration of the song, in millis. * @property duration The duration of the song, in millis.
* @property album The Song's parent album. Use this instead of [albumId]. * @property album The Song's parent album. Use this instead of [albumId].
* @property genre The Song's [Genre] * @property genre The Song's [Genre].
* These are not ensured to be linked due to possible quirks in the genre loading system.
* @property seconds The Song's duration in seconds * @property seconds The Song's duration in seconds
* @property formattedDuration The Song's duration as a duration string. * @property formattedDuration The Song's duration as a duration string.
*/ */
@ -86,7 +88,8 @@ data class Album(
private val mSongs = mutableListOf<Song>() private val mSongs = mutableListOf<Song>()
val songs: List<Song> get() = mSongs val songs: List<Song> get() = mSongs
val totalDuration: String get() = songs.sumOf { it.seconds }.toDuration() val totalDuration: String get() =
songs.sumOf { it.seconds }.toDuration()
fun linkArtist(artist: Artist) { fun linkArtist(artist: Artist) {
mArtist = artist mArtist = artist
@ -118,6 +121,8 @@ data class Artist(
} }
val genre: Genre? by lazy { val genre: Genre? by lazy {
// Get the genre that corresponds to the most songs in this artist, which would be
// the most "Prominent" genre.
songs.groupBy { it.genre }.entries.maxByOrNull { it.value.size }?.key songs.groupBy { it.genre }.entries.maxByOrNull { it.value.size }?.key
} }
@ -135,18 +140,15 @@ data class Genre(
override val id: Long = -1, override val id: Long = -1,
override val name: String, override val name: String,
) : Parent() { ) : Parent() {
val resolvedName: String by lazy {
if (name.contains(Regex("([1-9])"))) {
name.toNamedGenre() ?: name
} else {
name
}
}
private val mSongs = mutableListOf<Song>() private val mSongs = mutableListOf<Song>()
val songs: List<Song> get() = mSongs val songs: List<Song> get() = mSongs
val totalDuration: String get() = songs.sumOf { it.seconds }.toDuration() val resolvedName: String by lazy {
name.getGenreNameCompat() ?: name
}
val totalDuration: String get() =
songs.sumOf { it.seconds }.toDuration()
fun linkSong(song: Song) { fun linkSong(song: Song) {
mSongs.add(song) mSongs.add(song)

View file

@ -191,8 +191,9 @@ class MusicLoader(private val context: Context) {
artists.add( artists.add(
// IDs are incremented from the minimum int value so that they remain unique. // IDs are incremented from the minimum int value so that they remain unique.
Artist( Artist(
id = (artists.size + Int.MIN_VALUE).toLong(), id = (Int.MIN_VALUE + artists.size).toLong(),
name = entry.key, albums = entry.value name = entry.key,
albums = entry.value
) )
) )
} }

View file

@ -84,9 +84,7 @@ class MusicStore private constructor() {
* @return The corresponding [Song] for this [uri], null if there isnt one. * @return The corresponding [Song] for this [uri], null if there isnt one.
*/ */
fun getSongForUri(uri: Uri, resolver: ContentResolver): Song? { fun getSongForUri(uri: Uri, resolver: ContentResolver): Song? {
resolver.query( resolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursor ->
uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null
)?.use { cursor ->
cursor.moveToFirst() cursor.moveToFirst()
val fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)) val fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))

View file

@ -7,6 +7,7 @@ import android.provider.MediaStore
import android.text.format.DateUtils import android.text.format.DateUtils
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.TextView import android.widget.TextView
import androidx.core.text.isDigitsOnly
import androidx.databinding.BindingAdapter import androidx.databinding.BindingAdapter
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.recycler.SortMode import org.oxycblt.auxio.recycler.SortMode
@ -17,6 +18,7 @@ import org.oxycblt.auxio.ui.getPlural
* There are a lot more int-genre extensions as far as Im aware, but this works for most cases. * There are a lot more int-genre extensions as far as Im aware, but this works for most cases.
*/ */
private val ID3_GENRES = arrayOf( private val ID3_GENRES = arrayOf(
// ID3 Standard
"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz",
"Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
"Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno",
@ -28,6 +30,7 @@ private val ID3_GENRES = arrayOf(
"Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal",
"Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
// Winamp Extensions
"Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival",
"Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
"Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour",
@ -37,26 +40,41 @@ private val ID3_GENRES = arrayOf(
"Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
"Britpop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black Metal", "Britpop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black Metal",
"Crossover", "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Crossover", "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
"Anime", "JPop", "Synthpop" "Anime", "JPop", "Synthpop",
)
private const val PAREN_FILTER = "()" // Winamp 5.6+ extensions, used by EasyTAG and friends
"Abstract", "Art Rock", "Baroque", "Bhangra", "Big Beat", "Breakbeat", "Chillout", "Downtempo",
"Dub", "EBM", "Eclectic", "Electro", "Electroclash", "Emo", "Experimental", "Garage", "Global",
"IDM", "Illbient", "Industro-Goth", "Jam Band", "Krautrock", "Leftfield", "Lounge", "Math Rock", // S I X T Y F I V E
"New Romantic", "Nu-Breakz", "Post-Punk", "Post-Rock", "Psytrance", "Shoegaze", "Space Rock",
"Trop Rock", "World Music", "Neoclassical", "Audiobook", "Audio Theatre", "Neue Deutsche Welle",
"Podcast", "Indie Rock", "G-Funk", "Dubstep", "Garage Rock", "Psybient"
)
// --- EXTENSION FUNCTIONS --- // --- EXTENSION FUNCTIONS ---
/** /**
* Convert legacy ID3 genres to their named genre * Convert legacy int-based ID3 genres to their human-readable genre
* @return The named genre for this legacy genre. * @return The named genre for this legacy genre, null if there is no need to parse it or if the genre is invalid.
*/ */
fun String.toNamedGenre(): String? { fun String.getGenreNameCompat(): String? {
// Strip the genres of any parentheses, and convert it to an int if (isDigitsOnly()) {
val intGenre = this.filterNot { // ID3 v1, just parse as an integer
PAREN_FILTER.indexOf(it) > -1 return ID3_GENRES.getOrNull(toInt())
}.toInt() }
// If the conversion fails [Due to the genre using an extension that Auxio doesn't have], if (startsWith('(') && endsWith(')')) {
// then return null. // ID3 v2+, parse out the parentheses and get the integer
return ID3_GENRES.getOrNull(intGenre) // Any genres formatted as "(CHARS)" will be ignored.
val genreInt = substring(1 until lastIndex).toIntOrNull()
if (genreInt != null) {
return ID3_GENRES.getOrNull(genreInt)
}
}
// ID3 v3+, current name is fine.
return null
} }
/** /**
@ -92,7 +110,7 @@ fun Long.toDuration(): String {
*/ */
fun Int.toYear(context: Context): String { fun Int.toYear(context: Context): String {
return if (this > 0) { return if (this > 0) {
this.toString() toString()
} else { } else {
context.getString(R.string.placeholder_no_date) context.getString(R.string.placeholder_no_date)
} }