Add [Very hacky] genre support

Add a way to load genres! Except it creates duplicates. And requires creating like 20 music cursors. At least it works?
This commit is contained in:
OxygenCobalt 2020-08-21 09:43:22 -06:00
parent f8ae5d57a5
commit 160013bbe9
3 changed files with 105 additions and 39 deletions

View file

@ -52,12 +52,12 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
/*
// Room Database
def room_version = "2.2.5"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-runtime:$room_version"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
*/
// Lifecycle
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"

View file

@ -4,6 +4,7 @@ import android.app.Application
import android.content.ContentResolver
import android.database.Cursor
import android.provider.MediaStore
import android.provider.MediaStore.Audio.Genres
import android.provider.MediaStore.Audio.AudioColumns
import android.util.Log
import org.oxycblt.auxio.music.models.Song
@ -17,8 +18,10 @@ enum class MusicLoaderResponse {
class MusicLoader(private val app: Application) {
var songs = mutableListOf<Song>()
var genres = mutableListOf<Pair<Long, String>>()
private var musicCursor: Cursor? = null
private var genreCursor: Cursor? = null
val response: MusicLoaderResponse
@ -27,14 +30,15 @@ class MusicLoader(private val app: Application) {
}
private fun findMusic(): MusicLoaderResponse {
try {
musicCursor = getCursor(
genreCursor = getGenreCursor(
app.contentResolver
)
Log.i(this::class.simpleName, "Starting music search...")
useGenreCursor()
useCursor()
indexMusic()
try {
} catch (error: Exception) {
Log.e(this::class.simpleName, "Something went horribly wrong.")
error.printStackTrace()
@ -63,14 +67,30 @@ class MusicLoader(private val app: Application) {
}
}
private fun getCursor(resolver: ContentResolver): Cursor? {
private fun getGenreCursor(resolver: ContentResolver): Cursor? {
Log.i(this::class.simpleName, "Getting genre cursor.")
// Get every Genre indexed by the android system, for some reason
// you cant directly get this from the plain music cursor.
return resolver.query(
Genres.EXTERNAL_CONTENT_URI,
arrayOf(
Genres._ID, // 0
Genres.NAME // 1
),
null, null,
Genres.DEFAULT_SORT_ORDER
)
}
private fun getMusicCursor(resolver: ContentResolver, genreId: Long): Cursor? {
Log.i(this::class.simpleName, "Getting music cursor.")
// Get all the values that can be retrieved by the cursor.
// The rest are retrieved using MediaMetadataExtractor and
// stored into a database.
return resolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
Genres.Members.getContentUri("external", genreId),
arrayOf(
AudioColumns._ID, // 0
AudioColumns.DISPLAY_NAME, // 1
@ -86,11 +106,54 @@ class MusicLoader(private val app: Application) {
)
}
// Use the cursor index music files from the shared storage, returns true if any were found.
private fun useCursor() {
// Use the genre cursor to index all the genres the android system has indexed.
private fun useGenreCursor() {
// TODO: Move genre to its own model, even if its just two values
genreCursor?.use { cursor ->
// Don't even bother running if there's nothing to process.
if (cursor.count == 0) {
return
}
val idIndex = cursor.getColumnIndexOrThrow(Genres._ID)
val nameIndex = cursor.getColumnIndexOrThrow(Genres.NAME)
while (cursor.moveToNext()) {
genres.add(
Pair<Long, String>(
cursor.getLong(idIndex),
cursor.getString(nameIndex)
)
)
Log.i(this::class.simpleName, cursor.getString(nameIndex))
}
cursor.close()
}
Log.i(this::class.simpleName, "Retrieved " + genres.size.toString() + " Genres.")
}
// Use the cursor index music files from the shared storage.
private fun indexMusic() {
Log.i(this::class.simpleName, "Starting music search...")
// So, android has a brain aneurysm if you try to get an audio genre through
// AudioColumns. As a result, I just index every genre's name & ID, create a cursor
// of music for that genres ID, and then load and iterate through them normally,
// creating using the genres name as that songs Genre.
// God why do I have to do this
for (genre in genres) {
val musicCursor = getMusicCursor(app.contentResolver, genre.first)
musicCursor?.use { cursor ->
// Don't run the more expensive file loading operations if there is no music to index.
// Don't run the more expensive file loading operations if there
// is no music to index.
if (cursor.count == 0) {
return
}
@ -106,9 +169,10 @@ class MusicLoader(private val app: Application) {
while (cursor.moveToNext()) {
val id = cursor.getLong(idIndex)
val display = cursor.getString(displayIndex)
// Get the basic metadata from the cursor
val title = cursor.getString(titleIndex) ?: cursor.getString(displayIndex)
val title = cursor.getString(titleIndex) ?: display
val artist = cursor.getString(artistIndex)
val album = cursor.getString(albumIndex)
val year = cursor.getInt(yearIndex)
@ -120,7 +184,7 @@ class MusicLoader(private val app: Application) {
songs.add(
Song(
id, title, artist, album,
year, track, duration
genre.second, year, track, duration
)
)
}
@ -128,4 +192,5 @@ class MusicLoader(private val app: Application) {
cursor.close()
}
}
}
}

View file

@ -6,6 +6,7 @@ data class Song(
val name: String?,
val artist: String?,
val album: String?,
val genre: String?,
val year: Int,
val track: Int,
val duration: Long,