diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index b0044745c3..604aa318fe 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -110,6 +110,7 @@ + diff --git a/MediaBrowser.Controller/Providers/FanartBaseProvider.cs b/MediaBrowser.Controller/Providers/FanartBaseProvider.cs index 7a38fbb7a8..f775d0d3fc 100644 --- a/MediaBrowser.Controller/Providers/FanartBaseProvider.cs +++ b/MediaBrowser.Controller/Providers/FanartBaseProvider.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; using System; using MediaBrowser.Model.Logging; @@ -13,29 +14,44 @@ namespace MediaBrowser.Controller.Providers /// The LOG o_ FILE /// protected const string LOGO_FILE = "logo.png"; + /// /// The AR t_ FILE /// protected const string ART_FILE = "clearart.png"; + /// /// The THUM b_ FILE /// protected const string THUMB_FILE = "thumb.jpg"; + /// /// The DIS c_ FILE /// protected const string DISC_FILE = "disc.png"; + /// /// The BANNE r_ FILE /// protected const string BANNER_FILE = "banner.png"; + /// + /// The Backdrop + /// + protected const string BACKDROP_FILE = "backdrop.jpg"; + + /// + /// The Primary image + /// + protected const string PRIMARY_FILE = "folder.jpg"; + /// /// The API key /// protected const string APIKey = "5c6b04c68e904cfed1e6cbc9a9e683d4"; - protected FanartBaseProvider(ILogManager logManager) : base(logManager) + protected FanartBaseProvider(ILogManager logManager) + : base(logManager) { } @@ -49,8 +65,8 @@ namespace MediaBrowser.Controller.Providers { if (item.DontFetchMeta) return false; - return DateTime.UtcNow > (providerInfo.LastRefreshed.AddDays(Kernel.Instance.Configuration.MetadataRefreshDays)) - && ShouldFetch(item, providerInfo); + return DateTime.UtcNow > (providerInfo.LastRefreshed.AddDays(Kernel.Instance.Configuration.MetadataRefreshDays)) + && ShouldFetch(item, providerInfo); } /// @@ -59,10 +75,7 @@ namespace MediaBrowser.Controller.Providers /// true if [requires internet]; otherwise, false. public override bool RequiresInternet { - get - { - return true; - } + get { return true; } } /// @@ -84,6 +97,32 @@ namespace MediaBrowser.Controller.Providers { return false; } + #region Result Objects + + protected class FanArtImageInfo + { + public string id { get; set; } + public string url { get; set; } + public string likes { get; set; } + } + + protected class FanArtMusicInfo + { + public string mbid_id { get; set; } + public List musiclogo { get; set; } + public List artistbackground { get; set; } + public List artistthumb { get; set; } + public List hdmusiclogo { get; set; } + public List musicbanner { get; set; } + } + + protected class FanArtMusicResult + { + public FanArtMusicInfo result { get; set; } + } + + #endregion } + } diff --git a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs new file mode 100644 index 0000000000..fa7b67e582 --- /dev/null +++ b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs @@ -0,0 +1,240 @@ +using System.Collections.Specialized; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; + +namespace MediaBrowser.Controller.Providers.Music +{ + /// + /// Class FanArtArtistProvider + /// + class FanArtArtistProvider : FanartBaseProvider + { + /// + /// Gets the HTTP client. + /// + /// The HTTP client. + protected IHttpClient HttpClient { get; private set; } + + public FanArtArtistProvider(IHttpClient httpClient, ILogManager logManager) + : base(logManager) + { + if (httpClient == null) + { + throw new ArgumentNullException("httpClient"); + } + HttpClient = httpClient; + } + + /// + /// The fan art base URL + /// + protected string FanArtBaseUrl = "http://api.fanart.tv/webservice/artist/{0}/{1}/xml/all/1/1"; + + /// + /// Supportses the specified item. + /// + /// The item. + /// true if XXXX, false otherwise + public override bool Supports(BaseItem item) + { + return item is MusicArtist; + } + + /// + /// Shoulds the fetch. + /// + /// The item. + /// The provider info. + /// true if XXXX, false otherwise + protected override bool ShouldFetch(BaseItem item, BaseProviderInfo providerInfo) + { + var baseItem = item; + if (item.Path == null || item.DontFetchMeta || string.IsNullOrEmpty(baseItem.GetProviderId(MetadataProviders.Musicbrainz))) return false; //nothing to do + var artExists = item.ResolveArgs.ContainsMetaFileByName(ART_FILE); + var logoExists = item.ResolveArgs.ContainsMetaFileByName(LOGO_FILE); + var discExists = item.ResolveArgs.ContainsMetaFileByName(DISC_FILE); + + return (!artExists && Kernel.Instance.Configuration.DownloadMovieArt) + || (!logoExists && Kernel.Instance.Configuration.DownloadMovieLogo) + || (!discExists && Kernel.Instance.Configuration.DownloadMovieDisc); + } + + /// + /// Fetches metadata and returns true or false indicating if any work that requires persistence was done + /// + /// The item. + /// if set to true [force]. + /// The cancellation token. + /// Task{System.Boolean}. + protected override async Task FetchAsyncInternal(BaseItem item, bool force, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var artist = item; + if (ShouldFetch(artist, artist.ProviderData.GetValueOrDefault(Id, new BaseProviderInfo { ProviderId = Id }))) + { + var url = string.Format(FanArtBaseUrl, APIKey, artist.GetProviderId(MetadataProviders.Musicbrainz)); + var doc = new XmlDocument(); + + try + { + using (var xml = await HttpClient.Get(url, Kernel.Instance.ResourcePools.FanArt, cancellationToken).ConfigureAwait(false)) + { + doc.Load(xml); + } + } + catch (HttpException) + { + } + + cancellationToken.ThrowIfCancellationRequested(); + + if (doc.HasChildNodes) + { + string path; + var hd = Kernel.Instance.Configuration.DownloadHDFanArt ? "hd" : ""; + if (Kernel.Instance.Configuration.DownloadMovieLogo && !item.ResolveArgs.ContainsMetaFileByName(LOGO_FILE)) + { + var node = + doc.SelectSingleNode("//fanart/music/musiclogos/" + hd + "musiclogo/@url") ?? + doc.SelectSingleNode("//fanart/music/musiclogos/musiclogo/@url"); + path = node != null ? node.Value : null; + if (!string.IsNullOrEmpty(path)) + { + Logger.Debug("FanArtProvider getting ClearLogo for " + artist.Name); + try + { + artist.SetImage(ImageType.Logo, await Kernel.Instance.ProviderManager.DownloadAndSaveImage(artist, path, LOGO_FILE, Kernel.Instance.ResourcePools.FanArt, cancellationToken).ConfigureAwait(false)); + } + catch (HttpException) + { + } + catch (IOException) + { + + } + } + } + cancellationToken.ThrowIfCancellationRequested(); + + if (!item.ResolveArgs.ContainsMetaFileByName(BACKDROP_FILE)) + { + var nodes = doc.SelectNodes("//fanart/music/artistbackgrounds//@url"); + if (nodes != null) + { + var numBackdrops = 0; + foreach (XmlNode node in nodes) + { + path = node.Value; + if (!string.IsNullOrEmpty(path)) + { + Logger.Debug("FanArtProvider getting Backdrop for " + artist.Name); + try + { + artist.BackdropImagePaths.Add(await Kernel.Instance.ProviderManager.DownloadAndSaveImage(artist, path, ("Backdrop"+(numBackdrops > 0 ? numBackdrops.ToString() : "")+".jpg"), Kernel.Instance.ResourcePools.FanArt, cancellationToken).ConfigureAwait(false)); + numBackdrops++; + if (numBackdrops >= Kernel.Instance.Configuration.MaxBackdrops) break; + } + catch (HttpException) + { + } + catch (IOException) + { + + } + } + } + + } + + } + + cancellationToken.ThrowIfCancellationRequested(); + + if (Kernel.Instance.Configuration.DownloadMovieArt && !item.ResolveArgs.ContainsMetaFileByName(ART_FILE)) + { + var node = + doc.SelectSingleNode("//fanart/music/musicarts/" + hd + "musicart/@url") ?? + doc.SelectSingleNode("//fanart/music/musicarts/musicart/@url"); + path = node != null ? node.Value : null; + if (!string.IsNullOrEmpty(path)) + { + Logger.Debug("FanArtProvider getting ClearArt for " + artist.Name); + try + { + artist.SetImage(ImageType.Art, await Kernel.Instance.ProviderManager.DownloadAndSaveImage(artist, path, ART_FILE, Kernel.Instance.ResourcePools.FanArt, cancellationToken).ConfigureAwait(false)); + } + catch (HttpException) + { + } + catch (IOException) + { + + } + } + } + cancellationToken.ThrowIfCancellationRequested(); + + if (Kernel.Instance.Configuration.DownloadMovieBanner && !item.ResolveArgs.ContainsMetaFileByName(BANNER_FILE)) + { + var node = doc.SelectSingleNode("//fanart/music/musicbanners/"+hd+"musicbanner/@url") ?? + doc.SelectSingleNode("//fanart/music/musicbanners/musicbanner/@url"); + path = node != null ? node.Value : null; + if (!string.IsNullOrEmpty(path)) + { + Logger.Debug("FanArtProvider getting Banner for " + artist.Name); + try + { + artist.SetImage(ImageType.Banner, await Kernel.Instance.ProviderManager.DownloadAndSaveImage(artist, path, BANNER_FILE, Kernel.Instance.ResourcePools.FanArt, cancellationToken).ConfigureAwait(false)); + } + catch (HttpException) + { + } + catch (IOException) + { + + } + } + } + + cancellationToken.ThrowIfCancellationRequested(); + + // Artist thumbs are actually primary images (they are square/portrait) + if (!item.ResolveArgs.ContainsMetaFileByName(PRIMARY_FILE)) + { + var node = doc.SelectSingleNode("//fanart/music/artistthumbs/artistthumb/@url"); + path = node != null ? node.Value : null; + if (!string.IsNullOrEmpty(path)) + { + Logger.Debug("FanArtProvider getting Primary image for " + artist.Name); + try + { + artist.SetImage(ImageType.Primary, await Kernel.Instance.ProviderManager.DownloadAndSaveImage(artist, path, PRIMARY_FILE, Kernel.Instance.ResourcePools.FanArt, cancellationToken).ConfigureAwait(false)); + } + catch (HttpException) + { + } + catch (IOException) + { + + } + } + } + } + } + SetLastRefreshed(artist, DateTime.UtcNow); + return true; + } + } +} diff --git a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs index 5203b6f06b..5589c5c036 100644 --- a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs +++ b/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Net; +using MediaBrowser.Model.Entities; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Model.Logging; diff --git a/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs index 54792932e3..ff46bde14f 100644 --- a/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs +++ b/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs @@ -195,6 +195,8 @@ namespace MediaBrowser.Controller.Providers.Music cancellationToken.ThrowIfCancellationRequested(); + item.SetProviderId(MetadataProviders.Musicbrainz, id); + await FetchLastfmData(item, id, cancellationToken).ConfigureAwait(false); } else