diff --git a/MediaManager/Library/IMediaItem.cs b/MediaManager/Library/IMediaItem.cs index 2785fcd2..3e8b1892 100644 --- a/MediaManager/Library/IMediaItem.cs +++ b/MediaManager/Library/IMediaItem.cs @@ -30,100 +30,90 @@ public interface IMediaItem : IContentItem /// string Album { get; set; } - /// - /// The metadata key for a Bitmap typed value to retrieve the information about the artwork for the Album of the media's original source. - /// - object AlbumArt { get; set; } - /// /// The metadata for the artist for the Album of the media's original source. /// string AlbumArtist { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the Uri of the artwork for the Album of the media's original source. + /// The metadata for a Bitmap typed value to retrieve the information about the artwork for the Album of the media's original source. /// - string AlbumArtUri { get; set; } + object AlbumImage { get; set; } /// - /// The metadata key for a Bitmap typed value to retrieve the information about the artwork for the media. + /// The metadata for a CharSequence or string typed value to retrieve the information about the Uri of the artwork for the Album of the media's original source. /// - object Art { get; set; } + string AlbumImageUri { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the artist of the media. + /// The metadata for a CharSequence or string typed value to retrieve the information about the artist of the media. /// string Artist { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about Uri of the artwork for the media. + /// The metadata for a Bitmap typed value to retrieve the information about the artwork for the media. + /// + object Image { get; set; } + + /// + /// The metadata for a CharSequence or string typed value to retrieve the information about Uri of the artwork for the media. /// - string ArtUri { get; set; } + string ImageUri { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the author of the media. + /// The metadata for a CharSequence or string typed value to retrieve the information about the author of the media. /// string Author { get; set; } //TODO: Probably remove this one /// - /// The metadata key for a int typed value to retrieve the information about the bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5. + /// The metadata for a int typed value to retrieve the information about the bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5. /// BtFolderType BtFolderType { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the compilation status of the media. + /// The metadata for a CharSequence or string typed value to retrieve the information about the compilation status of the media. /// string Compilation { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the composer of the media. + /// The metadata for a CharSequence or string typed value to retrieve the information about the composer of the media. /// string Composer { get; set; } //TODO: Make it a DateTime /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the date the media was created or published. + /// The metadata for a CharSequence or string typed value to retrieve the information about the date the media was created or published. /// string Date { get; set; } /// - /// The metadata key for a int typed value to retrieve the information about the disc number for the media's original source. + /// The metadata for a int typed value to retrieve the information about the disc number for the media's original source. /// int DiscNumber { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the description that is suitable for display to the user. + /// The metadata for a CharSequence or string typed value to retrieve the information about the description that is suitable for display to the user. /// string DisplayDescription { get; set; } /// - /// The metadata key for a Bitmap typed value to retrieve the information about the icon or thumbnail that is suitable for display to the user. - /// - object DisplayIcon { get; set; } - - /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the Uri of icon or thumbnail that is suitable for display to the user. - /// - string DisplayIconUri { get; set; } - - /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the subtitle that is suitable for display to the user. + /// The metadata for a CharSequence or string typed value to retrieve the information about the subtitle that is suitable for display to the user. /// string DisplaySubtitle { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the title that is suitable for display to the user. + /// The metadata for a CharSequence or string typed value to retrieve the information about the title that is suitable for display to the user. /// string DisplayTitle { get; set; } /// - /// The metadata key for a int typed value to retrieve the information about the download status of the media which will be used for later offline playback. + /// The metadata for a int typed value to retrieve the information about the download status of the media which will be used for later offline playback. /// DownloadStatus DownloadStatus { get; set; } /// - /// The metadata key for a int typed value to retrieve the information about the duration of the media in ms. + /// The metadata for a int typed value to retrieve the information about the duration of the media in ms. /// TimeSpan Duration { get; set; } @@ -133,47 +123,47 @@ public interface IMediaItem : IContentItem object Extras { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the genre of the media. + /// The metadata for a CharSequence or string typed value to retrieve the information about the genre of the media. /// string Genre { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the Uri of the content. + /// The metadata for a CharSequence or string typed value to retrieve the information about the Uri of the content. /// string MediaUri { get; set; } /// - /// The metadata key for a int typed value to retrieve the information about the number of tracks in the media's original source. + /// The metadata for a int typed value to retrieve the information about the number of tracks in the media's original source. /// int NumTracks { get; set; } /// - /// The metadata key for a Rating2 typed value to retrieve the information about the overall rating for the media. + /// The metadata for a Rating2 typed value to retrieve the information about the overall rating for the media. /// object Rating { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the title of the media. + /// The metadata for a CharSequence or string typed value to retrieve the information about the title of the media. /// string Title { get; set; } /// - /// The metadata key for a int typed value to retrieve the information about the track number for the media. + /// The metadata for a int typed value to retrieve the information about the track number for the media. /// int TrackNumber { get; set; } /// - /// The metadata key for a Rating2 typed value to retrieve the information about the user's rating for the media. + /// The metadata for a Rating2 typed value to retrieve the information about the user's rating for the media. /// object UserRating { get; set; } /// - /// The metadata key for a CharSequence or string typed value to retrieve the information about the writer of the media. + /// The metadata for a CharSequence or string typed value to retrieve the information about the writer of the media. /// string Writer { get; set; } /// - /// The metadata key for a int typed value to retrieve the information about the year the media was created or published. + /// The metadata for a int typed value to retrieve the information about the year the media was created or published. /// int Year { get; set; } diff --git a/MediaManager/Library/MediaItem.cs b/MediaManager/Library/MediaItem.cs index 368e32c4..e84c6e6d 100644 --- a/MediaManager/Library/MediaItem.cs +++ b/MediaManager/Library/MediaItem.cs @@ -33,7 +33,7 @@ public string Album } private object _albumArt; - public object AlbumArt + public object AlbumImage { get => _albumArt; set => SetProperty(ref _albumArt, value); @@ -47,14 +47,14 @@ public string AlbumArtist } private string _albumArtUri; - public string AlbumArtUri + public string AlbumImageUri { get => _albumArtUri; set => SetProperty(ref _albumArtUri, value); } private object _art; - public object Art + public object Image { get => _art; set => SetProperty(ref _art, value); @@ -68,7 +68,7 @@ public string Artist } private string _artUri; - public string ArtUri + public string ImageUri { get => _artUri; set => SetProperty(ref _artUri, value); diff --git a/MediaManager/Library/MediaItemExtensions.cs b/MediaManager/Library/MediaItemExtensions.cs index 979ab20d..90e39def 100644 --- a/MediaManager/Library/MediaItemExtensions.cs +++ b/MediaManager/Library/MediaItemExtensions.cs @@ -51,5 +51,25 @@ public static string GetSubText(this IMediaItem mediaItem) else return ""; } + + public static string GetImageUri(this IMediaItem mediaItem) + { + if (!string.IsNullOrEmpty(mediaItem.ImageUri)) + return mediaItem.ImageUri; + else if (!string.IsNullOrEmpty(mediaItem.AlbumImageUri)) + return mediaItem.AlbumImageUri; + else + return ""; + } + + public static object GetImage(this IMediaItem mediaItem) + { + if (mediaItem.Image != null) + return mediaItem.Image; + else if (mediaItem.AlbumImage != null) + return mediaItem.AlbumImage; + else + return null; + } } } diff --git a/MediaManager/Media/MediaExtractorBase.cs b/MediaManager/Media/MediaExtractorBase.cs index 0e899c46..c7189f0a 100644 --- a/MediaManager/Media/MediaExtractorBase.cs +++ b/MediaManager/Media/MediaExtractorBase.cs @@ -143,6 +143,7 @@ public virtual async Task UpdateMediaItem(IMediaItem mediaItem) } mediaItem = await GetMetadata(mediaItem).ConfigureAwait(false); + mediaItem.Image = await GetMediaImage(mediaItem).ConfigureAwait(false); mediaItem.IsMetadataExtracted = true; } @@ -163,11 +164,18 @@ public async Task GetMetadata(IMediaItem mediaItem) public async Task GetMediaImage(IMediaItem mediaItem) { object image = null; - foreach (var provider in ImageProviders) + + if (mediaItem.IsMetadataExtracted) + image = mediaItem.GetImage(); + + if (image == null) { - image = await provider.ProvideImage(mediaItem).ConfigureAwait(false); - if (image != null) - return image; + foreach (var provider in ImageProviders) + { + image = await provider.ProvideImage(mediaItem).ConfigureAwait(false); + if (image != null) + return image; + } } return image; } diff --git a/MediaManager/MediaManager.csproj b/MediaManager/MediaManager.csproj index 9990ba21..c0e7d7b6 100644 --- a/MediaManager/MediaManager.csproj +++ b/MediaManager/MediaManager.csproj @@ -80,9 +80,11 @@ + + diff --git a/MediaManager/Platforms/Android/Media/FileImageProvider.cs b/MediaManager/Platforms/Android/Media/FileImageProvider.cs index 8e937b82..70b50f36 100644 --- a/MediaManager/Platforms/Android/Media/FileImageProvider.cs +++ b/MediaManager/Platforms/Android/Media/FileImageProvider.cs @@ -8,32 +8,40 @@ namespace MediaManager.Platforms.Android.Media { public class FileImageProvider : IMediaItemImageProvider { - public Task ProvideImage(IMediaItem mediaItem) + public async Task ProvideImage(IMediaItem mediaItem) { - var albumFolder = GetCurrentSongFolder(mediaItem); - if (albumFolder == null) - return null; - - if (!albumFolder.EndsWith("/")) + object image = null; + try { - albumFolder += "/"; - } + var albumFolder = GetCurrentSongFolder(mediaItem); + if (albumFolder == null) + return null; - var baseUri = new System.Uri(albumFolder); - var albumArtPath = TryGetAlbumArtPathByFilename(baseUri, "Folder.jpg"); - if (albumArtPath == null) - { - albumArtPath = TryGetAlbumArtPathByFilename(baseUri, "Cover.jpg"); + if (!albumFolder.EndsWith("/")) + { + albumFolder += "/"; + } + + var baseUri = new System.Uri(albumFolder); + var albumArtPath = TryGetAlbumArtPathByFilename(baseUri, "Folder.jpg"); if (albumArtPath == null) { - albumArtPath = TryGetAlbumArtPathByFilename(baseUri, "AlbumArtSmall.jpg"); + albumArtPath = TryGetAlbumArtPathByFilename(baseUri, "Cover.jpg"); if (albumArtPath == null) - return null; + { + albumArtPath = TryGetAlbumArtPathByFilename(baseUri, "AlbumArtSmall.jpg"); + if (albumArtPath == null) + return null; + } } - } - var bitmap = BitmapFactory.DecodeFile(albumArtPath); - return Task.FromResult(bitmap as object); + image = await BitmapFactory.DecodeFileAsync(albumArtPath).ConfigureAwait(false); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return mediaItem.AlbumImage = image; } protected virtual string TryGetAlbumArtPathByFilename(System.Uri baseUri, string filename) diff --git a/MediaManager/Platforms/Android/Media/ID3Provider.cs b/MediaManager/Platforms/Android/Media/ID3Provider.cs index 63eba494..3a6923a1 100644 --- a/MediaManager/Platforms/Android/Media/ID3Provider.cs +++ b/MediaManager/Platforms/Android/Media/ID3Provider.cs @@ -106,7 +106,7 @@ public async Task ProvideImage(IMediaItem mediaItem) { try { - image = await BitmapFactory.DecodeByteArrayAsync(imageByteArray, 0, imageByteArray.Length); + image = await BitmapFactory.DecodeByteArrayAsync(imageByteArray, 0, imageByteArray.Length).ConfigureAwait(false); } catch (Java.Lang.OutOfMemoryError) { @@ -119,7 +119,7 @@ public async Task ProvideImage(IMediaItem mediaItem) { Console.WriteLine(ex.Message); } - return image; + return mediaItem.Image = image; } public async Task ProvideVideoFrame(IMediaItem mediaItem, TimeSpan timeFromStart) diff --git a/MediaManager/Platforms/Android/Media/MediaDescriptionAdapter.cs b/MediaManager/Platforms/Android/Media/MediaDescriptionAdapter.cs index 8b28b704..adc0f939 100644 --- a/MediaManager/Platforms/Android/Media/MediaDescriptionAdapter.cs +++ b/MediaManager/Platforms/Android/Media/MediaDescriptionAdapter.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Android.App; using Android.Graphics; using Android.Runtime; @@ -38,7 +39,16 @@ public string GetCurrentContentTitle(IPlayer player) public Bitmap GetCurrentLargeIcon(IPlayer player, PlayerNotificationManager.BitmapCallback callback) { - return MediaManager.Queue.ElementAtOrDefault(player.CurrentWindowIndex)?.GetCover(); + var mediaItem = MediaManager.Queue.ElementAtOrDefault(player.CurrentWindowIndex); + if (mediaItem != null) + { + Task.Run(async () => + { + var image = await MediaManager.Extractor.GetMediaImage(mediaItem).ConfigureAwait(false) as Bitmap; + callback.OnBitmap(image); + }).ConfigureAwait(false); + } + return null; } public string GetCurrentSubText(IPlayer player) diff --git a/MediaManager/Platforms/Android/Media/MediaItemExtensions.cs b/MediaManager/Platforms/Android/Media/MediaItemExtensions.cs index c764a361..5118124a 100644 --- a/MediaManager/Platforms/Android/Media/MediaItemExtensions.cs +++ b/MediaManager/Platforms/Android/Media/MediaItemExtensions.cs @@ -69,7 +69,7 @@ public static IMediaSource ToMediaSource(this MediaDescriptionCompat mediaDescri public static MediaDescriptionCompat ToMediaDescription(this IMediaItem item) { var description = new MediaDescriptionCompat.Builder() - .SetMediaId(item?.Id.ToString()) + .SetMediaId(item?.Id) .SetMediaUri(global::Android.Net.Uri.Parse(item?.MediaUri)) .SetTitle(item?.GetTitle()) .SetSubtitle(item?.GetContentTitle()) @@ -77,13 +77,13 @@ public static MediaDescriptionCompat ToMediaDescription(this IMediaItem item) .SetExtras(item?.Extras as Bundle); //It should be better to only set the uri to prevent loading images into memory - if (!string.IsNullOrEmpty(item?.DisplayIconUri)) - description.SetIconUri(global::Android.Net.Uri.Parse(item?.DisplayIconUri)); + if (!string.IsNullOrEmpty(item?.GetImageUri())) + description.SetIconUri(global::Android.Net.Uri.Parse(item?.GetImageUri())); else { - var cover = item?.GetCover(); - if (cover != null) - description.SetIconBitmap(cover); + var image = item?.GetImage() as Bitmap; + if (image != null) + description.SetIconBitmap(image); } return description.Build(); @@ -143,12 +143,12 @@ public static IMediaItem ToMediaItem(this MediaMetadataCompat mediaMetadata) var item = new MediaItem(url); item.Advertisement = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyAdvertisement); item.Album = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyAlbum); - item.AlbumArt = mediaMetadata.GetBitmap(MediaMetadataCompat.MetadataKeyAlbumArt); + item.AlbumImage = mediaMetadata.GetBitmap(MediaMetadataCompat.MetadataKeyAlbumArt); item.AlbumArtist = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyAlbumArtist); - item.AlbumArtUri = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyAlbumArtUri); - item.Art = mediaMetadata.GetBitmap(MediaMetadataCompat.MetadataKeyArt); + item.AlbumImageUri = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyAlbumArtUri); + item.Image = mediaMetadata.GetBitmap(MediaMetadataCompat.MetadataKeyArt); item.Artist = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyArtist); - item.ArtUri = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyArtUri); + item.ImageUri = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyArtUri); item.Author = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyAuthor); //item.BtFolderType = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyBtFolderType); item.Compilation = mediaMetadata.GetString(MediaMetadataCompat.MetadataKeyCompilation); @@ -176,39 +176,5 @@ public static IMediaItem ToMediaItem(this MediaMetadataCompat mediaMetadata) item.IsMetadataExtracted = true; return item; } - - //TODO: Move to Extractor - public static Bitmap GetCover(this IMediaItem mediaItem) - { - if (mediaItem.AlbumArt is Bitmap bitmap) - return bitmap; - else if (mediaItem.Art is Bitmap artBitmap) - return artBitmap; - else if (!string.IsNullOrEmpty(mediaItem.ArtUri)) - { - return GetImageBitmapFromUrl(mediaItem.ArtUri); - } - else if (!string.IsNullOrEmpty(mediaItem.AlbumArtUri)) - { - return GetImageBitmapFromUrl(mediaItem.AlbumArtUri); - } - return null; - } - - private static Bitmap GetImageBitmapFromUrl(string url) - { - Bitmap imageBitmap = null; - - using (var webClient = new System.Net.WebClient()) - { - var imageBytes = webClient.DownloadData(url); - if (imageBytes != null && imageBytes.Length > 0) - { - imageBitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length); - } - } - - return imageBitmap; - } } } diff --git a/MediaManager/Platforms/Android/Media/ResourceImageProvider.cs b/MediaManager/Platforms/Android/Media/ResourceImageProvider.cs index 0d3babc0..b9f8397c 100644 --- a/MediaManager/Platforms/Android/Media/ResourceImageProvider.cs +++ b/MediaManager/Platforms/Android/Media/ResourceImageProvider.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Android.Content.Res; using Android.Graphics; using MediaManager.Library; @@ -11,28 +12,25 @@ public class ResourceImageProvider : IMediaItemImageProvider protected MediaManagerImplementation MediaManager => CrossMediaManager.Android; protected Resources Resources => Resources.System; - public Task ProvideImage(IMediaItem mediaItem) + public async Task ProvideImage(IMediaItem mediaItem) { object image = null; try { var artId = int.MinValue; - int.TryParse(mediaItem.ArtUri, out artId); + int.TryParse(mediaItem.ImageUri, out artId); if (artId == int.MinValue) - int.TryParse(mediaItem.AlbumArtUri, out artId); + int.TryParse(mediaItem.AlbumImageUri, out artId); if (artId != int.MinValue) - image = BitmapFactory.DecodeResource(Resources, artId); - - //if(image == null) - // image = BitmapFactory.DecodeResource(Resources, MediaManager.NotificationIconResource); + image = await BitmapFactory.DecodeResourceAsync(Resources, artId).ConfigureAwait(false); } - catch + catch (Exception ex) { - + Console.WriteLine(ex.Message); } - return Task.FromResult(image); + return mediaItem.Image = image; } } } diff --git a/MediaManager/Platforms/Android/Media/UriImageProvider.cs b/MediaManager/Platforms/Android/Media/UriImageProvider.cs index bc5a5b4e..70335220 100644 --- a/MediaManager/Platforms/Android/Media/UriImageProvider.cs +++ b/MediaManager/Platforms/Android/Media/UriImageProvider.cs @@ -11,19 +11,28 @@ public class UriImageProvider : IMediaItemImageProvider public async Task ProvideImage(IMediaItem mediaItem) { object image = null; - if (!string.IsNullOrEmpty(mediaItem.ArtUri)) + try { - try + if (!string.IsNullOrEmpty(mediaItem.ImageUri)) { - var url = new Java.Net.URL(mediaItem.ArtUri); - image = await Task.Run(() => BitmapFactory.DecodeStreamAsync(url.OpenStream())); + mediaItem.Image = image = await GetBitmapFromUrl(mediaItem.ImageUri).ConfigureAwait(false); } - catch (Exception ex) + if (image == null && !string.IsNullOrEmpty(mediaItem.AlbumImageUri)) { - Console.WriteLine(ex.Message); + mediaItem.AlbumImage = image = await GetBitmapFromUrl(mediaItem.AlbumImageUri).ConfigureAwait(false); } } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } return image; } + + protected virtual async Task GetBitmapFromUrl(string uri) + { + var url = new Java.Net.URL(uri); + return await Task.Run(() => BitmapFactory.DecodeStreamAsync(url.OpenStream())).ConfigureAwait(false); + } } } diff --git a/MediaManager/Platforms/Android/MediaSession/MediaBrowserService.cs b/MediaManager/Platforms/Android/MediaSession/MediaBrowserService.cs index 3ac796e1..3d8696a0 100644 --- a/MediaManager/Platforms/Android/MediaSession/MediaBrowserService.cs +++ b/MediaManager/Platforms/Android/MediaSession/MediaBrowserService.cs @@ -135,6 +135,7 @@ protected virtual void PrepareNotificationManager() PlayerNotificationManager.SetOngoing(true); PlayerNotificationManager.SetUsePlayPauseActions(MediaManager.Notification.ShowPlayPauseControls); PlayerNotificationManager.SetUseNavigationActions(MediaManager.Notification.ShowNavigationControls); + PlayerNotificationManager.SetSmallIcon(MediaManager.NotificationIconResource); //Must be called to start the connection (MediaManager.Notification as Notifications.NotificationManager).Player = MediaManager.Player; diff --git a/MediaManager/Platforms/Apple/Media/AVAssetProvider.cs b/MediaManager/Platforms/Apple/Media/AVAssetProvider.cs index d8246016..5282613c 100644 --- a/MediaManager/Platforms/Apple/Media/AVAssetProvider.cs +++ b/MediaManager/Platforms/Apple/Media/AVAssetProvider.cs @@ -4,16 +4,12 @@ using System.Threading.Tasks; using AVFoundation; using CoreMedia; -using Foundation; using MediaManager.Library; using MediaManager.Media; -#if __IOS__ || __TVOS__ -using UIKit; -#endif namespace MediaManager.Platforms.Apple.Media { - public class AVAssetProvider : IMediaItemMetadataProvider, IMediaItemImageProvider, IMediaItemVideoFrameProvider + public class AVAssetProvider : IMediaItemMetadataProvider, IMediaItemVideoFrameProvider { public AVAssetProvider() { @@ -48,7 +44,7 @@ public async Task ProvideMetadata(IMediaItem mediaItem) //AVMetadata.CommonKeyType }; - var url = GetUrlFor(mediaItem); + var url = mediaItem.GetNSUrl(); var asset = AVAsset.FromUrl(url); await asset.LoadValuesTaskAsync(assetsToLoad.ToArray()); @@ -77,52 +73,9 @@ public async Task ProvideMetadata(IMediaItem mediaItem) return mediaItem; } - protected NSUrl GetUrlFor(IMediaItem mediaItem) - { - var isLocallyAvailable = mediaItem.MediaLocation.IsLocal(); - - var url = isLocallyAvailable ? new NSUrl(mediaItem.MediaUri, false) : new NSUrl(mediaItem.MediaUri); - - return url; - } - - public async Task ProvideImage(IMediaItem mediaItem) - { - if (!string.IsNullOrEmpty(mediaItem.ArtUri)) - { -#if __IOS__ || __TVOS__ - var image = UIImage.LoadFromData(NSData.FromUrl(new NSUrl(mediaItem.ArtUri))); - mediaItem.AlbumArt = image; - - return image; -#endif - } - else - { - var assetsToLoad = new List - { - AVMetadata.CommonKeyArtwork - }; - - var url = GetUrlFor(mediaItem); - var asset = AVAsset.FromUrl(url); - await asset.LoadValuesTaskAsync(assetsToLoad.ToArray()); - - var metadataDict = asset.CommonMetadata.ToDictionary(t => t.CommonKey, t => t); - -#if __IOS__ || __TVOS__ - var image = UIImage.LoadFromData(metadataDict.GetValueOrDefault(AVMetadata.CommonKeyArtwork)?.DataValue); - mediaItem.AlbumArt = image; - - return image; -#endif - } - return null; - } - public Task ProvideVideoFrame(IMediaItem mediaItem, TimeSpan timeFromStart) { - var url = GetUrlFor(mediaItem); + var url = mediaItem.GetNSUrl(); var imageGenerator = new AVAssetImageGenerator(AVAsset.FromUrl(url)); imageGenerator.AppliesPreferredTrackTransform = true; var cgImage = imageGenerator.CopyCGImageAtTime(new CMTime((long)timeFromStart.TotalMilliseconds, 1000000), out var actualTime, out var error); diff --git a/MediaManager/Platforms/Apple/Media/AppleMediaExtractor.cs b/MediaManager/Platforms/Apple/Media/AppleMediaExtractor.cs index 64ffa835..32e3cfb2 100644 --- a/MediaManager/Platforms/Apple/Media/AppleMediaExtractor.cs +++ b/MediaManager/Platforms/Apple/Media/AppleMediaExtractor.cs @@ -16,6 +16,9 @@ public override IList CreateProviders() { var providers = base.CreateProviders(); providers.Add(new AVAssetProvider()); +#if __IOS__ || __TVOS__ + providers.Add(new Ios.Media.AVAssetImageProvider()); +#endif return providers; } diff --git a/MediaManager/Platforms/Apple/Media/MediaItemExtensions.cs b/MediaManager/Platforms/Apple/Media/MediaItemExtensions.cs new file mode 100644 index 00000000..14533934 --- /dev/null +++ b/MediaManager/Platforms/Apple/Media/MediaItemExtensions.cs @@ -0,0 +1,15 @@ +using Foundation; +using MediaManager.Library; +using MediaManager.Media; + +namespace MediaManager.Platforms.Apple.Media +{ + public static class MediaItemExtensions + { + public static NSUrl GetNSUrl(this IMediaItem mediaItem) + { + var isLocallyAvailable = mediaItem.MediaLocation.IsLocal(); + return isLocallyAvailable ? new NSUrl(mediaItem.MediaUri, false) : new NSUrl(mediaItem.MediaUri); + } + } +} diff --git a/MediaManager/Platforms/Apple/Notifications/NotificationManager.cs b/MediaManager/Platforms/Apple/Notifications/NotificationManager.cs index 78d69a82..30bfe6c8 100644 --- a/MediaManager/Platforms/Apple/Notifications/NotificationManager.cs +++ b/MediaManager/Platforms/Apple/Notifications/NotificationManager.cs @@ -146,7 +146,7 @@ public override void UpdateNotification() } #if __IOS__ || __TVOS__ - var cover = mediaItem.AlbumArt as UIKit.UIImage; + var cover = mediaItem.AlbumImage as UIKit.UIImage; if (cover != null) { diff --git a/MediaManager/Platforms/Ios/Media/AVAssetImageProvider.cs b/MediaManager/Platforms/Ios/Media/AVAssetImageProvider.cs new file mode 100644 index 00000000..71b825f0 --- /dev/null +++ b/MediaManager/Platforms/Ios/Media/AVAssetImageProvider.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AVFoundation; +using Foundation; +using MediaManager.Library; +using MediaManager.Media; +using MediaManager.Platforms.Apple.Media; +using UIKit; + +namespace MediaManager.Platforms.Ios.Media +{ + public class AVAssetImageProvider : IMediaItemImageProvider + { + public async Task ProvideImage(IMediaItem mediaItem) + { + object image = null; + try + { + if (!string.IsNullOrEmpty(mediaItem.ImageUri)) + { + mediaItem.Image = image = UIImage.LoadFromData(NSData.FromUrl(new NSUrl(mediaItem.ImageUri))); + } + if (image == null && !string.IsNullOrEmpty(mediaItem.AlbumImageUri)) + { + mediaItem.AlbumImage = image = UIImage.LoadFromData(NSData.FromUrl(new NSUrl(mediaItem.AlbumImageUri))); + } + if (image == null) + { + var assetsToLoad = new List + { + AVMetadata.CommonKeyArtwork + }; + + var url = mediaItem.GetNSUrl(); + var asset = AVAsset.FromUrl(url); + await asset.LoadValuesTaskAsync(assetsToLoad.ToArray()); + + var metadataDict = asset.CommonMetadata.ToDictionary(t => t.CommonKey, t => t); + + image = UIImage.LoadFromData(metadataDict.GetValueOrDefault(AVMetadata.CommonKeyArtwork)?.DataValue); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + return mediaItem.Image = image; + } + } +} diff --git a/MediaManager/Platforms/Tvos/MediaManagerImplementation.cs b/MediaManager/Platforms/Tvos/MediaManagerImplementation.cs deleted file mode 100644 index bde1f56a..00000000 --- a/MediaManager/Platforms/Tvos/MediaManagerImplementation.cs +++ /dev/null @@ -1,31 +0,0 @@ -using UIKit; - -namespace MediaManager -{ - [Foundation.Preserve(AllMembers = true)] - public class MediaManagerImplementation : AppleMediaManagerBase - { - public MediaManagerImplementation() - { - } - - protected bool _keepScreenOn; - public override bool KeepScreenOn - { - get - { - return _keepScreenOn; - } - set - { - if (SetProperty(ref _keepScreenOn, value)) - { - if (value && !UIApplication.SharedApplication.IdleTimerDisabled) - UIApplication.SharedApplication.IdleTimerDisabled = true; - else - UIApplication.SharedApplication.IdleTimerDisabled = false; - } - } - } - } -} diff --git a/MediaManager/Platforms/Tvos/Player/TvosMediaPlayer.cs b/MediaManager/Platforms/Tvos/Player/TvosMediaPlayer.cs deleted file mode 100644 index af92cef0..00000000 --- a/MediaManager/Platforms/Tvos/Player/TvosMediaPlayer.cs +++ /dev/null @@ -1,86 +0,0 @@ - -using System; -using AVFoundation; -using MediaManager.Platforms.Apple.Player; -using MediaManager.Platforms.Tvos.Video; -using MediaManager.Player; -using MediaManager.Video; - -namespace MediaManager.Platforms.Tvos.Player -{ - public class TvosMediaPlayer : AppleMediaPlayer, IMediaPlayer - { - public VideoView PlayerView => VideoView as VideoView; - - private IVideoView _videoView; - public override IVideoView VideoView - { - get => _videoView; - set - { - _videoView = value; - if (PlayerView != null) - { - PlayerView.PlayerViewController.Player = Player; - UpdateVideoView(); - } - } - } - - public override void UpdateVideoAspect(VideoAspectMode videoAspectMode) - { - if (PlayerView == null) - return; - - var playerViewController = PlayerView.PlayerViewController; - - switch (videoAspectMode) - { - case VideoAspectMode.None: - playerViewController.VideoGravity = AVLayerVideoGravity.Resize; - break; - case VideoAspectMode.AspectFit: - playerViewController.VideoGravity = AVLayerVideoGravity.ResizeAspect; - break; - case VideoAspectMode.AspectFill: - playerViewController.VideoGravity = AVLayerVideoGravity.ResizeAspectFill; - break; - default: - playerViewController.VideoGravity = AVLayerVideoGravity.ResizeAspect; - break; - } - } - - public override void UpdateShowPlaybackControls(bool showPlaybackControls) - { - if (PlayerView == null) - return; - - PlayerView.PlayerViewController.ShowsPlaybackControls = showPlaybackControls; - } - - protected override void Initialize() - { - base.Initialize(); - var audioSession = AVAudioSession.SharedInstance(); - try - { - audioSession.SetCategory(AVAudioSession.CategoryPlayback); - audioSession.SetActive(true, out var activationError); - if (activationError != null) - Console.WriteLine("Could not activate audio session {0}", activationError.LocalizedDescription); - } - catch - { - } - } - - protected override void Dispose(bool disposing) - { - var audioSession = AVAudioSession.SharedInstance(); - audioSession.SetActive(false); - - base.Dispose(disposing); - } - } -} diff --git a/MediaManager/Platforms/Tvos/Video/PlayerViewController.cs b/MediaManager/Platforms/Tvos/Video/PlayerViewController.cs deleted file mode 100644 index 651f4f3b..00000000 --- a/MediaManager/Platforms/Tvos/Video/PlayerViewController.cs +++ /dev/null @@ -1,29 +0,0 @@ -using AVKit; - -namespace MediaManager.Platforms.Tvos.Video -{ - public class PlayerViewController : AVPlayerViewController - { - protected static MediaManagerImplementation MediaManager => CrossMediaManager.Apple; - - public override void ViewWillAppear(bool animated) - { - base.ViewWillAppear(animated); - - if (MediaManager.MediaPlayer.AutoAttachVideoView && View.Superview is VideoView videoView) - MediaManager.MediaPlayer.VideoView = videoView; - } - - public override void ViewWillDisappear(bool animated) - { - base.ViewWillDisappear(animated); - - if (MediaManager.MediaPlayer.AutoAttachVideoView && MediaManager.MediaPlayer.VideoView == View.Superview) - { - MediaManager.MediaPlayer.VideoView = null; - } - - Player = null; - } - } -} diff --git a/MediaManager/Platforms/Tvos/Video/VideoView.cs b/MediaManager/Platforms/Tvos/Video/VideoView.cs deleted file mode 100644 index 37fa17c9..00000000 --- a/MediaManager/Platforms/Tvos/Video/VideoView.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.ComponentModel; -using AVKit; -using CoreGraphics; -using Foundation; -using MediaManager.Video; -using UIKit; - -namespace MediaManager.Platforms.Tvos.Video -{ - [DesignTimeVisible(true)] - public partial class VideoView : UIView, IVideoView - { - protected MediaManagerImplementation MediaManager => CrossMediaManager.Apple; - - private AVPlayerViewController _playerViewController; - public AVPlayerViewController PlayerViewController - { - get - { - if (_playerViewController == null) - { - PlayerViewController = new PlayerViewController(); - } - return _playerViewController; - } - - set - { - _playerViewController = value; - if (_playerViewController != null) - { - _playerViewController.View.Frame = Bounds; - AddSubview(_playerViewController.View); - (Superview?.NextResponder as UIViewController)?.AddChildViewController(_playerViewController); - } - } - } - - public VideoView() - { - InitView(); - } - - public VideoView(NSCoder coder) : base(coder) - { - InitView(); - } - - public VideoView(CGRect frame) : base(frame) - { - InitView(); - } - - protected VideoView(NSObjectFlag t) : base(t) - { - } - - protected internal VideoView(IntPtr handle) : base(handle) - { - } - - public virtual void InitView() - { - if (MediaManager.MediaPlayer.AutoAttachVideoView) - MediaManager.MediaPlayer.VideoView = this; - } - - protected override void Dispose(bool disposing) - { - if (MediaManager.MediaPlayer.AutoAttachVideoView && MediaManager.MediaPlayer.VideoView == this) - MediaManager.MediaPlayer.VideoView = null; - - base.Dispose(disposing); - } - } -}