diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-01-30 23:50:09 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-01-30 23:50:09 -0500 |
| commit | 9685b81db5b975f57739a9dcc6c2cdb6c4c4dbcf (patch) | |
| tree | e9046e6d8e3df2f205b48fbcd9389bdb18290b55 | |
| parent | 117c1b76b2f7a09024f308b1aa692a1e5282d1c5 (diff) | |
convert artist providers
37 files changed, 847 insertions, 1127 deletions
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index c4981a7fa..bfa2b645a 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -801,7 +801,7 @@ namespace MediaBrowser.Api.Images await entity.RefreshMetadata(new MetadataRefreshOptions { - ImageRefreshMode = MetadataRefreshMode.None, + ImageRefreshMode = ImageRefreshMode.ValidationOnly, ForceSave = true }, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index b84a8f4f7..37bf0c1ca 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -284,7 +284,7 @@ namespace MediaBrowser.Api.Images await item.RefreshMetadata(new MetadataRefreshOptions { ForceSave = true, - ImageRefreshMode = MetadataRefreshMode.None, + ImageRefreshMode = ImageRefreshMode.ValidationOnly, MetadataRefreshMode = MetadataRefreshMode.None }, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 860d34fd8..b2d95ed30 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -69,13 +69,6 @@ namespace MediaBrowser.Controller.Entities.Audio return base.GetClientTypeName(); } - /// <summary> - /// Gets or sets the last fm image URL. - /// </summary> - /// <value>The last fm image URL.</value> - public string LastFmImageUrl { get; set; } - public string LastFmImageSize { get; set; } - public MusicArtist() { UserItemCountList = new List<ItemByNameCounts>(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 06ebe8905..f12532204 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1492,7 +1492,7 @@ namespace MediaBrowser.Controller.Entities return RefreshMetadata(new MetadataRefreshOptions { ForceSave = true, - ImageRefreshMode = MetadataRefreshMode.None, + ImageRefreshMode = ImageRefreshMode.ValidationOnly, MetadataRefreshMode = MetadataRefreshMode.None }, CancellationToken.None); diff --git a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs index c1951038c..746157bb3 100644 --- a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs +++ b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs @@ -126,7 +126,7 @@ namespace MediaBrowser.Controller.MediaInfo { if (!IsEligibleForChapterImageExtraction(video)) { - return true; + extractImages = false; } var success = true; @@ -187,6 +187,11 @@ namespace MediaBrowser.Controller.MediaInfo break; } } + else if (!string.IsNullOrEmpty(chapter.ImagePath)) + { + chapter.ImagePath = null; + changesMade = true; + } } else if (!string.Equals(path, chapter.ImagePath, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index d6e8a3afe..27de50ef8 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -22,11 +22,21 @@ namespace MediaBrowser.Controller.Providers /// </summary> [Obsolete] public bool ResetResolveArgs { get; set; } + + public MetadataRefreshOptions() + { + ResetResolveArgs = true; + } } public class ImageRefreshOptions { - public MetadataRefreshMode ImageRefreshMode { get; set; } + public ImageRefreshMode ImageRefreshMode { get; set; } + + public ImageRefreshOptions() + { + ImageRefreshMode = ImageRefreshMode.Default; + } } public enum MetadataRefreshMode @@ -46,4 +56,22 @@ namespace MediaBrowser.Controller.Providers /// </summary> FullRefresh } + + public enum ImageRefreshMode + { + /// <summary> + /// The default + /// </summary> + Default, + + /// <summary> + /// Existing images will be validated + /// </summary> + ValidationOnly, + + /// <summary> + /// All providers will be executed to search for new metadata + /// </summary> + FullRefresh + } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 424c9c48e..716be54d2 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -245,7 +245,6 @@ namespace MediaBrowser.Model.Configuration EnableHttpLevelLogging = true; EnableDashboardResponseCaching = true; - EnableFanArtUpdates = true; EnableVideoImageExtraction = true; EnableMovieChapterImageExtraction = true; EnableEpisodeChapterImageExtraction = false; diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index 62b2e627f..b9b4e40d7 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -1,11 +1,15 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; +using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -14,11 +18,13 @@ namespace MediaBrowser.Providers.BoxSets public class BoxSetMetadataService : ConcreteMetadataService<BoxSet> { private readonly ILibraryManager _libraryManager; + private readonly ILocalizationManager _iLocalizationManager; - public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager) + public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager, ILocalizationManager iLocalizationManager) : base(serverConfigurationManager, logger, providerManager, providerRepo) { _libraryManager = libraryManager; + _iLocalizationManager = iLocalizationManager; } /// <summary> @@ -37,5 +43,36 @@ namespace MediaBrowser.Providers.BoxSets { return _libraryManager.UpdateItem(item, reason, cancellationToken); } + + protected override ItemUpdateType AfterMetadataRefresh(BoxSet item) + { + var updateType = base.AfterMetadataRefresh(item); + + if (!item.LockedFields.Contains(MetadataFields.OfficialRating)) + { + var currentOfficialRating = item.OfficialRating; + + // Gather all possible ratings + var ratings = item.RecursiveChildren + .Concat(item.GetLinkedChildren()) + .Where(i => i is Movie || i is Series) + .Select(i => i.OfficialRating) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Select(i => new Tuple<string, int?>(i, _iLocalizationManager.GetRatingLevel(i))) + .OrderBy(i => i.Item2 ?? 1000) + .Select(i => i.Item1); + + item.OfficialRating = ratings.FirstOrDefault() ?? item.OfficialRating; + + if (!string.Equals(currentOfficialRating ?? string.Empty, item.OfficialRating ?? string.Empty, + StringComparison.OrdinalIgnoreCase)) + { + updateType = updateType | ItemUpdateType.MetadataDownload; + } + } + + return updateType; + } } } diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs index 961982bfd..2e75a66cb 100644 --- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs +++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetImageProvider.cs @@ -1,29 +1,25 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Net; +using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Movies; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace MediaBrowser.Providers.BoxSets { class MovieDbBoxSetImageProvider : IRemoteImageProvider { - private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClient _httpClient; - public MovieDbBoxSetImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient) + public MovieDbBoxSetImageProvider(IHttpClient httpClient) { - _jsonSerializer = jsonSerializer; _httpClient = httpClient; } @@ -163,33 +159,6 @@ namespace MediaBrowser.Providers.BoxSets .ThenByDescending(i => i.vote_count); } - /// <summary> - /// Fetches the images. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="jsonSerializer">The json serializer.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{MovieImages}.</returns> - private async Task<MovieDbProvider.Images> FetchImages(BaseItem item, IJsonSerializer jsonSerializer, - CancellationToken cancellationToken) - { - await MovieDbProvider.Current.EnsureMovieInfo(item, cancellationToken).ConfigureAwait(false); - - var path = MovieDbProvider.Current.GetDataFilePath(item); - - if (!string.IsNullOrEmpty(path)) - { - var fileInfo = new FileInfo(path); - - if (fileInfo.Exists) - { - return jsonSerializer.DeserializeFromFile<MovieDbProvider.CompleteMovieData>(path).images; - } - } - - return null; - } - public int Order { get { return 0; } diff --git a/MediaBrowser.Providers/FanartBaseProvider.cs b/MediaBrowser.Providers/FanartBaseProvider.cs deleted file mode 100644 index f0f731809..000000000 --- a/MediaBrowser.Providers/FanartBaseProvider.cs +++ /dev/null @@ -1,98 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Logging; -using System.Collections.Generic; -using System.Threading; - -namespace MediaBrowser.Providers -{ - /// <summary> - /// Class FanartBaseProvider - /// </summary> - public abstract class FanartBaseProvider : BaseMetadataProvider - { - internal static readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3); - - /// <summary> - /// The LOG o_ FILE - /// </summary> - protected const string LogoFile = "logo.png"; - - /// <summary> - /// The AR t_ FILE - /// </summary> - protected const string ArtFile = "clearart.png"; - - /// <summary> - /// The THUM b_ FILE - /// </summary> - protected const string ThumbFile = "thumb.jpg"; - - /// <summary> - /// The DIS c_ FILE - /// </summary> - protected const string DiscFile = "disc.png"; - - /// <summary> - /// The BANNE r_ FILE - /// </summary> - protected const string BannerFile = "banner.png"; - - /// <summary> - /// The Backdrop - /// </summary> - protected const string BackdropFile = "backdrop.jpg"; - - /// <summary> - /// The Primary image - /// </summary> - protected const string PrimaryFile = "folder.jpg"; - - /// <summary> - /// The API key - /// </summary> - internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4"; - - protected FanartBaseProvider(ILogManager logManager, IServerConfigurationManager configurationManager) - : base(logManager, configurationManager) - { - } - - /// <summary> - /// Gets a value indicating whether [requires internet]. - /// </summary> - /// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value> - public override bool RequiresInternet - { - get { return true; } - } - - #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<FanArtImageInfo> musiclogo { get; set; } - public List<FanArtImageInfo> artistbackground { get; set; } - public List<FanArtImageInfo> artistthumb { get; set; } - public List<FanArtImageInfo> hdmusiclogo { get; set; } - public List<FanArtImageInfo> musicbanner { get; set; } - } - - protected class FanArtMusicResult - { - public FanArtMusicInfo result { get; set; } - } - - #endregion - - } - -} diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index d946f9cbd..d8d9ee0ca 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -112,7 +112,7 @@ namespace MediaBrowser.Providers.Manager } // Next run remote image providers, but only if local image providers didn't throw an exception - if (!localImagesFailed && options.ImageRefreshMode != MetadataRefreshMode.None) + if (!localImagesFailed && options.ImageRefreshMode != ImageRefreshMode.ValidationOnly) { var providers = GetNonLocalImageProviders(item, lastResult.DateLastImagesRefresh.HasValue, options).ToList(); @@ -125,6 +125,8 @@ namespace MediaBrowser.Providers.Manager refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow); refreshResult.AddImageProvidersRefreshed(result.Providers); } + + updateType = updateType | AfterMetadataRefresh(itemOfType); } var providersHadChanges = updateType > ItemUpdateType.Unspecified; @@ -147,6 +149,15 @@ namespace MediaBrowser.Providers.Manager } /// <summary> + /// Afters the metadata refresh. + /// </summary> + /// <param name="item">The item.</param> + protected virtual ItemUpdateType AfterMetadataRefresh(TItemType item) + { + return ItemUpdateType.Unspecified; + } + + /// <summary> /// Gets the providers. /// </summary> /// <param name="item">The item.</param> @@ -200,7 +211,7 @@ namespace MediaBrowser.Providers.Manager }).ToList(); // Run all if either of these flags are true - var runAllProviders = options.ImageRefreshMode == MetadataRefreshMode.FullRefresh || !hasRefreshedImages; + var runAllProviders = options.ImageRefreshMode == ImageRefreshMode.FullRefresh || !hasRefreshedImages; if (!runAllProviders) { diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 06c70d75d..83c628e23 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -80,7 +80,6 @@ <Compile Include="Manager\MetadataService.cs" /> <Compile Include="BaseXmlProvider.cs" /> <Compile Include="CollectionFolderImageProvider.cs" /> - <Compile Include="FanartBaseProvider.cs" /> <Compile Include="FolderProviderFromXml.cs" /> <Compile Include="Games\GameXmlParser.cs" /> <Compile Include="Games\GameProviderFromXml.cs" /> @@ -101,6 +100,8 @@ <Compile Include="Movies\ManualMovieDbImageProvider.cs" /> <Compile Include="Movies\ManualFanartMovieImageProvider.cs" /> <Compile Include="MusicGenres\MusicGenreMetadataService.cs" /> + <Compile Include="Music\ArtistMetadataService.cs" /> + <Compile Include="Music\LastFmArtistProvider.cs" /> <Compile Include="People\MovieDbPersonImageProvider.cs" /> <Compile Include="Movies\MovieUpdatesPrescanTask.cs" /> <Compile Include="Movies\MovieXmlParser.cs" /> @@ -112,18 +113,15 @@ <Compile Include="Movies\OpenMovieDatabaseProvider.cs" /> <Compile Include="Music\AlbumInfoFromSongProvider.cs" /> <Compile Include="Music\AlbumProviderFromXml.cs" /> - <Compile Include="Music\ArtistInfoFromSongProvider.cs" /> - <Compile Include="Music\ArtistProviderFromXml.cs" /> + <Compile Include="Music\ArtistXmlProvider.cs" /> <Compile Include="Music\FanArtAlbumProvider.cs" /> - <Compile Include="Music\FanArtArtistProvider.cs" /> <Compile Include="Music\FanArtUpdatesPrescanTask.cs" /> <Compile Include="Music\LastfmAlbumProvider.cs" /> <Compile Include="Music\LastFmImageProvider.cs" /> - <Compile Include="Music\LastfmArtistProvider.cs" /> <Compile Include="Music\LastfmBaseProvider.cs" /> <Compile Include="Music\LastfmHelper.cs" /> <Compile Include="Music\ManualFanartAlbumProvider.cs" /> - <Compile Include="Music\ManualFanartArtistProvider.cs" /> + <Compile Include="Music\FanartArtistProvider.cs" /> <Compile Include="Music\ManualLastFmImageProvider.cs" /> <Compile Include="Music\MusicBrainzAlbumProvider.cs" /> <Compile Include="Music\MusicVideoXmlParser.cs" /> diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs index 3c8fd4612..2cf403b09 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs @@ -17,13 +17,14 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Net; using System.Net; +using MediaBrowser.Providers.Music; namespace MediaBrowser.Providers.Movies { /// <summary> /// Class FanArtMovieProvider /// </summary> - class FanArtMovieProvider : FanartBaseProvider + class FanArtMovieProvider : BaseMetadataProvider { /// <summary> /// Gets the HTTP client. @@ -228,7 +229,7 @@ namespace MediaBrowser.Providers.Movies { cancellationToken.ThrowIfCancellationRequested(); - var url = string.Format(FanArtBaseUrl, ApiKey, tmdbId); + var url = string.Format(FanArtBaseUrl, FanartArtistProvider.ApiKey, tmdbId); var xmlPath = GetFanartXmlPath(tmdbId); @@ -237,7 +238,7 @@ namespace MediaBrowser.Providers.Movies using (var response = await HttpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = FanArtResourcePool, + ResourcePool = FanartArtistProvider.FanArtResourcePool, CancellationToken = cancellationToken }).ConfigureAwait(false)) @@ -318,7 +319,7 @@ namespace MediaBrowser.Providers.Movies { foreach (var image in images.Where(i => i.Type == ImageType.Backdrop)) { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, null, cancellationToken) + await _providerManager.SaveImage(item, image.Url, FanartArtistProvider.FanArtResourcePool, ImageType.Backdrop, null, cancellationToken) .ConfigureAwait(false); if (item.BackdropImagePaths.Count >= backdropLimit) break; @@ -332,7 +333,7 @@ namespace MediaBrowser.Providers.Movies { try { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanartArtistProvider.FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); break; } catch (HttpException ex) diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs index 9bd73bf65..88f478d1c 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.Movies /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - if (!_config.Configuration.EnableInternetProviders) + if (!_config.Configuration.EnableInternetProviders || !_config.Configuration.EnableFanArtUpdates) { progress.Report(100); return; @@ -101,18 +101,18 @@ namespace MediaBrowser.Providers.Movies // First get last time using (var stream = await _httpClient.Get(new HttpRequestOptions { - Url = string.Format(UpdatesUrl, FanartBaseProvider.ApiKey, lastUpdateTime), + Url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime), CancellationToken = cancellationToken, EnableHttpCompression = true, - ResourcePool = FanartBaseProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.FanArtResourcePool }).ConfigureAwait(false)) { - // If empty fanart will return a string of "null", rather than an empty list using (var reader = new StreamReader(stream)) { var json = await reader.ReadToEndAsync().ConfigureAwait(false); + // If empty fanart will return a string of "null", rather than an empty list if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase)) { return new List<string>(); diff --git a/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs index 7e0222f72..c94339a7e 100644 --- a/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Net; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; @@ -15,19 +16,22 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; +using MediaBrowser.Providers.Music; namespace MediaBrowser.Providers.Movies { - public class ManualFanartMovieImageProvider : IRemoteImageProvider + public class ManualFanartMovieImageProvider : IRemoteImageProvider, IHasChangeMonitor { private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IServerConfigurationManager _config; private readonly IHttpClient _httpClient; + private readonly IFileSystem _fileSystem; - public ManualFanartMovieImageProvider(IServerConfigurationManager config, IHttpClient httpClient) + public ManualFanartMovieImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem) { _config = config; _httpClient = httpClient; + _fileSystem = fileSystem; } public string Name @@ -329,8 +333,25 @@ namespace MediaBrowser.Providers.Movies { CancellationToken = cancellationToken, Url = url, - ResourcePool = FanartBaseProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.FanArtResourcePool }); } + + public bool HasChanged(IHasMetadata item, DateTime date) + { + var id = item.GetProviderId(MetadataProviders.Tmdb); + + if (!string.IsNullOrEmpty(id)) + { + // Process images + var xmlPath = FanArtMovieProvider.Current.GetFanartXmlPath(id); + + var fileInfo = new FileInfo(xmlPath); + + return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date; + } + + return false; + } } } diff --git a/MediaBrowser.Providers/Music/ArtistInfoFromSongProvider.cs b/MediaBrowser.Providers/Music/ArtistInfoFromSongProvider.cs deleted file mode 100644 index 05f7d4efe..000000000 --- a/MediaBrowser.Providers/Music/ArtistInfoFromSongProvider.cs +++ /dev/null @@ -1,91 +0,0 @@ -using MediaBrowser.Common.Extensions; -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.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Providers.Music -{ - public class ArtistInfoFromSongProvider : BaseMetadataProvider - { - public ArtistInfoFromSongProvider(ILogManager logManager, IServerConfigurationManager configurationManager) - : base(logManager, configurationManager) - { - } - - public override bool Supports(BaseItem item) - { - return item is MusicArtist; - } - - protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) - { - var artist = (MusicArtist)item; - - if (!artist.IsAccessedByName) - { - // If song metadata has changed - if (GetComparisonData(artist) != providerInfo.FileStamp) - { - return true; - } - } - - return base.NeedsRefreshInternal(item, providerInfo); - } - /// <summary> - /// Gets the data. - /// </summary> - /// <param name="artist">The artist.</param> - /// <returns>Guid.</returns> - private Guid GetComparisonData(MusicArtist artist) - { - var songs = artist.RecursiveChildren.OfType<Audio>().ToList(); - - return GetComparisonData(songs); - } - - private Guid GetComparisonData(IEnumerable<Audio> songs) - { - var genres = songs.SelectMany(i => i.Genres) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - return string.Join(string.Empty, genres.OrderBy(i => i).ToArray()).GetMD5(); - } - - public override Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken) - { - var artist = (MusicArtist)item; - - if (!artist.IsAccessedByName) - { - var songs = artist.RecursiveChildren.OfType<Audio>().ToList(); - - if (!item.LockedFields.Contains(MetadataFields.Genres)) - { - artist.Genres = songs.SelectMany(i => i.Genres) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - } - - providerInfo.FileStamp = GetComparisonData(songs); - } - - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - return TrueTaskResult; - } - - public override MetadataProviderPriority Priority - { - get { return MetadataProviderPriority.Second; } - } - } -} diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs new file mode 100644 index 000000000..31202feb2 --- /dev/null +++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs @@ -0,0 +1,67 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Providers.Manager; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.Music +{ + public class ArtistMetadataService : ConcreteMetadataService<MusicArtist> + { + private readonly ILibraryManager _libraryManager; + + public ArtistMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager) + : base(serverConfigurationManager, logger, providerManager, providerRepo) + { + _libraryManager = libraryManager; + } + + /// <summary> + /// Merges the specified source. + /// </summary> + /// <param name="source">The source.</param> + /// <param name="target">The target.</param> + /// <param name="lockedFields">The locked fields.</param> + /// <param name="replaceData">if set to <c>true</c> [replace data].</param> + /// <param name="mergeMetadataSettings">if set to <c>true</c> [merge metadata settings].</param> + protected override void MergeData(MusicArtist source, MusicArtist target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings) + { + ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + } + + protected override Task SaveItem(MusicArtist item, ItemUpdateType reason, CancellationToken cancellationToken) + { + return _libraryManager.UpdateItem(item, reason, cancellationToken); + } + + protected override ItemUpdateType AfterMetadataRefresh(MusicArtist item) + { + var updateType = base.AfterMetadataRefresh(item); + + if (!item.IsAccessedByName && !item.LockedFields.Contains(MetadataFields.Genres)) + { + var songs = item.RecursiveChildren.OfType<Audio>().ToList(); + + var currentGenres = item.Genres.ToList(); + + item.Genres = songs.SelectMany(i => i.Genres) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + if (currentGenres.Count != item.Genres.Count || !currentGenres.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase)) + { + updateType = updateType | ItemUpdateType.MetadataDownload; + } + } + + return updateType; + } + } +} diff --git a/MediaBrowser.Providers/Music/ArtistProviderFromXml.cs b/MediaBrowser.Providers/Music/ArtistProviderFromXml.cs deleted file mode 100644 index a25fd0093..000000000 --- a/MediaBrowser.Providers/Music/ArtistProviderFromXml.cs +++ /dev/null @@ -1,92 +0,0 @@ -using MediaBrowser.Common.IO; -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.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Providers.Music -{ - class ArtistProviderFromXml : BaseMetadataProvider - { - private readonly IFileSystem _fileSystem; - - public ArtistProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem) - : base(logManager, configurationManager) - { - _fileSystem = fileSystem; - } - - /// <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 MusicArtist) && item.LocationType == LocationType.FileSystem; - } - - /// <summary> - /// Gets the priority. - /// </summary> - /// <value>The priority.</value> - public override MetadataProviderPriority Priority - { - get { return MetadataProviderPriority.First; } - } - - private const string XmlFileName = "artist.xml"; - protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) - { - var xml = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, XmlFileName)); - - if (xml == null) - { - return false; - } - - return _fileSystem.GetLastWriteTimeUtc(xml) > item.DateLastSaved; - } - - /// <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, BaseProviderInfo providerInfo, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - var metadataFile = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, XmlFileName)); - - if (metadataFile != null) - { - var path = metadataFile.FullName; - - await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - try - { - new BaseItemXmlParser<MusicArtist>(Logger).Fetch((MusicArtist)item, path, cancellationToken); - } - finally - { - XmlParsingResourcePool.Release(); - } - - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - return true; - } - - return false; - } - } -} diff --git a/MediaBrowser.Providers/Music/ArtistXmlProvider.cs b/MediaBrowser.Providers/Music/ArtistXmlProvider.cs new file mode 100644 index 000000000..f29a6b861 --- /dev/null +++ b/MediaBrowser.Providers/Music/ArtistXmlProvider.cs @@ -0,0 +1,59 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Logging; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.Music +{ + class ArtistXmlProvider : BaseXmlProvider, ILocalMetadataProvider<MusicArtist> + { + private readonly ILogger _logger; + + public ArtistXmlProvider(IFileSystem fileSystem, ILogger logger) + : base(fileSystem) + { + _logger = logger; + } + + public async Task<MetadataResult<MusicArtist>> GetMetadata(string path, CancellationToken cancellationToken) + { + path = GetXmlPath(path); + + var result = new MetadataResult<MusicArtist>(); + + await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + var item = new MusicArtist(); + + new BaseItemXmlParser<MusicArtist>(_logger).Fetch(item, path, cancellationToken); + result.HasMetadata = true; + result.Item = item; + } + catch (FileNotFoundException) + { + result.HasMetadata = false; + } + finally + { + XmlParsingResourcePool.Release(); + } + + return result; + } + + public string Name + { + get { return "Media Browser Xml"; } + } + + protected override string GetXmlPath(string path) + { + return Path.Combine(path, "artist.xml"); + } + } +} diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs index b6e0d61f7..e2dde6c4f 100644 --- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Music /// <summary> /// Class FanArtAlbumProvider /// </summary> - public class FanArtAlbumProvider : FanartBaseProvider + public class FanArtAlbumProvider : BaseMetadataProvider { /// <summary> /// The _provider manager @@ -131,8 +131,7 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrEmpty(artistMusicBrainzId)) { - var artistXmlPath = FanArtArtistProvider.GetArtistDataPath(ConfigurationManager.CommonApplicationPaths, artistMusicBrainzId); - artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml"); + var artistXmlPath = FanartArtistProvider.GetArtistXmlPath(ConfigurationManager.CommonApplicationPaths, artistMusicBrainzId); var file = new FileInfo(artistXmlPath); @@ -195,7 +194,7 @@ namespace MediaBrowser.Providers.Music { try { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanartArtistProvider.FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); break; } catch (HttpException ex) diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index dc7c7c139..35d27036d 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -4,237 +4,427 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; using MediaBrowser.Model.Providers; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Net; -using System.Net; +using System.Xml; namespace MediaBrowser.Providers.Music { - /// <summary> - /// Class FanArtArtistProvider - /// </summary> - public class FanArtArtistProvider : FanartBaseProvider + public class FanartArtistProvider : IRemoteImageProvider, IHasChangeMonitor { - /// <summary> - /// Gets the HTTP client. - /// </summary> - /// <value>The HTTP client.</value> - protected IHttpClient HttpClient { get; private set; } - - /// <summary> - /// The _provider manager - /// </summary> - private readonly IProviderManager _providerManager; + internal static readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3); + internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4"; + private const string FanArtBaseUrl = "http://api.fanart.tv/webservice/artist/{0}/{1}/xml/all/1/1"; - internal static FanArtArtistProvider Current; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + private readonly IServerConfigurationManager _config; + private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; - /// <summary> - /// Initializes a new instance of the <see cref="FanArtArtistProvider"/> class. - /// </summary> - /// <param name="httpClient">The HTTP client.</param> - /// <param name="logManager">The log manager.</param> - /// <param name="configurationManager">The configuration manager.</param> - /// <param name="providerManager">The provider manager.</param> - /// <exception cref="System.ArgumentNullException">httpClient</exception> - public FanArtArtistProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem) - : base(logManager, configurationManager) + internal static FanartArtistProvider Current; + + public FanartArtistProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem) { - if (httpClient == null) - { - throw new ArgumentNullException("httpClient"); - } - HttpClient = httpClient; - _providerManager = providerManager; + _config = config; + _httpClient = httpClient; _fileSystem = fileSystem; Current = this; } - /// <summary> - /// The fan art base URL - /// </summary> - protected string FanArtBaseUrl = "http://api.fanart.tv/webservice/artist/{0}/{1}/xml/all/1/1"; + public string Name + { + get { return ProviderName; } + } - public override ItemUpdateType ItemUpdateType + public static string ProviderName { - get - { - return ItemUpdateType.ImageUpdate; - } + get { return "FanArt"; } } - - /// <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) + + public bool Supports(IHasImages item) { return item is MusicArtist; } - /// <summary> - /// Gets a value indicating whether [refresh on version change]. - /// </summary> - /// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value> - protected override bool RefreshOnVersionChange + public IEnumerable<ImageType> GetSupportedImages(IHasImages item) { - get + return new List<ImageType> { - return true; + ImageType.Primary, + ImageType.Logo, + ImageType.Art, + ImageType.Banner, + ImageType.Backdrop + }; + } + + public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, ImageType imageType, CancellationToken cancellationToken) + { + var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false); + + return images.Where(i => i.Type == imageType); + } + + public async Task<IEnumerable<RemoteImageInfo>> GetAllImages(IHasImages item, CancellationToken cancellationToken) + { + var artist = (MusicArtist)item; + + var list = new List<RemoteImageInfo>(); + + var artistMusicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz); + + if (!String.IsNullOrEmpty(artistMusicBrainzId)) + { + await EnsureMovieXml(artistMusicBrainzId, cancellationToken).ConfigureAwait(false); + + var artistXmlPath = GetArtistXmlPath(_config.CommonApplicationPaths, artistMusicBrainzId); + + try + { + AddImages(list, artistXmlPath, cancellationToken); + } + catch (FileNotFoundException) + { + + } } + + var language = item.GetPreferredMetadataLanguage(); + + var isLanguageEn = String.Equals(language, "en", StringComparison.OrdinalIgnoreCase); + + // Sort first by width to prioritize HD versions + return list.OrderByDescending(i => i.Width ?? 0) + .ThenByDescending(i => + { + if (String.Equals(language, i.Language, StringComparison.OrdinalIgnoreCase)) + { + return 3; + } + if (!isLanguageEn) + { + if (String.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase)) + { + return 2; + } + } + if (String.IsNullOrEmpty(i.Language)) + { + return isLanguageEn ? 3 : 2; + } + return 0; + }) + .ThenByDescending(i => i.CommunityRating ?? 0) + .ThenByDescending(i => i.VoteCount ?? 0); } /// <summary> - /// Gets the provider version. + /// Adds the images. /// </summary> - /// <value>The provider version.</value> - protected override string ProviderVersion + /// <param name="list">The list.</param> + /// <param name="xmlPath">The XML path.</param> + /// <param name="cancellationToken">The cancellation token.</param> + private void AddImages(List<RemoteImageInfo> list, string xmlPath, CancellationToken cancellationToken) { - get + using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8)) { - return "7"; + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings + { + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true, + ValidationType = ValidationType.None + })) + { + reader.MoveToContent(); + + // Loop through each element + while (reader.Read()) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "music": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromMusicNode(list, subReader, cancellationToken); + } + break; + } + + default: + reader.Skip(); + break; + } + } + } + } } } - public override MetadataProviderPriority Priority + /// <summary> + /// Adds the images from music node. + /// </summary> + /// <param name="list">The list.</param> + /// <param name="reader">The reader.</param> + /// <param name="cancellationToken">The cancellation token.</param> + private void AddImagesFromMusicNode(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken) { - get + reader.MoveToContent(); + + while (reader.Read()) { - return MetadataProviderPriority.Fourth; + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "hdmusiclogos": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromImageTypeNode(list, ImageType.Logo, 800, 310, subReader, cancellationToken); + } + break; + } + case "musiclogos": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromImageTypeNode(list, ImageType.Logo, 400, 155, subReader, cancellationToken); + } + break; + } + case "artistbackgrounds": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromImageTypeNode(list, ImageType.Backdrop, 1920, 1080, subReader, cancellationToken); + } + break; + } + case "hdmusicarts": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromImageTypeNode(list, ImageType.Art, 1000, 562, subReader, cancellationToken); + } + break; + } + case "musicarts": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromImageTypeNode(list, ImageType.Art, 500, 281, subReader, cancellationToken); + } + break; + } + case "hdmusicbanners": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromImageTypeNode(list, ImageType.Banner, 1000, 185, subReader, cancellationToken); + } + break; + } + case "musicbanners": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromImageTypeNode(list, ImageType.Banner, 1000, 185, subReader, cancellationToken); + } + break; + } + case "artistthumbs": + { + using (var subReader = reader.ReadSubtree()) + { + AddImagesFromImageTypeNode(list, ImageType.Primary, 1000, 1000, subReader, cancellationToken); + } + break; + } + default: + { + using (reader.ReadSubtree()) + { + } + break; + } + } + } } } /// <summary> - /// Needses the refresh internal. + /// Adds the images from albums node. /// </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) + /// <param name="list">The list.</param> + /// <param name="type">The type.</param> + /// <param name="width">The width.</param> + /// <param name="height">The height.</param> + /// <param name="reader">The reader.</param> + /// <param name="cancellationToken">The cancellation token.</param> + private void AddImagesFromImageTypeNode(List<RemoteImageInfo> list, ImageType type, int width, int height, XmlReader reader, CancellationToken cancellationToken) { - if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz))) + reader.MoveToContent(); + + while (reader.Read()) { - return false; + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "hdmusiclogo": + case "musiclogo": + case "artistbackground": + case "hdmusicart": + case "musicart": + case "hdmusicbanner": + case "musicbanner": + case "artistthumb": + { + AddImage(list, reader, type, width, height); + break; + } + default: + { + using (reader.ReadSubtree()) + { + } + break; + } + } + } } - - return base.NeedsRefreshInternal(item, providerInfo); } - protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) + /// <summary> + /// Adds the image. + /// </summary> + /// <param name="list">The list.</param> + /// <param name="reader">The reader.</param> + /// <param name="type">The type.</param> + /// <param name="width">The width.</param> + /// <param name="height">The height.</param> + private void AddImage(List<RemoteImageInfo> list, XmlReader reader, ImageType type, int width, int height) { - var musicBrainzId = item.GetProviderId(MetadataProviders.Musicbrainz); + var url = reader.GetAttribute("url"); - if (!string.IsNullOrEmpty(musicBrainzId)) + var size = reader.GetAttribute("size"); + + if (!String.IsNullOrEmpty(size)) { - // Process images - var artistXmlPath = GetArtistDataPath(ConfigurationManager.CommonApplicationPaths, musicBrainzId); - artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml"); + int sizeNum; + if (Int32.TryParse(size, NumberStyles.Any, _usCulture, out sizeNum)) + { + width = sizeNum; + height = sizeNum; + } + } - var file = new FileInfo(artistXmlPath); + var likesString = reader.GetAttribute("likes"); + int likes; + + var info = new RemoteImageInfo + { + RatingType = RatingType.Likes, + Type = type, + Width = width, + Height = height, + ProviderName = Name, + Url = url, + Language = reader.GetAttribute("lang") + }; - return !file.Exists || _fileSystem.GetLastWriteTimeUtc(file) > providerInfo.LastRefreshed; + if (!String.IsNullOrEmpty(likesString) && Int32.TryParse(likesString, NumberStyles.Any, _usCulture, out likes)) + { + info.CommunityRating = likes; } - return base.NeedsRefreshBasedOnCompareDate(item, providerInfo); + list.Add(info); } - /// <summary> - /// The us culture - /// </summary> - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// <summary> - /// Gets the artist data path. - /// </summary> - /// <param name="appPaths">The application paths.</param> - /// <param name="musicBrainzArtistId">The music brainz artist identifier.</param> - /// <returns>System.String.</returns> - internal static string GetArtistDataPath(IApplicationPaths appPaths, string musicBrainzArtistId) + public int Order { - var dataPath = Path.Combine(GetArtistDataPath(appPaths), musicBrainzArtistId); - - return dataPath; + get { return 0; } } - /// <summary> - /// Gets the artist data path. - /// </summary> - /// <param name="appPaths">The application paths.</param> - /// <returns>System.String.</returns> - internal static string GetArtistDataPath(IApplicationPaths appPaths) + public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) { - var dataPath = Path.Combine(appPaths.DataPath, "fanart-music"); - - return dataPath; + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url, + ResourcePool = FanArtResourcePool + }); } - /// <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, BaseProviderInfo providerInfo, CancellationToken cancellationToken) + public bool HasChanged(IHasMetadata item, DateTime date) { - cancellationToken.ThrowIfCancellationRequested(); + var id = item.GetProviderId(MetadataProviders.Musicbrainz); - var musicBrainzId = item.GetProviderId(MetadataProviders.Musicbrainz); + if (!String.IsNullOrEmpty(id)) + { + // Process images + var artistXmlPath = GetArtistXmlPath(_config.CommonApplicationPaths, id); - var artistDataPath = GetArtistDataPath(ConfigurationManager.ApplicationPaths, musicBrainzId); - var xmlPath = Path.Combine(artistDataPath, "fanart.xml"); + var fileInfo = new FileInfo(artistXmlPath); - // Only download the xml if it doesn't already exist. The prescan task will take care of getting updates - if (!File.Exists(xmlPath)) - { - await DownloadArtistXml(artistDataPath, musicBrainzId, cancellationToken).ConfigureAwait(false); + return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date; } - if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Art || - ConfigurationManager.Configuration.DownloadMusicArtistImages.Backdrops || - ConfigurationManager.Configuration.DownloadMusicArtistImages.Banner || - ConfigurationManager.Configuration.DownloadMusicArtistImages.Logo || - ConfigurationManager.Configuration.DownloadMusicArtistImages.Primary) + return false; + } + + internal Task EnsureMovieXml(string musicBrainzId, CancellationToken cancellationToken) + { + var xmlPath = GetArtistXmlPath(_config.ApplicationPaths, musicBrainzId); + + var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath); + + if (fileInfo.Exists) { - var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualFanartArtistProvider.ProviderName).ConfigureAwait(false); - await FetchFromXml(item, images.ToList(), cancellationToken).ConfigureAwait(false); + if (_config.Configuration.EnableFanArtUpdates || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7) + { + return Task.FromResult(true); + } } - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - return true; + return DownloadArtistXml(musicBrainzId, cancellationToken); } /// <summary> /// Downloads the artist XML. /// </summary> - /// <param name="artistPath">The artist path.</param> /// <param name="musicBrainzId">The music brainz id.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{System.Boolean}.</returns> - internal async Task DownloadArtistXml(string artistPath, string musicBrainzId, CancellationToken cancellationToken) + internal async Task DownloadArtistXml(string musicBrainzId, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var url = string.Format(FanArtBaseUrl, ApiKey, musicBrainzId); - var xmlPath = Path.Combine(artistPath, "fanart.xml"); + var xmlPath = GetArtistXmlPath(_config.ApplicationPaths, musicBrainzId); + + Directory.CreateDirectory(Path.GetDirectoryName(xmlPath)); - Directory.CreateDirectory(artistPath); - - using (var response = await HttpClient.Get(new HttpRequestOptions + using (var response = await _httpClient.Get(new HttpRequestOptions { Url = url, ResourcePool = FanArtResourcePool, @@ -250,83 +440,35 @@ namespace MediaBrowser.Providers.Music } /// <summary> - /// Fetches from XML. + /// Gets the artist data path. /// </summary> - /// <param name="item">The item.</param> - /// <param name="images">The images.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - private async Task FetchFromXml(BaseItem item, List<RemoteImageInfo> images , CancellationToken cancellationToken) + /// <param name="appPaths">The application paths.</param> + /// <param name="musicBrainzArtistId">The music brainz artist identifier.</param> + /// <returns>System.String.</returns> + private static string GetArtistDataPath(IApplicationPaths appPaths, string musicBrainzArtistId) { - if (!item.LockedFields.Contains(MetadataFields.Images)) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Primary && !item.HasImage(ImageType.Primary)) - { - await SaveImage(item, images, ImageType.Primary, cancellationToken).ConfigureAwait(false); - } - - cancellationToken.ThrowIfCancellationRequested(); - - if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Logo && !item.HasImage(ImageType.Logo)) - { - await SaveImage(item, images, ImageType.Logo, cancellationToken).ConfigureAwait(false); - } - - cancellationToken.ThrowIfCancellationRequested(); - - if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Art && !item.HasImage(ImageType.Art)) - { - await SaveImage(item, images, ImageType.Art, cancellationToken).ConfigureAwait(false); - } - - cancellationToken.ThrowIfCancellationRequested(); - - if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Banner && !item.HasImage(ImageType.Banner)) - { - await SaveImage(item, images, ImageType.Banner, cancellationToken).ConfigureAwait(false); - } - } + var dataPath = Path.Combine(GetArtistDataPath(appPaths), musicBrainzArtistId); - if (!item.LockedFields.Contains(MetadataFields.Backdrops)) - { - cancellationToken.ThrowIfCancellationRequested(); + return dataPath; + } - var backdropLimit = ConfigurationManager.Configuration.MusicOptions.MaxBackdrops; - if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Backdrops && - item.BackdropImagePaths.Count < backdropLimit) - { - foreach (var image in images.Where(i => i.Type == ImageType.Backdrop)) - { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, null, cancellationToken) - .ConfigureAwait(false); + /// <summary> + /// Gets the artist data path. + /// </summary> + /// <param name="appPaths">The application paths.</param> + /// <returns>System.String.</returns> + internal static string GetArtistDataPath(IApplicationPaths appPaths) + { + var dataPath = Path.Combine(appPaths.DataPath, "fanart-music"); - if (item.BackdropImagePaths.Count >= backdropLimit) break; - } - } - } + return dataPath; } - private async Task SaveImage(BaseItem item, List<RemoteImageInfo> images, ImageType type, CancellationToken cancellationToken) + internal static string GetArtistXmlPath(IApplicationPaths appPaths, string musicBrainzArtistId) { - foreach (var image in images.Where(i => i.Type == type)) - { - try - { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); - break; - } - catch (HttpException ex) - { - // Sometimes fanart has bad url's in their xml - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) - { - continue; - } - break; - } - } + var dataPath = GetArtistDataPath(appPaths, musicBrainzArtistId); + + return Path.Combine(dataPath, "fanart.xml"); } } } diff --git a/MediaBrowser.Providers/Music/FanArtUpdatesPrescanTask.cs b/MediaBrowser.Providers/Music/FanArtUpdatesPrescanTask.cs index a3d0deb0e..c3a879f8c 100644 --- a/MediaBrowser.Providers/Music/FanArtUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/Music/FanArtUpdatesPrescanTask.cs @@ -53,13 +53,13 @@ namespace MediaBrowser.Providers.Music /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - if (!_config.Configuration.EnableInternetProviders) + if (!_config.Configuration.EnableInternetProviders || !_config.Configuration.EnableFanArtUpdates) { progress.Report(100); return; } - var path = FanArtArtistProvider.GetArtistDataPath(_config.CommonApplicationPaths); + var path = FanartArtistProvider.GetArtistDataPath(_config.CommonApplicationPaths); Directory.CreateDirectory(path); @@ -85,7 +85,7 @@ namespace MediaBrowser.Providers.Music progress.Report(5); - await UpdateArtists(artistsToUpdate, path, progress, cancellationToken).ConfigureAwait(false); + await UpdateArtists(artistsToUpdate, progress, cancellationToken).ConfigureAwait(false); } var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture); @@ -107,10 +107,10 @@ namespace MediaBrowser.Providers.Music // First get last time using (var stream = await _httpClient.Get(new HttpRequestOptions { - Url = string.Format(UpdatesUrl, FanartBaseProvider.ApiKey, lastUpdateTime), + Url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime), CancellationToken = cancellationToken, EnableHttpCompression = true, - ResourcePool = FanartBaseProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.FanArtResourcePool }).ConfigureAwait(false)) { @@ -137,18 +137,17 @@ namespace MediaBrowser.Providers.Music /// Updates the artists. /// </summary> /// <param name="idList">The id list.</param> - /// <param name="artistsDataPath">The artists data path.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - private async Task UpdateArtists(IEnumerable<string> idList, string artistsDataPath, IProgress<double> progress, CancellationToken cancellationToken) + private async Task UpdateArtists(IEnumerable<string> idList, IProgress<double> progress, CancellationToken cancellationToken) { var list = idList.ToList(); var numComplete = 0; foreach (var id in list) { - await UpdateArtist(id, artistsDataPath, cancellationToken).ConfigureAwait(false); + await UpdateArtist(id, cancellationToken).ConfigureAwait(false); numComplete++; double percent = numComplete; @@ -163,18 +162,13 @@ namespace MediaBrowser.Providers.Music /// Updates the artist. /// </summary> /// <param name="musicBrainzId">The musicBrainzId.</param> - /// <param name="artistsDataPath">The artists data path.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - private Task UpdateArtist(string musicBrainzId, string artistsDataPath, CancellationToken cancellationToken) + private Task UpdateArtist(string musicBrainzId, CancellationToken cancellationToken) { _logger.Info("Updating artist " + musicBrainzId); - artistsDataPath = Path.Combine(artistsDataPath, musicBrainzId); - - Directory.CreateDirectory(artistsDataPath); - - return FanArtArtistProvider.Current.DownloadArtistXml(artistsDataPath, musicBrainzId, cancellationToken); + return FanartArtistProvider.Current.DownloadArtistXml(musicBrainzId, cancellationToken); } /// <summary> diff --git a/MediaBrowser.Providers/Music/LastFmImageProvider.cs b/MediaBrowser.Providers/Music/LastFmImageProvider.cs index 98ba58fa8..71278ce5c 100644 --- a/MediaBrowser.Providers/Music/LastFmImageProvider.cs +++ b/MediaBrowser.Providers/Music/LastFmImageProvider.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.Music /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> public override bool Supports(BaseItem item) { - return item is MusicArtist || item is MusicAlbum; + return item is MusicAlbum; } /// <summary> @@ -96,7 +96,7 @@ namespace MediaBrowser.Providers.Music if (image != null) { - await _providerManager.SaveImage(item, image.Url, LastfmBaseProvider.LastfmResourcePool, ImageType.Primary, null, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, LastFmArtistProvider.LastfmResourcePool, ImageType.Primary, null, cancellationToken).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs index 04946fabc..5cfcf054d 100644 --- a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs @@ -144,12 +144,12 @@ namespace MediaBrowser.Providers.Music private async Task<LastfmGetAlbumResult> GetAlbumResult(string artist, string album, CancellationToken cancellationToken) { // Get albu info using artist and album name - var url = RootUrl + string.Format("method=album.getInfo&artist={0}&album={1}&api_key={2}&format=json", UrlEncode(artist), UrlEncode(album), ApiKey); + var url = LastFmArtistProvider.RootUrl + string.Format("method=album.getInfo&artist={0}&album={1}&api_key={2}&format=json", UrlEncode(artist), UrlEncode(album), LastFmArtistProvider.ApiKey); using (var json = await HttpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = LastfmResourcePool, + ResourcePool = LastFmArtistProvider.LastfmResourcePool, CancellationToken = cancellationToken, EnableHttpCompression = false @@ -170,12 +170,12 @@ namespace MediaBrowser.Providers.Music private async Task<LastfmGetAlbumResult> GetAlbumResult(string musicbraizId, CancellationToken cancellationToken) { // Get albu info using artist and album name - var url = RootUrl + string.Format("method=album.getInfo&mbid={0}&api_key={1}&format=json", musicbraizId, ApiKey); + var url = LastFmArtistProvider.RootUrl + string.Format("method=album.getInfo&mbid={0}&api_key={1}&format=json", musicbraizId, LastFmArtistProvider.ApiKey); using (var json = await HttpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = LastfmResourcePool, + ResourcePool = LastFmArtistProvider.LastfmResourcePool, CancellationToken = cancellationToken, EnableHttpCompression = false diff --git a/MediaBrowser.Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Providers/Music/LastfmArtistProvider.cs index 02babb4e6..488340cf6 100644 --- a/MediaBrowser.Providers/Music/LastfmArtistProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmArtistProvider.cs @@ -2,7 +2,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; @@ -20,69 +19,128 @@ using System.Xml; namespace MediaBrowser.Providers.Music { - /// <summary> - /// Class LastfmArtistProvider - /// </summary> - public class LastfmArtistProvider : LastfmBaseProvider + public class LastFmArtistProvider : IRemoteMetadataProvider<MusicArtist> { - /// <summary> - /// The _library manager - /// </summary> - protected readonly ILibraryManager LibraryManager; + private readonly IJsonSerializer _json; + private readonly IHttpClient _httpClient; - /// <summary> - /// Initializes a new instance of the <see cref="LastfmArtistProvider" /> class. - /// </summary> - /// <param name="jsonSerializer">The json serializer.</param> - /// <param name="httpClient">The HTTP client.</param> - /// <param name="logManager">The log manager.</param> - /// <param name="configurationManager">The configuration manager.</param> - /// <param name="libraryManager">The library manager.</param> - public LastfmArtistProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, ILibraryManager libraryManager) - : base(jsonSerializer, httpClient, logManager, configurationManager) + internal static readonly SemaphoreSlim LastfmResourcePool = new SemaphoreSlim(4, 4); + + internal const string RootUrl = @"http://ws.audioscrobbler.com/2.0/?"; + internal static string ApiKey = "7b76553c3eb1d341d642755aecc40a33"; + + private readonly IServerConfigurationManager _config; + private ILogger _logger; + + public LastFmArtistProvider(IHttpClient httpClient, IJsonSerializer json) { - LibraryManager = libraryManager; + _httpClient = httpClient; + _json = json; } - protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) + public async Task<MetadataResult<MusicArtist>> GetMetadata(ItemId id, CancellationToken cancellationToken) { - if (HasAltMeta(item)) + var result = new MetadataResult<MusicArtist>(); + + var musicBrainzId = id.GetProviderId(MetadataProviders.Musicbrainz) ?? await FindId(id, cancellationToken).ConfigureAwait(false); + + if (!String.IsNullOrWhiteSpace(musicBrainzId)) { - return false; + cancellationToken.ThrowIfCancellationRequested(); + + result.Item = new MusicArtist(); + result.HasMetadata = true; + + result.Item.SetProviderId(MetadataProviders.Musicbrainz, musicBrainzId); + + await FetchLastfmData(result.Item, musicBrainzId, cancellationToken).ConfigureAwait(false); } - return base.NeedsRefreshInternal(item, providerInfo); + return result; } - protected override string ProviderVersion + protected virtual async Task FetchLastfmData(MusicArtist item, string musicBrainzId, CancellationToken cancellationToken) { - get + // Get artist info with provided id + var url = RootUrl + String.Format("method=artist.getInfo&mbid={0}&api_key={1}&format=json", UrlEncode(musicBrainzId), ApiKey); + + LastfmGetArtistResult result; + + using (var json = await _httpClient.Get(new HttpRequestOptions + { + Url = url, + ResourcePool = LastfmResourcePool, + CancellationToken = cancellationToken, + EnableHttpCompression = false + + }).ConfigureAwait(false)) + { + using (var reader = new StreamReader(json)) + { + var jsonText = await reader.ReadToEndAsync().ConfigureAwait(false); + + // Fix their bad json + jsonText = jsonText.Replace("\"#text\"", "\"url\""); + + result = _json.DeserializeFromString<LastfmGetArtistResult>(jsonText); + } + } + + if (result != null && result.artist != null) { - return "9"; + ProcessArtistData(item, result.artist, musicBrainzId); } } - /// <summary> - /// Gets the priority. - /// </summary> - /// <value>The priority.</value> - public override MetadataProviderPriority Priority + private void ProcessArtistData(MusicArtist artist, LastfmArtist data, string musicBrainzId) { - get { return MetadataProviderPriority.Third; } - } + var yearFormed = 0; - private bool HasAltMeta(BaseItem item) - { - return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName("artist.xml"); - } + if (data.bio != null) + { + Int32.TryParse(data.bio.yearformed, out yearFormed); + if (!artist.LockedFields.Contains(MetadataFields.Overview)) + { + artist.Overview = data.bio.content; + } + if (!string.IsNullOrEmpty(data.bio.placeformed) && !artist.LockedFields.Contains(MetadataFields.ProductionLocations)) + { + artist.AddProductionLocation(data.bio.placeformed); + } + } - /// <summary> - /// Finds the id. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{System.String}.</returns> - private async Task<string> FindId(BaseItem item, CancellationToken cancellationToken) + if (yearFormed > 0) + { + artist.PremiereDate = new DateTime(yearFormed, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + artist.ProductionYear = yearFormed; + } + + string imageSize; + var url = LastfmHelper.GetImageUrl(data, out imageSize); + + var cachePath = Path.Combine(_config.ApplicationPaths.CachePath, "lastfm", musicBrainzId, "image.txt"); + + try + { + if (string.IsNullOrEmpty(url)) + { + File.Delete(cachePath); + } + else + { + Directory.CreateDirectory(Path.GetDirectoryName(cachePath)); + File.WriteAllText(cachePath, url + "|" + imageSize); + } + } + catch (IOException ex) + { + // Don't fail if this is unable to write + _logger.ErrorException("Error saving to {0}", ex, cachePath); + } + } + + private async Task<string> FindId(ItemId item, CancellationToken cancellationToken) { try { @@ -102,43 +160,17 @@ namespace MediaBrowser.Providers.Music } /// <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, BaseProviderInfo providerInfo, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - var id = item.GetProviderId(MetadataProviders.Musicbrainz) ?? await FindId(item, cancellationToken).ConfigureAwait(false); - - if (!string.IsNullOrWhiteSpace(id)) - { - cancellationToken.ThrowIfCancellationRequested(); - - item.SetProviderId(MetadataProviders.Musicbrainz, id); - - await FetchLastfmData(item, id, force, cancellationToken).ConfigureAwait(false); - } - - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - return true; - } - - /// <summary> /// Finds the id from music brainz. /// </summary> /// <param name="item">The item.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{System.String}.</returns> - private async Task<string> FindIdFromMusicBrainz(BaseItem item, CancellationToken cancellationToken) + private async Task<string> FindIdFromMusicBrainz(ItemId item, CancellationToken cancellationToken) { // They seem to throw bad request failures on any term with a slash var nameToSearch = item.Name.Replace('/', ' '); - var url = string.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch)); + var url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch)); var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); @@ -154,7 +186,7 @@ namespace MediaBrowser.Providers.Music if (HasDiacritics(item.Name)) { // Try again using the search with accent characters url - url = string.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); + url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); @@ -178,7 +210,7 @@ namespace MediaBrowser.Providers.Music /// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns> private bool HasDiacritics(string text) { - return !string.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal); + return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal); } /// <summary> @@ -188,7 +220,7 @@ namespace MediaBrowser.Providers.Music /// <returns>System.String.</returns> private string RemoveDiacritics(string text) { - return string.Concat( + return String.Concat( text.Normalize(NormalizationForm.FormD) .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark) @@ -196,53 +228,18 @@ namespace MediaBrowser.Providers.Music } /// <summary> - /// Fetches the lastfm data. + /// Encodes an URL. /// </summary> - /// <param name="item">The item.</param> - /// <param name="musicBrainzId">The music brainz id.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - protected virtual async Task FetchLastfmData(BaseItem item, string musicBrainzId, bool force, CancellationToken cancellationToken) + /// <param name="name">The name.</param> + /// <returns>System.String.</returns> + private string UrlEncode(string name) { - // Get artist info with provided id - var url = RootUrl + string.Format("method=artist.getInfo&mbid={0}&api_key={1}&format=json", UrlEncode(musicBrainzId), ApiKey); - - LastfmGetArtistResult result; - - using (var json = await HttpClient.Get(new HttpRequestOptions - { - Url = url, - ResourcePool = LastfmResourcePool, - CancellationToken = cancellationToken, - EnableHttpCompression = false - - }).ConfigureAwait(false)) - { - 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) - { - LastfmHelper.ProcessArtistData((MusicArtist)item, result.artist); - } + return WebUtility.UrlEncode(name); } - /// <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) + public string Name { - return item is MusicArtist; + get { return "last.fm"; } } } } diff --git a/MediaBrowser.Providers/Music/LastfmBaseProvider.cs b/MediaBrowser.Providers/Music/LastfmBaseProvider.cs index cab9e7e39..7ff7bf407 100644 --- a/MediaBrowser.Providers/Music/LastfmBaseProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmBaseProvider.cs @@ -15,8 +15,6 @@ namespace MediaBrowser.Providers.Music /// </summary> public abstract class LastfmBaseProvider : BaseMetadataProvider { - internal static readonly SemaphoreSlim LastfmResourcePool = new SemaphoreSlim(4, 4); - /// <summary> /// Initializes a new instance of the <see cref="LastfmBaseProvider" /> class. /// </summary> @@ -80,9 +78,6 @@ namespace MediaBrowser.Providers.Music } } - protected const string RootUrl = @"http://ws.audioscrobbler.com/2.0/?"; - protected static string ApiKey = "7b76553c3eb1d341d642755aecc40a33"; - /// <summary> /// Encodes an URL. /// </summary> diff --git a/MediaBrowser.Providers/Music/LastfmHelper.cs b/MediaBrowser.Providers/Music/LastfmHelper.cs index 1b8d0c5f6..0895d245c 100644 --- a/MediaBrowser.Providers/Music/LastfmHelper.cs +++ b/MediaBrowser.Providers/Music/LastfmHelper.cs @@ -8,36 +8,7 @@ namespace MediaBrowser.Providers.Music { public static class LastfmHelper { - public static void ProcessArtistData(MusicArtist artist, LastfmArtist data) - { - var yearFormed = 0; - - if (data.bio != null) - { - Int32.TryParse(data.bio.yearformed, out yearFormed); - if (!artist.LockedFields.Contains(MetadataFields.Overview)) - { - artist.Overview = data.bio.content; - } - if (!string.IsNullOrEmpty(data.bio.placeformed) && !artist.LockedFields.Contains(MetadataFields.ProductionLocations)) - { - artist.AddProductionLocation(data.bio.placeformed); - } - } - - if (yearFormed > 0) - { - artist.PremiereDate = new DateTime(yearFormed, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - artist.ProductionYear = yearFormed; - } - - string imageSize; - artist.LastFmImageUrl = GetImageUrl(data, out imageSize); - artist.LastFmImageSize = imageSize; - } - - private static string GetImageUrl(IHasLastFmImages data, out string size) + public static string GetImageUrl(IHasLastFmImages data, out string size) { size = null; diff --git a/MediaBrowser.Providers/Music/ManualFanartAlbumProvider.cs b/MediaBrowser.Providers/Music/ManualFanartAlbumProvider.cs index d5108f309..f1dda948f 100644 --- a/MediaBrowser.Providers/Music/ManualFanartAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/ManualFanartAlbumProvider.cs @@ -71,8 +71,7 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrEmpty(artistMusicBrainzId)) { - var artistXmlPath = FanArtArtistProvider.GetArtistDataPath(_config.CommonApplicationPaths, artistMusicBrainzId); - artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml"); + var artistXmlPath = FanartArtistProvider.GetArtistXmlPath(_config.CommonApplicationPaths, artistMusicBrainzId); var musicBrainzReleaseGroupId = album.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); @@ -348,7 +347,7 @@ namespace MediaBrowser.Providers.Music { CancellationToken = cancellationToken, Url = url, - ResourcePool = FanartBaseProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.FanArtResourcePool }); } } diff --git a/MediaBrowser.Providers/Music/ManualFanartArtistProvider.cs b/MediaBrowser.Providers/Music/ManualFanartArtistProvider.cs deleted file mode 100644 index f100a3e31..000000000 --- a/MediaBrowser.Providers/Music/ManualFanartArtistProvider.cs +++ /dev/null @@ -1,367 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Xml; - -namespace MediaBrowser.Providers.Music -{ - public class ManualFanartArtistProvider : IRemoteImageProvider - { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly IServerConfigurationManager _config; - private readonly IHttpClient _httpClient; - - public ManualFanartArtistProvider(IServerConfigurationManager config, IHttpClient httpClient) - { - _config = config; - _httpClient = httpClient; - } - - public string Name - { - get { return ProviderName; } - } - - public static string ProviderName - { - get { return "FanArt"; } - } - - public bool Supports(IHasImages item) - { - return item is MusicArtist; - } - - public IEnumerable<ImageType> GetSupportedImages(IHasImages item) - { - return new List<ImageType> - { - ImageType.Primary, - ImageType.Logo, - ImageType.Art, - ImageType.Banner, - ImageType.Backdrop - }; - } - - public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, ImageType imageType, CancellationToken cancellationToken) - { - var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false); - - return images.Where(i => i.Type == imageType); - } - - public Task<IEnumerable<RemoteImageInfo>> GetAllImages(IHasImages item, CancellationToken cancellationToken) - { - var artist = (MusicArtist)item; - - var list = new List<RemoteImageInfo>(); - - var artistMusicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz); - - if (!string.IsNullOrEmpty(artistMusicBrainzId)) - { - var artistXmlPath = FanArtArtistProvider.GetArtistDataPath(_config.CommonApplicationPaths, artistMusicBrainzId); - artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml"); - - try - { - AddImages(list, artistXmlPath, cancellationToken); - } - catch (FileNotFoundException) - { - - } - } - - var language = item.GetPreferredMetadataLanguage(); - - var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); - - // Sort first by width to prioritize HD versions - list = list.OrderByDescending(i => i.Width ?? 0) - .ThenByDescending(i => - { - if (string.Equals(language, i.Language, StringComparison.OrdinalIgnoreCase)) - { - return 3; - } - if (!isLanguageEn) - { - if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase)) - { - return 2; - } - } - if (string.IsNullOrEmpty(i.Language)) - { - return isLanguageEn ? 3 : 2; - } - return 0; - }) - .ThenByDescending(i => i.CommunityRating ?? 0) - .ThenByDescending(i => i.VoteCount ?? 0) - .ToList(); - - return Task.FromResult<IEnumerable<RemoteImageInfo>>(list); - } - - /// <summary> - /// Adds the images. - /// </summary> - /// <param name="list">The list.</param> - /// <param name="xmlPath">The XML path.</param> - /// <param name="cancellationToken">The cancellation token.</param> - private void AddImages(List<RemoteImageInfo> list, string xmlPath, CancellationToken cancellationToken) - { - using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8)) - { - // Use XmlReader for best performance - using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings - { - CheckCharacters = false, - IgnoreProcessingInstructions = true, - IgnoreComments = true, - ValidationType = ValidationType.None - })) - { - reader.MoveToContent(); - - // Loop through each element - while (reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "music": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromMusicNode(list, subReader, cancellationToken); - } - break; - } - - default: - reader.Skip(); - break; - } - } - } - } - } - } - - /// <summary> - /// Adds the images from music node. - /// </summary> - /// <param name="list">The list.</param> - /// <param name="reader">The reader.</param> - /// <param name="cancellationToken">The cancellation token.</param> - private void AddImagesFromMusicNode(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken) - { - reader.MoveToContent(); - - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "hdmusiclogos": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromImageTypeNode(list, ImageType.Logo, 800, 310, subReader, cancellationToken); - } - break; - } - case "musiclogos": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromImageTypeNode(list, ImageType.Logo, 400, 155, subReader, cancellationToken); - } - break; - } - case "artistbackgrounds": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromImageTypeNode(list, ImageType.Backdrop, 1920, 1080, subReader, cancellationToken); - } - break; - } - case "hdmusicarts": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromImageTypeNode(list, ImageType.Art, 1000, 562, subReader, cancellationToken); - } - break; - } - case "musicarts": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromImageTypeNode(list, ImageType.Art, 500, 281, subReader, cancellationToken); - } - break; - } - case "hdmusicbanners": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromImageTypeNode(list, ImageType.Banner, 1000, 185, subReader, cancellationToken); - } - break; - } - case "musicbanners": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromImageTypeNode(list, ImageType.Banner, 1000, 185, subReader, cancellationToken); - } - break; - } - case "artistthumbs": - { - using (var subReader = reader.ReadSubtree()) - { - AddImagesFromImageTypeNode(list, ImageType.Primary, 1000, 1000, subReader, cancellationToken); - } - break; - } - default: - { - using (reader.ReadSubtree()) - { - } - break; - } - } - } - } - } - - /// <summary> - /// Adds the images from albums node. - /// </summary> - /// <param name="list">The list.</param> - /// <param name="type">The type.</param> - /// <param name="width">The width.</param> - /// <param name="height">The height.</param> - /// <param name="reader">The reader.</param> - /// <param name="cancellationToken">The cancellation token.</param> - private void AddImagesFromImageTypeNode(List<RemoteImageInfo> list, ImageType type, int width, int height, XmlReader reader, CancellationToken cancellationToken) - { - reader.MoveToContent(); - - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "hdmusiclogo": - case "musiclogo": - case "artistbackground": - case "hdmusicart": - case "musicart": - case "hdmusicbanner": - case "musicbanner": - case "artistthumb": - { - AddImage(list, reader, type, width, height); - break; - } - default: - { - using (reader.ReadSubtree()) - { - } - break; - } - } - } - } - } - - /// <summary> - /// Adds the image. - /// </summary> - /// <param name="list">The list.</param> - /// <param name="reader">The reader.</param> - /// <param name="type">The type.</param> - /// <param name="width">The width.</param> - /// <param name="height">The height.</param> - private void AddImage(List<RemoteImageInfo> list, XmlReader reader, ImageType type, int width, int height) - { - var url = reader.GetAttribute("url"); - - var size = reader.GetAttribute("size"); - - if (!string.IsNullOrEmpty(size)) - { - int sizeNum; - if (int.TryParse(size, NumberStyles.Any, _usCulture, out sizeNum)) - { - width = sizeNum; - height = sizeNum; - } - } - - var likesString = reader.GetAttribute("likes"); - int likes; - - var info = new RemoteImageInfo - { - RatingType = RatingType.Likes, - Type = type, - Width = width, - Height = height, - ProviderName = Name, - Url = url, - Language = reader.GetAttribute("lang") - }; - - if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes)) - { - info.CommunityRating = likes; - } - - list.Add(info); - } - - public int Order - { - get { return 0; } - } - - public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken) - { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url, - ResourcePool = FanartBaseProvider.FanArtResourcePool - }); - } - } -} diff --git a/MediaBrowser.Providers/Music/ManualLastFmImageProvider.cs b/MediaBrowser.Providers/Music/ManualLastFmImageProvider.cs index aa7d00fb6..b1e9fa9b3 100644 --- a/MediaBrowser.Providers/Music/ManualLastFmImageProvider.cs +++ b/MediaBrowser.Providers/Music/ManualLastFmImageProvider.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; @@ -6,6 +7,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -15,10 +17,12 @@ namespace MediaBrowser.Providers.Music public class ManualLastFmImageProvider : IRemoteImageProvider { private readonly IHttpClient _httpClient; + private readonly IServerConfigurationManager _config; - public ManualLastFmImageProvider(IHttpClient httpClient) + public ManualLastFmImageProvider(IHttpClient httpClient, IServerConfigurationManager config) { _httpClient = httpClient; + _config = config; } public string Name @@ -57,6 +61,8 @@ namespace MediaBrowser.Providers.Music RemoteImageInfo info = null; + var musicBrainzId = item.GetProviderId(MetadataProviders.Musicbrainz); + var album = item as MusicAlbum; if (album != null) { @@ -64,9 +70,23 @@ namespace MediaBrowser.Providers.Music } var musicArtist = item as MusicArtist; - if (musicArtist != null) + if (musicArtist != null && !string.IsNullOrEmpty(musicBrainzId)) { - info = GetInfo(musicArtist.LastFmImageUrl, musicArtist.LastFmImageSize); + var cachePath = Path.Combine(_config.ApplicationPaths.CachePath, "lastfm", musicBrainzId, "image.txt"); + + try + { + var parts = File.ReadAllText(cachePath).Split('|'); + + info = GetInfo(parts.FirstOrDefault(), parts.LastOrDefault()); + } + catch (DirectoryNotFoundException ex) + { + } + catch (FileNotFoundException ex) + { + } + } if (info != null) @@ -123,7 +143,7 @@ namespace MediaBrowser.Providers.Music { CancellationToken = cancellationToken, Url = url, - ResourcePool = LastfmBaseProvider.LastfmResourcePool + ResourcePool = LastFmArtistProvider.LastfmResourcePool }); } } diff --git a/MediaBrowser.Providers/ProviderUtils.cs b/MediaBrowser.Providers/ProviderUtils.cs index 416ada42c..a04df581c 100644 --- a/MediaBrowser.Providers/ProviderUtils.cs +++ b/MediaBrowser.Providers/ProviderUtils.cs @@ -104,6 +104,48 @@ namespace MediaBrowser.Providers } } + if (!lockedFields.Contains(MetadataFields.Tags)) + { + var sourceHasTags = source as IHasTags; + var targetHasTags = target as IHasTags; + + if (sourceHasTags != null && targetHasTags != null) + { + if (replaceData || targetHasTags.Tags.Count == 0) + { + targetHasTags.Tags = sourceHasTags.Tags; + } + } + } + + if (!lockedFields.Contains(MetadataFields.Keywords)) + { + var sourceHasKeywords = source as IHasKeywords; + var targetHasKeywords = target as IHasKeywords; + + if (sourceHasKeywords != null && targetHasKeywords != null) + { + if (replaceData || targetHasKeywords.Keywords.Count == 0) + { + targetHasKeywords.Keywords = sourceHasKeywords.Keywords; + } + } + } + + if (!lockedFields.Contains(MetadataFields.ProductionLocations)) + { + var sourceHasProductionLocations = source as IHasProductionLocations; + var targetHasProductionLocations = target as IHasProductionLocations; + + if (sourceHasProductionLocations != null && targetHasProductionLocations != null) + { + if (replaceData || targetHasProductionLocations.ProductionLocations.Count == 0) + { + targetHasProductionLocations.ProductionLocations = sourceHasProductionLocations.ProductionLocations; + } + } + } + if (replaceData || !target.VoteCount.HasValue) { target.VoteCount = source.VoteCount; @@ -120,6 +162,23 @@ namespace MediaBrowser.Providers target.LockedFields = source.LockedFields; target.DontFetchMeta = source.DontFetchMeta; target.DisplayMediaType = source.DisplayMediaType; + + var sourceHasLanguageSettings = source as IHasPreferredMetadataLanguage; + var targetHasLanguageSettings = target as IHasPreferredMetadataLanguage; + + if (sourceHasLanguageSettings != null && targetHasLanguageSettings != null) + { + targetHasLanguageSettings.PreferredMetadataCountryCode = sourceHasLanguageSettings.PreferredMetadataCountryCode; + targetHasLanguageSettings.PreferredMetadataLanguage = sourceHasLanguageSettings.PreferredMetadataLanguage; + } + + var sourceHasDisplayOrder = source as IHasDisplayOrder; + var targetHasDisplayOrder = target as IHasDisplayOrder; + + if (sourceHasDisplayOrder != null && targetHasDisplayOrder != null) + { + targetHasDisplayOrder.DisplayOrder = sourceHasDisplayOrder.DisplayOrder; + } } } } diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs index 50ce72a89..6ab612784 100644 --- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs @@ -15,13 +15,14 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Net; using System.Net; +using MediaBrowser.Providers.Music; namespace MediaBrowser.Providers.TV { /// <summary> /// Class FanArtSeasonProvider /// </summary> - class FanArtSeasonProvider : FanartBaseProvider + class FanArtSeasonProvider : BaseMetadataProvider { /// <summary> /// The _provider manager @@ -132,7 +133,7 @@ namespace MediaBrowser.Providers.TV { try { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanartArtistProvider.FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); break; } catch (HttpException ex) diff --git a/MediaBrowser.Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Providers/TV/FanArtTVProvider.cs index 286702b8c..1f7109c61 100644 --- a/MediaBrowser.Providers/TV/FanArtTVProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtTVProvider.cs @@ -18,10 +18,11 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Net; using System.Net; +using MediaBrowser.Providers.Music; namespace MediaBrowser.Providers.TV { - class FanArtTvProvider : FanartBaseProvider + class FanArtTvProvider : BaseMetadataProvider { protected string FanArtBaseUrl = "http://api.fanart.tv/webservice/series/{0}/{1}/xml/all/1/1"; @@ -244,7 +245,7 @@ namespace MediaBrowser.Providers.TV { foreach (var image in images.Where(i => i.Type == ImageType.Backdrop)) { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, null, cancellationToken) + await _providerManager.SaveImage(item, image.Url, FanartArtistProvider.FanArtResourcePool, ImageType.Backdrop, null, cancellationToken) .ConfigureAwait(false); if (item.BackdropImagePaths.Count >= backdropLimit) break; @@ -259,7 +260,7 @@ namespace MediaBrowser.Providers.TV { try { - await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanartArtistProvider.FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false); break; } catch (HttpException ex) @@ -284,7 +285,7 @@ namespace MediaBrowser.Providers.TV { cancellationToken.ThrowIfCancellationRequested(); - var url = string.Format(FanArtBaseUrl, ApiKey, tvdbId); + var url = string.Format(FanArtBaseUrl, FanartArtistProvider.ApiKey, tvdbId); var xmlPath = GetFanartXmlPath(tvdbId); @@ -293,7 +294,7 @@ namespace MediaBrowser.Providers.TV using (var response = await HttpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = FanArtResourcePool, + ResourcePool = FanartArtistProvider.FanArtResourcePool, CancellationToken = cancellationToken }).ConfigureAwait(false)) diff --git a/MediaBrowser.Providers/TV/FanArtTvUpdatesPrescanTask.cs b/MediaBrowser.Providers/TV/FanArtTvUpdatesPrescanTask.cs index 46137a211..0c5b3fabc 100644 --- a/MediaBrowser.Providers/TV/FanArtTvUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/TV/FanArtTvUpdatesPrescanTask.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.TV /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { - if (!_config.Configuration.EnableInternetProviders) + if (!_config.Configuration.EnableInternetProviders || !_config.Configuration.EnableFanArtUpdates) { progress.Report(100); return; @@ -108,10 +108,10 @@ namespace MediaBrowser.Providers.TV // First get last time using (var stream = await _httpClient.Get(new HttpRequestOptions { - Url = string.Format(UpdatesUrl, FanartBaseProvider.ApiKey, lastUpdateTime), + Url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime), CancellationToken = cancellationToken, EnableHttpCompression = true, - ResourcePool = FanartBaseProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.FanArtResourcePool }).ConfigureAwait(false)) { diff --git a/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs b/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs index 1d6f82a3a..6fdd7d094 100644 --- a/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs @@ -15,6 +15,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; +using MediaBrowser.Providers.Music; namespace MediaBrowser.Providers.TV { @@ -268,7 +269,7 @@ namespace MediaBrowser.Providers.TV { CancellationToken = cancellationToken, Url = url, - ResourcePool = FanartBaseProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.FanArtResourcePool }); } } diff --git a/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs b/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs index b88a94e4e..f7e19a6c1 100644 --- a/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs @@ -15,6 +15,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; +using MediaBrowser.Providers.Music; namespace MediaBrowser.Providers.TV { @@ -329,7 +330,7 @@ namespace MediaBrowser.Providers.TV { CancellationToken = cancellationToken, Url = url, - ResourcePool = FanartBaseProvider.FanArtResourcePool + ResourcePool = FanartArtistProvider.FanArtResourcePool }); } } diff --git a/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs index c8094302c..706ff67a7 100644 --- a/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Library/Validators/PeoplePostScanTask.cs @@ -93,7 +93,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators // All other metadata can wait for that. await itemByName.RefreshMetadata(new MetadataRefreshOptions { - ImageRefreshMode = MetadataRefreshMode.None, + ImageRefreshMode = ImageRefreshMode.ValidationOnly, MetadataRefreshMode = MetadataRefreshMode.None }, cancellationToken).ConfigureAwait(false); |
