diff --git a/app/build.gradle b/app/build.gradle index c054f21a4..1ed00cc7e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicLoader.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicLoader.kt index 4b82c4bff..da3f21c36 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicLoader.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicLoader.kt @@ -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() + var genres = mutableListOf>() 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 { + genreCursor = getGenreCursor( + app.contentResolver + ) + + useGenreCursor() + + indexMusic() + try { - musicCursor = getCursor( - app.contentResolver - ) - - Log.i(this::class.simpleName, "Starting music search...") - - useCursor() } 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,46 +106,91 @@ 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() { - musicCursor?.use { cursor -> + // 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 - // Don't run the more expensive file loading operations if there is no music to index. + genreCursor?.use { cursor -> + + // Don't even bother running if there's nothing to process. if (cursor.count == 0) { return } - val idIndex = cursor.getColumnIndexOrThrow(AudioColumns._ID) - val displayIndex = cursor.getColumnIndexOrThrow(AudioColumns.DISPLAY_NAME) - val titleIndex = cursor.getColumnIndexOrThrow(AudioColumns.TITLE) - val artistIndex = cursor.getColumnIndexOrThrow(AudioColumns.ARTIST) - val albumIndex = cursor.getColumnIndexOrThrow(AudioColumns.ALBUM) - val yearIndex = cursor.getColumnIndexOrThrow(AudioColumns.YEAR) - val trackIndex = cursor.getColumnIndexOrThrow(AudioColumns.TRACK) - val durationIndex = cursor.getColumnIndexOrThrow(AudioColumns.DURATION) + val idIndex = cursor.getColumnIndexOrThrow(Genres._ID) + val nameIndex = cursor.getColumnIndexOrThrow(Genres.NAME) while (cursor.moveToNext()) { - val id = cursor.getLong(idIndex) - - // Get the basic metadata from the cursor - val title = cursor.getString(titleIndex) ?: cursor.getString(displayIndex) - val artist = cursor.getString(artistIndex) - val album = cursor.getString(albumIndex) - val year = cursor.getInt(yearIndex) - val track = cursor.getInt(trackIndex) - val duration = cursor.getLong(durationIndex) - - // TODO: Add album art [But its loaded separately, as that will take a bit] - // TODO: Add genres whenever android hasn't borked it - songs.add( - Song( - id, title, artist, album, - year, track, duration + genres.add( + Pair( + 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. + if (cursor.count == 0) { + return + } + + val idIndex = cursor.getColumnIndexOrThrow(AudioColumns._ID) + val displayIndex = cursor.getColumnIndexOrThrow(AudioColumns.DISPLAY_NAME) + val titleIndex = cursor.getColumnIndexOrThrow(AudioColumns.TITLE) + val artistIndex = cursor.getColumnIndexOrThrow(AudioColumns.ARTIST) + val albumIndex = cursor.getColumnIndexOrThrow(AudioColumns.ALBUM) + val yearIndex = cursor.getColumnIndexOrThrow(AudioColumns.YEAR) + val trackIndex = cursor.getColumnIndexOrThrow(AudioColumns.TRACK) + val durationIndex = cursor.getColumnIndexOrThrow(AudioColumns.DURATION) + + 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) ?: display + val artist = cursor.getString(artistIndex) + val album = cursor.getString(albumIndex) + val year = cursor.getInt(yearIndex) + val track = cursor.getInt(trackIndex) + val duration = cursor.getLong(durationIndex) + + // TODO: Add album art [But its loaded separately, as that will take a bit] + // TODO: Add genres whenever android hasn't borked it + songs.add( + Song( + id, title, artist, album, + genre.second, year, track, duration + ) + ) + } + + cursor.close() + } + } } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/models/Song.kt b/app/src/main/java/org/oxycblt/auxio/music/models/Song.kt index 74e40adab..918067844 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/models/Song.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/models/Song.kt @@ -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,