Browse Source

fixes #521 - Use last fm as a secondary provider for artist images

Luke Pulverenti 11 years ago
parent
commit
4039c0f704

+ 2 - 0
MediaBrowser.Controller/Entities/Audio/Artist.cs

@@ -6,6 +6,8 @@ namespace MediaBrowser.Controller.Entities.Audio
     /// </summary>
     public class Artist : BaseItem, IItemByName
     {
+        public string LastFmImageUrl { get; set; }
+        
         /// <summary>
         /// Gets the user data key.
         /// </summary>

+ 1 - 0
MediaBrowser.Controller/Entities/Audio/MusicArtist.cs

@@ -6,5 +6,6 @@ namespace MediaBrowser.Controller.Entities.Audio
     /// </summary>
     public class MusicArtist : Folder
     {
+        public string LastFmImageUrl { get; set; }
     }
 }

+ 1 - 0
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -77,6 +77,7 @@
     <Compile Include="Music\FanArtUpdatesPrescanTask.cs" />
     <Compile Include="Music\LastfmAlbumProvider.cs" />
     <Compile Include="Music\LastfmArtistByNameProvider.cs" />
+    <Compile Include="Music\LastFmArtistImageProvider.cs" />
     <Compile Include="Music\LastfmArtistProvider.cs" />
     <Compile Include="Music\LastfmBaseProvider.cs" />
     <Compile Include="Music\LastfmHelper.cs" />

+ 8 - 19
MediaBrowser.Providers/Music/ArtistsPostScanTask.cs

@@ -63,28 +63,17 @@ namespace MediaBrowser.Providers.Music
                     backdrops.InsertRange(0, artist.BackdropImagePaths);
                     artist.BackdropImagePaths = backdrops.Distinct(StringComparer.OrdinalIgnoreCase)
                         .ToList();
-
-                    if (!artist.LockedFields.Contains(MetadataFields.Genres))
-                    {
-                        // Merge genres
-                        var genres = musicArtist.Genres.ToList();
-                        genres.InsertRange(0, artist.Genres);
-                        artist.Genres = genres.Distinct(StringComparer.OrdinalIgnoreCase)
-                            .ToList();
-                    }
                 }
-                else
+
+                if (!artist.LockedFields.Contains(MetadataFields.Genres))
                 {
-                    if (!artist.LockedFields.Contains(MetadataFields.Genres))
-                    {
-                        // Avoid implicitly captured closure
-                        var artist1 = artist;
+                    // Avoid implicitly captured closure
+                    var artist1 = artist;
 
-                        artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name))
-                            .SelectMany(i => i.Genres)
-                            .Distinct(StringComparer.OrdinalIgnoreCase)
-                            .ToList();
-                    }
+                    artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name))
+                        .SelectMany(i => i.Genres)
+                        .Distinct(StringComparer.OrdinalIgnoreCase)
+                        .ToList();
                 }
 
                 numComplete++;

+ 8 - 0
MediaBrowser.Providers/Music/FanArtArtistProvider.cs

@@ -115,6 +115,14 @@ namespace MediaBrowser.Providers.Music
             }
         }
 
+        public override MetadataProviderPriority Priority
+        {
+            get
+            {
+                return MetadataProviderPriority.Fourth;
+            }
+        }
+
         /// <summary>
         /// Needses the refresh internal.
         /// </summary>

+ 120 - 0
MediaBrowser.Providers/Music/LastFmArtistImageProvider.cs

@@ -0,0 +1,120 @@
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Providers.Music
+{
+    /// <summary>
+    /// Class LastFmArtistImageProvider
+    /// </summary>
+    public class LastFmArtistImageProvider : BaseMetadataProvider
+    {
+        /// <summary>
+        /// The _provider manager
+        /// </summary>
+        private readonly IProviderManager _providerManager;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LastFmArtistImageProvider"/> class.
+        /// </summary>
+        /// <param name="logManager">The log manager.</param>
+        /// <param name="configurationManager">The configuration manager.</param>
+        /// <param name="providerManager">The provider manager.</param>
+        public LastFmArtistImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager) : 
+            base(logManager, configurationManager)
+        {
+            _providerManager = providerManager;
+        }
+
+        /// <summary>
+        /// Supportses the specified item.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+        public override bool Supports(BaseItem item)
+        {
+            return item is Artist || item is MusicArtist;
+        }
+
+        /// <summary>
+        /// Needses the refresh internal.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="providerInfo">The provider info.</param>
+        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+        protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
+        {
+            if (item.HasImage(ImageType.Primary))
+            {
+                return false;
+            }
+
+            if (string.IsNullOrWhiteSpace(GetImageUrl(item)))
+            {
+                return false;
+            }
+
+            return base.NeedsRefreshInternal(item, providerInfo);
+        }
+
+        /// <summary>
+        /// Fetches metadata and returns true or false indicating if any work that requires persistence was done
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="force">if set to <c>true</c> [force].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{System.Boolean}.</returns>
+        public override async Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
+        {
+            var url = GetImageUrl(item);
+
+            if (!string.IsNullOrWhiteSpace(url))
+            {
+                await _providerManager.SaveImage(item, url, LastfmBaseProvider.LastfmResourcePool, ImageType.Primary, null, cancellationToken)
+                                    .ConfigureAwait(false);
+            }
+
+            SetLastRefreshed(item, DateTime.UtcNow);
+            return true;
+        }
+
+        /// <summary>
+        /// Gets the priority.
+        /// </summary>
+        /// <value>The priority.</value>
+        public override MetadataProviderPriority Priority
+        {
+            get { return MetadataProviderPriority.Fifth; }
+        }
+
+        /// <summary>
+        /// Gets the image URL.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>System.String.</returns>
+        private string GetImageUrl(BaseItem item)
+        {
+            var musicArtist = item as MusicArtist;
+
+            if (musicArtist != null)
+            {
+                return musicArtist.LastFmImageUrl;
+            }
+
+            var artistByName = item as Artist;
+
+            if (artistByName != null)
+            {
+                return artistByName.LastFmImageUrl;
+            }
+
+            return null;
+        }
+    }
+}

+ 3 - 3
MediaBrowser.Providers/Music/LastfmAlbumProvider.cs

@@ -67,7 +67,7 @@ namespace MediaBrowser.Providers.Music
             return base.NeedsRefreshInternal(item, providerInfo);
         }
 
-        protected override async Task FetchLastfmData(BaseItem item, string id, CancellationToken cancellationToken)
+        protected override async Task FetchLastfmData(BaseItem item, string id, bool force, CancellationToken cancellationToken)
         {
             var album = (MusicAlbum)item;
 
@@ -165,9 +165,9 @@ namespace MediaBrowser.Providers.Music
             }
         }
         
-        protected override Task FetchData(BaseItem item, CancellationToken cancellationToken)
+        protected override Task FetchData(BaseItem item, bool force, CancellationToken cancellationToken)
         {
-            return FetchLastfmData(item, string.Empty, cancellationToken);
+            return FetchLastfmData(item, string.Empty, force, cancellationToken);
         }
 
         public override bool Supports(BaseItem item)

+ 3 - 3
MediaBrowser.Providers/Music/LastfmArtistByNameProvider.cs

@@ -72,20 +72,20 @@ namespace MediaBrowser.Providers.Music
         /// <param name="musicBrainzId">The music brainz id.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        protected override async Task FetchLastfmData(BaseItem item, string musicBrainzId, CancellationToken cancellationToken)
+        protected override async Task FetchLastfmData(BaseItem item, string musicBrainzId, bool force, CancellationToken cancellationToken)
         {
             var artist = (Artist)item;
 
             // See if we can avoid an http request by finding the matching MusicArtist entity
             var musicArtist = FindMusicArtist(artist, LibraryManager);
 
-            if (musicArtist != null)
+            if (musicArtist != null && !force)
             {
                 LastfmHelper.ProcessArtistData(musicArtist, artist);
             }
             else
             {
-                await base.FetchLastfmData(item, musicBrainzId, cancellationToken).ConfigureAwait(false);
+                await base.FetchLastfmData(item, musicBrainzId, force, cancellationToken).ConfigureAwait(false);
             }
         }
 

+ 10 - 2
MediaBrowser.Providers/Music/LastfmArtistProvider.cs

@@ -200,7 +200,7 @@ namespace MediaBrowser.Providers.Music
         /// <param name="musicBrainzId">The music brainz id.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        protected override async Task FetchLastfmData(BaseItem item, string musicBrainzId, CancellationToken cancellationToken)
+        protected override async Task FetchLastfmData(BaseItem item, string musicBrainzId, bool force, CancellationToken cancellationToken)
         {
             // Get artist info with provided id
             var url = RootUrl + string.Format("method=artist.getInfo&mbid={0}&api_key={1}&format=json", UrlEncode(musicBrainzId), ApiKey);
@@ -216,7 +216,15 @@ namespace MediaBrowser.Providers.Music
 
             }).ConfigureAwait(false))
             {
-                result = JsonSerializer.DeserializeFromStream<LastfmGetArtistResult>(json);
+                using (var reader = new StreamReader(json))
+                {
+                    var jsonText = await reader.ReadToEndAsync().ConfigureAwait(false);
+
+                    // Fix their bad json
+                    jsonText = jsonText.Replace("\"#text\"", "\"url\"");
+
+                    result = JsonSerializer.DeserializeFromString<LastfmGetArtistResult>(jsonText);
+                }
             }
 
             if (result != null && result.artist != null)

+ 13 - 6
MediaBrowser.Providers/Music/LastfmBaseProvider.cs

@@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Music
     /// </summary>
     public abstract class LastfmBaseProvider : BaseMetadataProvider
     {
-        protected static readonly SemaphoreSlim LastfmResourcePool = new SemaphoreSlim(4, 4);
+        internal static readonly SemaphoreSlim LastfmResourcePool = new SemaphoreSlim(4, 4);
 
         /// <summary>
         /// Initializes a new instance of the <see cref="LastfmBaseProvider" /> class.
@@ -100,7 +100,7 @@ namespace MediaBrowser.Providers.Music
         /// <param name="item">The item.</param>
         /// <param name="cancellationToken"></param>
         /// <returns>Task.</returns>
-        protected virtual async Task FetchData(BaseItem item, CancellationToken cancellationToken)
+        protected virtual async Task FetchData(BaseItem item, bool force, CancellationToken cancellationToken)
         {
             var id = item.GetProviderId(MetadataProviders.Musicbrainz) ?? await FindId(item, cancellationToken).ConfigureAwait(false);
             if (!string.IsNullOrWhiteSpace(id))
@@ -111,18 +111,18 @@ namespace MediaBrowser.Providers.Music
 
                 item.SetProviderId(MetadataProviders.Musicbrainz, id);
 
-                await FetchLastfmData(item, id, cancellationToken).ConfigureAwait(false);
+                await FetchLastfmData(item, id, force, cancellationToken).ConfigureAwait(false);
             }
             else
             {
                 Logger.Info("LastfmProvider could not find " + item.Name + ". Check name on Last.fm.");
             }
-            
+
         }
 
         protected abstract Task<string> FindId(BaseItem item, CancellationToken cancellationToken);
 
-        protected abstract Task FetchLastfmData(BaseItem item, string id, CancellationToken cancellationToken);
+        protected abstract Task FetchLastfmData(BaseItem item, string id, bool force, CancellationToken cancellationToken);
 
         /// <summary>
         /// Encodes an URL.
@@ -145,7 +145,7 @@ namespace MediaBrowser.Providers.Music
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            await FetchData(item, cancellationToken).ConfigureAwait(false);
+            await FetchData(item, force, cancellationToken).ConfigureAwait(false);
             SetLastRefreshed(item, DateTime.UtcNow);
             return true;
         }
@@ -187,6 +187,12 @@ namespace MediaBrowser.Providers.Music
         public List<LastfmFormationInfo> formationlist { get; set; }
     }
 
+    public class LastFmImage
+    {
+        public string url { get; set; }
+        public string size { get; set; }
+    }
+
     public class LastfmArtist
     {
         public string name { get; set; }
@@ -198,6 +204,7 @@ namespace MediaBrowser.Providers.Music
         public List<LastfmArtist> similar { get; set; }
         public LastfmTags tags { get; set; }
         public LastFmBio bio { get; set; }
+        public List<LastFmImage> image { get; set; }
     }
 
 

+ 34 - 0
MediaBrowser.Providers/Music/LastfmHelper.cs

@@ -31,6 +31,40 @@ namespace MediaBrowser.Providers.Music
             {
                 AddTags(artist, data.tags);
             }
+
+            var musicArtist = artist as MusicArtist;
+
+            if (musicArtist != null)
+            {
+                musicArtist.LastFmImageUrl = GetImageUrl(data);
+            }
+
+            var artistByName = artist as Artist;
+
+            if (artistByName != null)
+            {
+                artistByName.LastFmImageUrl = GetImageUrl(data);
+            }
+        }
+
+        private static string GetImageUrl(LastfmArtist data)
+        {
+            if (data.image == null)
+            {
+                return null;
+            }
+
+            var img = data.image.FirstOrDefault(i => string.Equals(i.size, "extralarge", StringComparison.OrdinalIgnoreCase)) ??
+                data.image.FirstOrDefault(i => string.Equals(i.size, "large", StringComparison.OrdinalIgnoreCase)) ?? 
+                data.image.FirstOrDefault(i => string.Equals(i.size, "medium", StringComparison.OrdinalIgnoreCase)) ?? 
+                data.image.FirstOrDefault();
+
+            if (img != null)
+            {
+                return img.url;
+            }
+
+            return null;
         }
 
         public static void ProcessArtistData(MusicArtist source, Artist target)