Jump to content

Querying all album artwork


xilefian

Recommended Posts

I've been developing a companion application for Poweramp using its developer API https://github.com/maxmpz/powerampapi

Unfortunately I've been stuck with retrieving artwork through the API.

I can successfully listen to the "PowerampAPI.ACTION_AA_CHANGED" broadcast and I can get the URI or the Bitmap from the given intent, this is working fine (I can display the artwork for the currently playing track), however I would like to get the album artwork for any track, not just the "currently playing" track.

In my companion application I am listing the following:

  • All Songs (files)
  • Albums
  • Artists
  • Genres
  • Playlists
  • Queue
  • Top rated (top_rated/files)
  • Recently added (recently_added/files)

I can successfully get the folder_id from the files and from there I can get the folders.thumb for the file location of the artwork, however this location doesn't seem to work for me.

Is there an easier or simpler way of getting the album artwork?

Link to comment
Share on other sites

Here is my code.

The filesPath would be something like "albums/12345/files" or similar. It can be just "files".

private Uri getArtwork(String filesPath) {
  // Fields to query for individual file
  String[] fileFields = { "folder_files._id", "folder_files.name", "folder_id", "aa_status" };

  // filesPath can be albums, artists, genres, etc
  Uri filesUri = PowerampAPI.ROOT_URI.buildUpon().appendEncodedPath(filesPath).build();

  // Query all files of path
  Cursor fileCursor = getContentResolver().query(filesUri, fileFields, null, null, null);
  if (fileCursor != null) {
    // Get folderIds of files with loaded album artwork
    List<String> folderIds = new ArrayList<>();

    // Loop through all files of path
    for (fileCursor.moveToFirst(); !fileCursor.isAfterLast(); fileCursor.moveToNext()) {
      // Add folderId to list of folders
      String folderId = fileCursor.getString(2);
      if (!folderIds.contains(folderId)) {
        folderIds.add(folderId);
      }
    }
    fileCursor.close();

    if (!folderIds.isEmpty()) {
      // Fields to query for individual folder
      String[] folderFields = { "folders._id", "folders.name", "folders.thumb", "folders.thumb_status", "folders.path" };

      // Get first folder with an available album/thumb image
      String thumb = null;
      for (String folderId : folderIds) {
        Uri folderUri = PowerampAPI.ROOT_URI.buildUpon().appendPath("folders").appendPath(folderId).build();
        Cursor folderCursor = getContentResolver().query(folderUri, folderFields, null, null, null);
        if (folderCursor != null) {
          for (folderCursor.moveToFirst(); !folderCursor.isAfterLast(); folderCursor.moveToNext()) {
            // Print Columns
            Log.d(TAG, "Folder ID : " + folderCursor.getString(0));
            Log.d(TAG, "Folder Name : " + folderCursor.getString(1));
            Log.d(TAG, "Folder Thumb : " + folderCursor.getString(2));
            Log.d(TAG, "Folder Thumb Status : " + folderCursor.getString(3));
            Log.d(TAG, "Folder Path : " + folderCursor.getString(4));

            // Get folder thumb image
            String folderThumb = folderCursor.getString(2);
            if (!TextUtils.isEmpty(folderThumb)) {
              if (folderThumb.startsWith("/storage/")) {
                thumb = folderThumb;
              } else {
                String folderPath = folderCursor.getString(4);
                thumb = folderPath + folderThumb;
              }
            }

            if (!TextUtils.isEmpty(thumb)) {
              // Stop search if we found a valid thumb
              break;
            }
          }

          folderCursor.close();
        }

        if (!TextUtils.isEmpty(thumb)) {
          // Stop search if we found a valid thumb
          break;
        }
      }

      // If we found a thumb file, return its Uri
      if (!TextUtils.isEmpty(thumb)) {
        File thumbFile = new File(thumb);
        if (thumbFile.exists()) {
          return Uri.fromFile(thumbFile);
        }
      }
    }
  }
  return null; // Failed to find an album/thumb image
}

I am confident that the Uri I am getting is valid, just not sure my method is correct? I'm going to be fiddling with my implementation and permissions to see if that is the issue here, but at the moment it feels "wrong" to be getting album artwork this way. The image either doesn't load or loads a white image.

I'll give more context about my application if I've once again exhausted investigation, if this code works for others then it'll certainly be my end. Really doesn't feel correct to get album artwork this way.

EDIT: Looks like a permissions error, unfortunately permissions is something I need to avoid. This code also only loads up the artwork on in file storage, avoids embedded artowrk. My original question still stands: Is there any way to get the album artwork through the Poweramp API?

Link to comment
Share on other sites

Your approach to get the thumbfile reference is ok. but all you have at this point is the filename.

The next step would be to read the .jpg bitsream 

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(picture, options);
    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(picture, options);
}
    public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
    if (height > reqHeight || width > reqWidth) {
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;
        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

Look on Stackoverflow as there are plenty of examples.. The way I do it is to get the equivalent android albumid and retrieve it using the Mediastore, then get its url

album_id = c.getLong(c.getColumnIndex(MediaStore.Audio.Albums._ID));
    @Override
   public Bitmap loadItem(Long id) {
      Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
      Uri imageUri = Uri.withAppendedPath(sArtworkUri, String.valueOf(id));
      Resources res = mContext.getResources();
      int width = res.getDimensionPixelSize(R.dimen.image_width);
      int height = res.getDimensionPixelSize(R.dimen.image_height);

        Bitmap bitmap = null;
        try {
            bitmap = decodeSampledBitmapFromResource(imageUri, width, height);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (bitmap != null) {
         mMemCache.put(id, bitmap);
      }else {
/*            Uri path = Uri.parse("android.resource://com.newflyingdutchman.newplaylistmanager/"
                    + R.drawable.playlist);
            bitmap = decodeSampledBitmapFromResource(path, width, height);
            mMemCache.put(id, bitmap);
 */       }
      return bitmap;
   }

 

However, Poweramp may get its thumb from other locations too, eg the embedded albumart on the mp3 itself.

To quote Andre "Poweramp uses internal device storage for caching downloaded album art," but I found nothing using the Poweramp api relating to albumart.

 

Code snippets from smoothie by Lucas Rocha

Link to comment
Share on other sites

Hi sorry for the late reply. I am a very experienced Android developer, displaying bitmaps is fine, I am asking specifically if there is a way to retrieve album art through the API and hopefully in a way that avoids permissions (get the bitmap directly, rather than file paths) similar to how the album art intent of the currently played track works.

If not, this looks like something I'll have to hack together myself.

The hacky solution I have in mind now is:

And then separately:

  • When track is played via Poweramp Then Copy album art from currently playing track into app's image cache.

Thanks for the help.

Link to comment
Share on other sites

7 hours ago, TheoKlink said:

Why complicate matters. Your approach relies on Poweramp not changing its approach to dealing with albumart. It makes far more sense to use the android albumart which is what powramp copies when it scans first time.

It is my understanding that Poweramp does not update the Android album-art, so if a custom album art is set in Poweramp (by the user or auto download) then that change is not reflected in the Android album-art. If I am wrong about this, then I will modify my approach.

I would have included the Android album-art in my solution, however as you said yourself; Poweramp copies this when it scans for the first time, so there's little reason to use it when Poweramp's album-art likely already contains the same images. If this is not the case, then I will add Android's album-art as a source along side Poweramp's.

I am relying on Poweramp's API for my app's behaviour. If that changes then I will have to change my methods. My app uses the API for a few things, so I'll have to adapt my app regardless if there are any changes, so this is not a concern.

From what I can see, Android's album-art still requires external storage permissions to access. If that wasn't the case, then I would certainly add it as an album art source for the case of the permission not being granted.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...