I'm building a music player app. I'm trying to populate a recyclerView with album arts of songs. I successfully did that with the code that is given below. But some of the songs do not have embedded album art not any album art in the folder. So, I'm trying to check if the album art is null or not before adding it to the recyclerView. If the album art is null, the app will automatically fetch it from the internet. I tried checking if the album art is null or not, but everytime it gives me a uri whether the album art is available or not.
Code for fetching album art from mediastore:
String[] projection = {MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.ALBUM_ID};
Cursor cursor = getActivity().getContentResolver().query(uri, projection, selection, whereVal, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media._ID));
String name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String album = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM));
Long duration = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
String data = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
Long albumId = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
String albumArtUri = String.valueOf(ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"),albumId));
SongInfoModel s = new SongInfoModel(id, name, artist, null, album, null, duration, data, albumId,albumArtUri);
SongList.add(s);
} while (cursor.moveToNext());
}
The value for albumArtUri is never null.
It always gives the following uri(s):
content://media/external/audio/albumart/12
content://media/external/audio/albumart/5
content://media/external/audio/albumart/6
content://media/external/audio/albumart/3
content://media/external/audio/albumart/8
content://media/external/audio/albumart/9
But among these uri(s), content://media/external/audio/albumart/9 has no album art. It always displays the placeholder I said using Glide
So my question, how to check if album art is available(as embedded art or in song folder) before populating the recyclerView? I know I can use Glide placeholder and I'm using it. But I also want to fetch album art from the internet if album art is not available offline, that is why I need to check, so that I can add the internet links into the arraylist. Hope you guys get what I'm trying to say.
Thank you!
EDIT:
I found that the below given code snippet returns if album art exists or not but it consumes a lot of time.
public String fetchAlbumArt(long albumID){
String art;
Cursor cur = getActivity().getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, new String[]
{MediaStore.Audio.Albums.ALBUM_ART}, MediaStore.Audio.Albums._ID + "=?", new String[] {String.valueOf(albumID)}, null);
cur.moveToFirst();
art = cur.getString(cur.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
cur.close();
return art;
}
The easiest way:
// loading album cover using Glide library
String stralbumId = c.getString(c
.getColumnIndex(BaseColumns._ID));
Uri ImageUrl = getAlbumUri(mContext, stralbumId);
if (ImageUrl != null) {
Glide.with(mContext)
.asBitmap()
.load(ImageUrl)
.into(image);
}
and
public Uri getAlbumUri(Context mContext,String album_id){
if(mContext!=null) {
Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri imageUri = Uri.withAppendedPath(sArtworkUri, String.valueOf(album_id));
return imageUri;
}
return null;
}
you can check for album cover by using the MediaMetadataRetriever
try the code below and also read the MediaMetadataRetriever Documentation
MediaMetadataRetriever retriver = new MediaMetadataRetriever();
retriver.setDataSource(musicFile.getAbsolutePath());
byte[] cover = retriver.getEmbeddedPicture();
if(cover == null){
// get cover from the internet
}else{
// use glide to load the album art
}
Try to use the code below
var albumArtExists = true
try {
val contentUri = ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, albumId)
context.contentResolver.loadThumbnail(contentUri, Size(64, 64), null)
} catch(e: FileNotFoundException) {
albumArtExists = false
}
This works for sdk 29 and higher
Related
I have downloaded an image from Google Drive storage. I want to set this image to imageview in my app using Gallery Intent.
Uri of image received in onActivityResult: content://com.google.android.apps.docs.storage/document/acc%3D2%3Bdoc%3Dencoded%3DWe%2BdXDcNgTeulVk1Ntu3YfRYkm9wk7uTdTG6LFVyck1BxY4g7xAxyPAgtMtz4A%3D%3S
I am using this code get the real-path from the url:
if ("com.google.android.apps.docs.storage".equals(uri
.getAuthority())) {
//content://com.google.android.apps.docs.storage/document/acc%3D2%3Bdoc%3Dencoded%3DWe%2BdXDcNbYeulVk1Ntu3YfRYkm9wk7uTdTG6LE6yck1BxY4g7xAxyPAgtMtz4A%3D%3D
final String docId = DocumentsContract.getDocumentId(uri);
final String id = docId.split(";")[1];
final String[] selectionArgs = new String[]{id};
//String[] column = {MediaStore.Images.Media.DATA};
// where id is equal to
String selection = MediaStore.Images.Media._ID + "=?";
Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
//..
Cursor cursor = null;
String filePath = null;
try {
String[] column = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri,
column, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndex(column[0]);
filePath = cursor.getString(columnIndex);
}
} finally {
if (cursor != null)
cursor.close();
return filePath;
}
}
.....
But I am getting NULL cursor. Thus, filepath is always empty/null.
Anyone, could please suggest what I am doing wrong?
I am using this code get the real-path from the url
Delete it.
Anyone, could please suggest what I am doing wrong?
You are using that code.
Pass the Uri to your favorite image-loading library (Glide, Picasso, etc.). It will do all the work for you, populating your ImageView, in just a few lines of code.
Or, if you insist on doing it yourself:
Use a ContentResolver and openInputStream() to get an InputStream on the content identified by the Uri
Use BitmapFactory.decodeStream() to get a Bitmap based on that InputStream
Do those two steps on a background thread, as you should not do disk I/O and image decoding on the main application thread
On the main application thread, put the Bitmap in your ImageView,
I'm able to get the paths of all videos in the filesystem using MediaStore. is there any way to get a specific duration (or less than that) video using MediaStore. like video duration less than 15min.
These are my code to get the video paths
public void getVideoPaths(Context context) {
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = {MediaStore.Video.VideoColumns.DATA};
Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
if (c != null) {
while (c.moveToNext()) {
filesNames.add(c.getString(0));
}
c.close();
}
}
String duration = Integer.toString(15*60*1000);
Cursor c = context.getContentResolver().query(uri, projection, MediaStore.Video.VideoColumns.DURATION + " < ?", new String[] {duration}, null);
This will query for only files shorter than 15 minutes
The MediaStore is a Media provider that contains meta data for all available media on both internal and external storage devices. You just need to have a uri of that video file than use below code for duration purpose
MediaPlayer mp = MediaPlayer.create(this, Uri.parse(uriOfYourFile));
int duration = mp.getDuration();
And after that check for specific duration. You can use one more option as well as mentioned below
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
//use one of overloaded setDataSource() functions to set your data source
retriever.setDataSource(context, Uri.fromFile(videoFile));
String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long timeInMillisec = Long.parseLong(time );
retriever.release()
Hope that helps you.
I used this answer to get the duration,but it's not working for me.Can anybody tell me what's the problem?
Any help is appreciated.
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] columns = {MediaStore.Video.VideoColumns.DURATION};
String selection = MediaStore.Video.VideoColumns.DATA + "=?";
String selectionArgs[] = {"/data/data/com.test.test/files/video1.mp4"};
Cursor cursor = context.getContentResolver().query(uri, columns, selection, selectionArgs, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
String duration = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.DURATION));
}
cursor.close();
}
If you've already got the Uri or the file path to the video, it might be easier to use the MediaMetadataRetriever class. It would look something like this:
MediaMetadataRetriever r = new MediaMetadataRetriever();
r.setDataSource(filePath);
String durString = r.extractMetadata( MediaMetadataRetriever.METADATA_KEY_DURATION );
int duration = Integer.parseInt(durString);
The MediaStore is a Media provider that contains meta data for all available media on both internal and external storage devices.I am not sure,but the path you are using maybe is not visible for MediaStore.If you are using MediaPlayer do like this...
MediaPlayer mp = MediaPlayer.create(this, Uri.parse(uriOfYourFile));
int duration = mp.getDuration();
So I've been trying this for some time now. To get the album art for an mp3 file and displaying it on its respective ImageView and I am using the uri("content://media/external/audio/albumart")
This is my method for getting the album art
public Bitmap getAlbumArt(long idAlbum){
Bitmap bitmap = null;
try{
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri, idAlbum);
ParcelFileDescriptor parcelFileDescriptor = getContext().getContentResolver().openFileDescriptor(uri,"r");
if (parcelFileDescriptor != null){
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
}
}catch (Exception e){
e.printStackTrace();
}
return bitmap;
}
and this method always returns
java.io.FileNotFoundException: No entry for content://media/external/audio/albumart/31726
where the 31726 is the album id.
Since I'm catching this exception and I set it to a default Album art if it returns null, every mp3 has its ImageView set to the default album art. I am using my Samsung Galaxy s3 to run the application and my device runs android 4.2.2 JellyBean. Please someone help me getting this right.
This is how I request the album id
Uri musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] columns = {
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Albums._ID,
MediaStore.Audio.Media.DATA
};
String where = MediaStore.Audio.Media.IS_MUSIC + "=1";
Cursor musicCursor = usicResolver.query(musicUri,columns,where,null, null);
Then in an if loop with condition
if(musicCursor.moveToFirst()){
int albumId = musicCursor.getColumnIndex
(MediaStore.Audio.Albums._ID);
do{
long idAlbum = musicCursor.getLong(albumId);
//Then i send it to my above method getAlbumArt
Bitmap songAlbumArt = getAlbumArt(idAlbum);
}while(musicCursor.moveToNext());
}
This is how I query the cover art path from the album id:
private static String getCoverArtPath(long albumId, Context context) {
Cursor albumCursor = context.getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID + " = ?",
new String[]{Long.toString(albumId)},
null
);
boolean queryResult = albumCursor.moveToFirst();
String result = null;
if (queryResult) {
result = albumCursor.getString(0);
}
albumCursor.close();
return result;
}
You can get the Bitmap from the BitmapFactory using the path returned from the method above:
BitmapFactory.decodeFile(coverArtPath);
ImageLoader.getInstance().
displayImage( ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"), song_tag.albumId).toString(),
image,
new DisplayImageOptions.Builder().cacheInMemory(true).showImageOnFail(R.drawable.stock6).resetViewBeforeLoading(true).build());
image is the object of ImageView
song_tag.albumid is the album id which you have to send to get the image
stock6 is the default image
EDIT:
It seems that ALBUM_ART was deprecated on API 29:
https://developer.android.com/reference/android/provider/MediaStore.Audio.AlbumColumns#ALBUM_ART
Instead, they suggest using ContentResolver#loadThumbnail:
https://developer.android.com/reference/android/content/ContentResolver#loadThumbnail(android.net.Uri,%20android.util.Size,%20android.os.CancellationSignal)
--
ORIGINAL:
Querying the album art field from content://media/external/audio/albums would do it for me some time ago, but I noticed it stopped working since a few Android versions ago, for some reason.
Now I querying the albums table gets me a null album art field:
adb shell content query --uri content://media/external/audio/albums
Row: 0 numsongs=1, artist=My Artist, numsongs_by_artist=1, _id=8821305607184940112, album=My Album, album_art=NULL, album_key=4c3a3434044e5052303a4604342a3e32044248194e, artist_id=7053871990187004266, artist_key=484c465046503832464c2a04422a402a563a32444e3a4e, maxyear=NULL, minyear=NULL, album_id=8821305607184940112
Querying the album art route directly, also gives me no results...
adb shell content query --uri content://media/external/audio/albumart
No result found.
It seems that the MediaStore on the platform side... stopped trying to parse album art from music files, and add them to its db?
It is possible to retrieve each track image from the mediastore audio content provider? I am not sure whether they have separate images for each audio track, or if they only have a single image for each album. If possible, please provide a solution or corresponding link.
Android does not save it as the "track image", but the "album image". So you have to do another query to the Album data:
albumId comes from the cursor that loads the songs:
long albumId = cursor.getLong(7);
Cursor artCursor = context.getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[] {MediaStore.Audio.AlbumColumns.ALBUM_ART},
MediaStore.Audio.Media._ID+" =?",
new String[]{String.valueOf(albumId)},
null);
String albumArt;
if(artCursor.moveToNext()) {
albumArt = "file://"+artCursor.getString(0);
} else {
albumArt = null;
}
artCursor.close();
if(albumArt != null) {
BitmapFactory.decodeFile(new File(albumArt));
}
This solution works on Android 10, using kotlin and glide:
val uri = ContentUris.withAppendedId(
Uri.parse("content://media/external/audio/albumart"),
getItem(position)?.album_id?.toLong() ?: -1
)
Glide.with(holder.song_thumb.context)
.load(uri)
.into(holder.song_thumb)
getItem(position)?.album_id is the album id on the track retrieved using cursor on the content provider.
On Android 10, this Uri is accessible, while the path retrieved with the query on the content provider is not (regardless the READ_EXTERNAL_STORAGE permission).