Improve genre compatibility
Add a new range of Winamp 5.6+ genres to further improve compatibility with old genres.
This commit is contained in:
parent
58ec1ce293
commit
fab377eba4
5 changed files with 52 additions and 32 deletions
|
@ -28,6 +28,7 @@ android {
|
|||
applicationIdSuffix = '.debug'
|
||||
versionNameSuffix = "-DEBUG"
|
||||
}
|
||||
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
|
@ -62,7 +63,7 @@ dependencies {
|
|||
|
||||
// General
|
||||
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'
|
||||
|
||||
// Layout
|
||||
|
|
|
@ -26,11 +26,13 @@ sealed class Parent : BaseModel() {
|
|||
/**
|
||||
* The data object for a song. Inherits [BaseModel].
|
||||
* @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 duration The duration of the song, in millis.
|
||||
* @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 formattedDuration The Song's duration as a duration string.
|
||||
*/
|
||||
|
@ -86,7 +88,8 @@ data class Album(
|
|||
private val mSongs = mutableListOf<Song>()
|
||||
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) {
|
||||
mArtist = artist
|
||||
|
@ -118,6 +121,8 @@ data class Artist(
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -135,18 +140,15 @@ data class Genre(
|
|||
override val id: Long = -1,
|
||||
override val name: String,
|
||||
) : Parent() {
|
||||
val resolvedName: String by lazy {
|
||||
if (name.contains(Regex("([1-9])"))) {
|
||||
name.toNamedGenre() ?: name
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
private val mSongs = mutableListOf<Song>()
|
||||
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) {
|
||||
mSongs.add(song)
|
||||
|
|
|
@ -191,8 +191,9 @@ class MusicLoader(private val context: Context) {
|
|||
artists.add(
|
||||
// IDs are incremented from the minimum int value so that they remain unique.
|
||||
Artist(
|
||||
id = (artists.size + Int.MIN_VALUE).toLong(),
|
||||
name = entry.key, albums = entry.value
|
||||
id = (Int.MIN_VALUE + artists.size).toLong(),
|
||||
name = entry.key,
|
||||
albums = entry.value
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -84,9 +84,7 @@ class MusicStore private constructor() {
|
|||
* @return The corresponding [Song] for this [uri], null if there isnt one.
|
||||
*/
|
||||
fun getSongForUri(uri: Uri, resolver: ContentResolver): Song? {
|
||||
resolver.query(
|
||||
uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null
|
||||
)?.use { cursor ->
|
||||
resolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursor ->
|
||||
cursor.moveToFirst()
|
||||
val fileName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.provider.MediaStore
|
|||
import android.text.format.DateUtils
|
||||
import android.widget.ImageButton
|
||||
import android.widget.TextView
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import androidx.databinding.BindingAdapter
|
||||
import org.oxycblt.auxio.R
|
||||
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.
|
||||
*/
|
||||
private val ID3_GENRES = arrayOf(
|
||||
// ID3 Standard
|
||||
"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz",
|
||||
"Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "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",
|
||||
"Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
|
||||
|
||||
// Winamp Extensions
|
||||
"Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival",
|
||||
"Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
|
||||
"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",
|
||||
"Britpop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black 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 ---
|
||||
|
||||
/**
|
||||
* Convert legacy ID3 genres to their named genre
|
||||
* @return The named genre for this legacy genre.
|
||||
* Convert legacy int-based ID3 genres to their human-readable 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? {
|
||||
// Strip the genres of any parentheses, and convert it to an int
|
||||
val intGenre = this.filterNot {
|
||||
PAREN_FILTER.indexOf(it) > -1
|
||||
}.toInt()
|
||||
fun String.getGenreNameCompat(): String? {
|
||||
if (isDigitsOnly()) {
|
||||
// ID3 v1, just parse as an integer
|
||||
return ID3_GENRES.getOrNull(toInt())
|
||||
}
|
||||
|
||||
// If the conversion fails [Due to the genre using an extension that Auxio doesn't have],
|
||||
// then return null.
|
||||
return ID3_GENRES.getOrNull(intGenre)
|
||||
if (startsWith('(') && endsWith(')')) {
|
||||
// ID3 v2+, parse out the parentheses and get the integer
|
||||
// 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 {
|
||||
return if (this > 0) {
|
||||
this.toString()
|
||||
toString()
|
||||
} else {
|
||||
context.getString(R.string.placeholder_no_date)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue