Why doesn't MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI provide an accurate "Album Artist"?
Asked Answered
P

1

9

I'm working with the android MediaStore. I can get a list of music on the device, and all the details associated with each media item (title, artist, duration, etc.)

I would like to be able to show a list of Albums, with their Album Artist.

To be clear, each track has an Artist, like "NoFX" but if the track occurs on a compilation CD, like Punk-O-Rama, the Artist is "NoFX" but the Album Artist would probably be something like "Various Artists."

I have reviewed the question here:

Android - Getting Album Artist from Cursor

and I'm trying to implement with MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI and MediaStore.Audio.Albums.ARTIST. This doesn't seem to return the correct result, however.

Looking at the Android source code, I can see there IS in fact an album_artist field behind MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, but it's flagged "@hide". (see line ~1170 at https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/provider/MediaStore.java).

I found this field looking through other [related] Android source code: https://android.googlesource.com/platform/development/+/master/apps/Development/src/com/android/development/MediaScannerActivity.java

I've written a simple app/activity to test this:

package com.ma.albumartisttest;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.util.SparseArray;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // query all media and get the album_artist field
        Cursor cursor = getContentResolver().query(
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                new String[]{MediaStore.Audio.Media.ALBUM_ID, "album_artist"}, null, null, null);

        // Store an id=>name map
        SparseArray<String> albumArtistNames = new SparseArray<String>();
        if (cursor != null) {
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                String mediaAlbumArtist = cursor.getString(1);
                if (mediaAlbumArtist != null && mediaAlbumArtist.toLowerCase().contains("various")) {
                    // loop through the cursor, save "album_artist"s that look like "various"
                    albumArtistNames.put((int) cursor.getLong(0), mediaAlbumArtist);
                }
            }
            cursor.close();
        }

        String msg;
        if (albumArtistNames.size() == 0) {
            msg = "No 'various' artists found!";
            Log.d("TESTALBUMARTIST", msg);
        } else {
            StringBuffer out = new StringBuffer();
            for (int i = 0; i < albumArtistNames.size(); i++) {
                // loop through the albums found above
                int albumId = albumArtistNames.keyAt(i);
                String album_artist = albumArtistNames.get(albumId);
                Cursor albumCursor = getContentResolver().query(
                        MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
                        new String[]{MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ARTIST},
                        MediaStore.Audio.Albums._ID + "=?",
                        new String[]{"" + albumId}, null);
                if (albumCursor != null) {
                    if (albumCursor.moveToFirst()) {
                        // print out what was found.
                        String artistFromAlbumsDB = albumCursor.getString(1);
                        Log.d("TESTALBUMARTIST", album_artist + ":" + artistFromAlbumsDB);
                        out.append("Album id: " + albumId).append('\n')
                                .append("Artist from media table: " + album_artist).append('\n')
                                .append("Artist from albums table: " + artistFromAlbumsDB)
                                .append("\n\n");
                    }
                    albumCursor.close();
                }
            }
            msg = out.toString();
        }

        // show the results on-screen
        TextView tv = new TextView(this);
        tv.setText(msg);
        setContentView(tv);
    }
}

This activity produces the following logcat output:

12-20 14:16:45.688  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:Mike Garson
12-20 14:16:45.708  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:Franco Corelli
12-20 14:16:45.728  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:The Foreshadowing
12-20 14:16:45.748  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists - Polyvinyl Record Co:Volcano, I'm Still Excited!!
12-20 14:16:45.778  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists - Curve Music:GRAND:PM
12-20 14:16:45.808  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists - DiN:Ian Boddy
12-20 14:16:45.828  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:SNFU
12-20 14:16:45.858  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:Pulley
12-20 14:16:45.878  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:Osker
12-20 14:16:45.908  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:Pennywise
12-20 14:16:45.938  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:NoFX
12-20 14:16:45.958  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists:Death By Stereo
12-20 14:16:45.978  22009-22009/com.ma.albumartisttest D/TESTALBUMARTIST﹕ Various Artists (Sillage Intemporel):Sheri Malckin

I'm running this on a Nexus 7 running 4.4.2. I've also tested and seen the same behavior on a Huawei Prism II running 4.1.1

Why doesn't the straightforward and not "hidden" way of getting Album Artists work?

What I expect is that the Album queries also return "Various Artists".

All help is appreciated.

Visual output of test Application/Activity

Prevenient answered 20/12, 2013 at 19:19 Comment(1)
What I've implemented so far is a custom Provider that queries MediaStore.Audio.Media for album_artist, and returns distinct ALBUM_IDs. It's not perfect, and performance is less than desirable (since I can't do a GROUP BY), but it looks like it's mostly working for me. It would be nice if someone knew more about why this doesn't work, or how to fix it.Prevenient
T
0

I don't see you defining or importing ListActivity anywhere in your code.

Have a look in these two examples:

Tetrastichous answered 27/12, 2013 at 23:27 Comment(1)
As mentioned above, I have thoroughly reviewed that SO link. I'm getting a valid artist name when I query the Album Artist, but it's invalid. Also, a ListActivity isn't required to query a Cursor nor to display a list -- I've used a much simpler TextView to display the results.Prevenient

© 2022 - 2024 — McMap. All rights reserved.