XamarinMediaManager icon indicating copy to clipboard operation
XamarinMediaManager copied to clipboard

Album and Display Image doesn't change

Open arahmancsd opened this issue 4 years ago • 9 comments

🐛 Bug Report

I am using this package and it is quite well. However, when i want to change the media item display, album and image it doesn't update or change the images. Here is the code.

// fileUri = https://www.azee.tech/Dari/001.mp3
var item = (MediaItem)await CrossMediaManager.Current.Extractor.CreateMediaItem(fileUri);
 var reciterImageUri = "https://www.azee.tech/sudais.jpg"; // this is the image uri
 var image = new Image() { Source = ImageSource.FromUri(new Uri(reciterImageUri)) };
 if (item != null)
 {
    item.Id = string.Format("{0},{1},{2},{3},{4},{5},{6}", (short)mode, chapterId, reciter.ReciterID, playlistId, playlistChapterId, -1, -1);
    item.IsMetadataExtracted = false;
    item.Title = string.Format("{0} - {1} ({2})", c.ChapterID, c.ArabicEnglishName, c.EnglishName);
    item.Album = reciter.Name;
    item.Artist = reciter.Name;

    //none of these work
    item.AlbumImage = image;
    item.AlbumImageUri = reciterImageUri;
    item.DisplayImage = image;
    item.DisplayImageUri = reciterImageUri;
    item.Image = image;
    item.ImageUri = reciterImageUri;
 }
 return item;

Image link

Expected: Should the change the album and display image.

Actual: Doesn't change Album or Display image

Screenshot_16122160688

The media file play works as expected, but the image doesn't change.

I understand this was reported in #709, but closed without working solution.

arahmancsd avatar Feb 01 '21 21:02 arahmancsd

Hi @arahmancsd Do you found a solution? I encounter the same issue both on iOS and Android regarding the Album / Display image.

pcdus avatar Feb 16 '21 08:02 pcdus

This seems to be still a bug in the package, I have tried different methods but none worked.

arahmancsd avatar Feb 17 '21 21:02 arahmancsd

Encountering the same issue.

LittleBoxOfChicken avatar Feb 18 '21 13:02 LittleBoxOfChicken

I've finally found a way to display an Album Image like this:

CrossMediaManager.Current.Queue.Current.IsMetadataExtracted = false;
var webUrlImage = "https://my.url.com/mycover.jpg";
CrossMediaManager.Current.Queue.Current.DisplayImageUri = webUrlImage;
CrossMediaManager.Current.Queue.Current.AlbumImageUri = webUrlImage;
CrossMediaManager.Current.Queue.Current.ImageUri = webUrlImage;
CrossMediaManager.Current.Notification.UpdateNotification();
CrossMediaManager.Current.Extractor.UpdateMediaItem(CrossMediaManager.Current.Queue.Current);

But I always display the same Image, as I play audio stream of a Web Radio: I display the cover of this radio.

pcdus avatar Feb 22 '21 17:02 pcdus

I have used your code in PropertyChanged, MetadataUpdated, OnStateChanged (only in playing), and also added your code right after await play(), but none worked for me. Is it working in emulator for you?

arahmancsd avatar Feb 22 '21 20:02 arahmancsd

@Goldstrike just tried this code snippet. Works on Android but not on iOS for me. Have you tested this on iOS?

UPDATE:

A full rebuild of iOS has actually fixed this! So yes, this code does indeed work.

jamsoft avatar Jul 20 '21 14:07 jamsoft

Actually managed to work in iOS. The image path must be https and JPG/JPEG only. However, the same code doesn't work with Android.

arahmancsd avatar Oct 20 '22 22:10 arahmancsd

@arahmancsd I didn't have any problem on Android to display the image.

pcdus avatar Oct 21 '22 06:10 pcdus

Finally, I solved this mystery (at least for me) in Android and iOS. I'll go ahead and get straight to the code.

Part 1 It would be faster to create a MediaItem object when you have the raw data rather than using Extracter, but in both cases, it would work. Extractor is slower compared to raw data to create a MediaItem object. So in my case I had the raw data so I created a MediaItem object

var mediaItem = new MediaItem()
                         {
                             MediaUri = mediaUri,
                             IsMetadataExtracted = false,
                             Id = something,
                             Title = title,
                             DisplayTitle = displayTitle,
                             DisplaySubtitle = displaySubtitle,
                             DisplayImageUri = imageUri, // valid https jpg URL => setting this works with iOS out of the box
                             AlbumImageUri = imageUri, // valid https jpg URL => setting this works with iOS out of the box
                             ImageUri = imageUri, ///valid https jpg URL => setting this works with iOS out of the box
                             Album = albumName,
                             Author = author,
                             Artist = artist,
                             Genre = genre,
                             DisplayImage = null, // this is optional => setting this in iOS somehow creates a problem so you can remove it 
                             DownloadStatus = ...,
                             MediaLocation = ...,
                         };

However, you can create your mediaitem object with Extractor as well.

Part 2 In StateChanged add the following (since I care about Playing only so it is up to you)

if (CrossMediaManager.Current.State == MediaPlayerState.Playing
             && CrossMediaManager.Current.Queue.Current is IMediaItem mediaItem
             && mediaItem is not null)
        {
            mediaItem = await mediaItem.AddDisplayImageAsync(mediaItem.DisplayImageUri);

            CrossMediaManager.Current.Notification.UpdateNotification();
            await CrossMediaManager.Current.Extractor.UpdateMediaItem(mediaItem);
        }

Part 3 // This is an extension


using MediaManager.Library;

#if ANDROID
using Android.Graphics;
using Android.OS;
using Android.Support.V4.Media;
#endif

#if IOS
using Foundation;
using UIKit;
#endif

// Although this is not required in iOS, but I am having a function to care of it.
public static async Task<IMediaItem> AddDisplayImageAsync(this IMediaItem mediaItem, string imageUrl)
    {
        if (mediaItem is not null && !string.IsNullOrWhiteSpace(imageUrl))
        {
            try
            {
                using HttpClient client = new();
                var stream = await client.GetStreamAsync(imageUrl).ConfigureAwait(false);
#if ANDROID
                var bitmap = BitmapFactory.DecodeStream(stream);
                mediaItem.DisplayImage = bitmap;
#elif IOS
                using var imageData = NSData.FromStream(stream);
                using var image = UIImage.LoadFromData(imageData);
#endif
            }
            catch (Exception ex)
            {
                mediaItem.DisplayImage = null;
            }
        }

        return mediaItem;
    }

Additionally, if you are using Extractor you won't have to add StateChanged. You can add a display image directly by returning an object from AddDisplayImageAsync without the extension (something like below). However, please note that this would be slower for the list/playlist. So for performance, it is good to place it in StateChanged.

private async Task<object> GetDisplayImageAsync(string imageUrl)
    {
        if (!string.IsNullOrWhiteSpace(imageUrl))
        {
            try
            {
                using HttpClient client = new();
                var stream = await client.GetStreamAsync(imageUrl).ConfigureAwait(false);
#if ANDROID
                return BitmapFactory.DecodeStream(stream);
#elif IOS
                using var imageData = NSData.FromStream(stream);
                return UIImage.LoadFromData(imageData);
#endif
            }
            catch (Exception)
            {
                
            }
        }

        return null;
    }

arahmancsd avatar Dec 18 '23 22:12 arahmancsd