diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index c4981a7faa..bfa2b645a0 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 b84a8f4f74..37bf0c1cae 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 860d34fd82..b2d95ed300 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(); } - /// - /// Gets or sets the last fm image URL. - /// - /// The last fm image URL. - public string LastFmImageUrl { get; set; } - public string LastFmImageSize { get; set; } - public MusicArtist() { UserItemCountList = new List(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 06ebe89055..f12532204f 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 c1951038cc..746157bb33 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 d6e8a3afea..27de50ef8c 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -22,11 +22,21 @@ namespace MediaBrowser.Controller.Providers /// [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 /// FullRefresh } + + public enum ImageRefreshMode + { + /// + /// The default + /// + Default, + + /// + /// Existing images will be validated + /// + ValidationOnly, + + /// + /// All providers will be executed to search for new metadata + /// + FullRefresh + } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 424c9c48e5..716be54d25 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 62b2e627f3..b9b4e40d7a 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 { 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; } /// @@ -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(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 961982bfdd..2e75a66cb9 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); } - /// - /// Fetches the images. - /// - /// The item. - /// The json serializer. - /// The cancellation token. - /// Task{MovieImages}. - private async Task 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(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 f0f731809a..0000000000 --- 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 -{ - /// - /// Class FanartBaseProvider - /// - public abstract class FanartBaseProvider : BaseMetadataProvider - { - internal static readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3); - - /// - /// The LOG o_ FILE - /// - protected const string LogoFile = "logo.png"; - - /// - /// The AR t_ FILE - /// - protected const string ArtFile = "clearart.png"; - - /// - /// The THUM b_ FILE - /// - protected const string ThumbFile = "thumb.jpg"; - - /// - /// The DIS c_ FILE - /// - protected const string DiscFile = "disc.png"; - - /// - /// The BANNE r_ FILE - /// - protected const string BannerFile = "banner.png"; - - /// - /// The Backdrop - /// - protected const string BackdropFile = "backdrop.jpg"; - - /// - /// The Primary image - /// - protected const string PrimaryFile = "folder.jpg"; - - /// - /// The API key - /// - internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4"; - - protected FanartBaseProvider(ILogManager logManager, IServerConfigurationManager configurationManager) - : base(logManager, configurationManager) - { - } - - /// - /// Gets a value indicating whether [requires internet]. - /// - /// true if [requires internet]; otherwise, false. - 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 musiclogo { get; set; } - public List artistbackground { get; set; } - public List artistthumb { get; set; } - public List hdmusiclogo { get; set; } - public List musicbanner { get; set; } - } - - protected class FanArtMusicResult - { - public FanArtMusicInfo result { get; set; } - } - - #endregion - - } - -} diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index d946f9cbdb..d8d9ee0cac 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; @@ -146,6 +148,15 @@ namespace MediaBrowser.Providers.Manager } } + /// + /// Afters the metadata refresh. + /// + /// The item. + protected virtual ItemUpdateType AfterMetadataRefresh(TItemType item) + { + return ItemUpdateType.Unspecified; + } + /// /// Gets the providers. /// @@ -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 06c70d75d2..83c628e23e 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -80,7 +80,6 @@ - @@ -101,6 +100,8 @@ + + @@ -112,18 +113,15 @@ - - + - - - + diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs index 3c8fd4612d..2cf403b09c 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 { /// /// Class FanArtMovieProvider /// - class FanArtMovieProvider : FanartBaseProvider + class FanArtMovieProvider : BaseMetadataProvider { /// /// 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 9bd73bf656..88f478d1c3 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.Movies /// Task. public async Task Run(IProgress 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(); diff --git a/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs index 7e0222f722..c94339a7e4 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 05f7d4efe5..0000000000 --- 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); - } - /// - /// Gets the data. - /// - /// The artist. - /// Guid. - private Guid GetComparisonData(MusicArtist artist) - { - var songs = artist.RecursiveChildren.OfType /// The musicBrainzId. - /// The artists data path. /// The cancellation token. /// Task. - 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); } /// diff --git a/MediaBrowser.Providers/Music/LastFmImageProvider.cs b/MediaBrowser.Providers/Music/LastFmImageProvider.cs index 98ba58fa8b..71278ce5c3 100644 --- a/MediaBrowser.Providers/Music/LastFmImageProvider.cs +++ b/MediaBrowser.Providers/Music/LastFmImageProvider.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Providers.Music /// true if XXXX, false otherwise public override bool Supports(BaseItem item) { - return item is MusicArtist || item is MusicAlbum; + return item is MusicAlbum; } /// @@ -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 04946fabc3..5cfcf054d5 100644 --- a/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmAlbumProvider.cs @@ -144,12 +144,12 @@ namespace MediaBrowser.Providers.Music private async Task 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 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 02babb4e6a..488340cf60 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 { - /// - /// Class LastfmArtistProvider - /// - public class LastfmArtistProvider : LastfmBaseProvider + public class LastFmArtistProvider : IRemoteMetadataProvider { - /// - /// The _library manager - /// - protected readonly ILibraryManager LibraryManager; + private readonly IJsonSerializer _json; + private readonly IHttpClient _httpClient; - /// - /// Initializes a new instance of the class. - /// - /// The json serializer. - /// The HTTP client. - /// The log manager. - /// The configuration manager. - /// The library manager. - 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> GetMetadata(ItemId id, CancellationToken cancellationToken) { - if (HasAltMeta(item)) + var result = new MetadataResult(); + + 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(jsonText); + } + } + + if (result != null && result.artist != null) { - return "9"; + ProcessArtistData(item, result.artist, musicBrainzId); } } - /// - /// Gets the priority. - /// - /// The priority. - 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); + } + } - /// - /// Finds the id. - /// - /// The item. - /// The cancellation token. - /// Task{System.String}. - private async Task 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 FindId(ItemId item, CancellationToken cancellationToken) { try { @@ -101,44 +159,18 @@ namespace MediaBrowser.Providers.Music } } - /// - /// Fetches metadata and returns true or false indicating if any work that requires persistence was done - /// - /// The item. - /// if set to true [force]. - /// The cancellation token - /// Task{System.Boolean}. - public override async Task 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; - } - /// /// Finds the id from music brainz. /// /// The item. /// The cancellation token. /// Task{System.String}. - private async Task FindIdFromMusicBrainz(BaseItem item, CancellationToken cancellationToken) + private async Task 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 /// true if the specified text has diacritics; otherwise, false. private bool HasDiacritics(string text) { - return !string.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal); + return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal); } /// @@ -188,7 +220,7 @@ namespace MediaBrowser.Providers.Music /// System.String. 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 } /// - /// Fetches the lastfm data. + /// Encodes an URL. /// - /// The item. - /// The music brainz id. - /// The cancellation token. - /// Task. - protected virtual async Task FetchLastfmData(BaseItem item, string musicBrainzId, bool force, CancellationToken cancellationToken) + /// The name. + /// System.String. + 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(jsonText); - } - } - - if (result != null && result.artist != null) - { - LastfmHelper.ProcessArtistData((MusicArtist)item, result.artist); - } + return WebUtility.UrlEncode(name); } - /// - /// Supportses the specified item. - /// - /// The item. - /// true if XXXX, false otherwise - 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 cab9e7e39c..7ff7bf4076 100644 --- a/MediaBrowser.Providers/Music/LastfmBaseProvider.cs +++ b/MediaBrowser.Providers/Music/LastfmBaseProvider.cs @@ -15,8 +15,6 @@ namespace MediaBrowser.Providers.Music /// public abstract class LastfmBaseProvider : BaseMetadataProvider { - internal static readonly SemaphoreSlim LastfmResourcePool = new SemaphoreSlim(4, 4); - /// /// Initializes a new instance of the class. /// @@ -80,9 +78,6 @@ namespace MediaBrowser.Providers.Music } } - protected const string RootUrl = @"http://ws.audioscrobbler.com/2.0/?"; - protected static string ApiKey = "7b76553c3eb1d341d642755aecc40a33"; - /// /// Encodes an URL. /// diff --git a/MediaBrowser.Providers/Music/LastfmHelper.cs b/MediaBrowser.Providers/Music/LastfmHelper.cs index 1b8d0c5f6d..0895d245cd 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 d5108f3091..f1dda948f7 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 f100a3e314..0000000000 --- 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 GetSupportedImages(IHasImages item) - { - return new List - { - ImageType.Primary, - ImageType.Logo, - ImageType.Art, - ImageType.Banner, - ImageType.Backdrop - }; - } - - public async Task> GetImages(IHasImages item, ImageType imageType, CancellationToken cancellationToken) - { - var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false); - - return images.Where(i => i.Type == imageType); - } - - public Task> GetAllImages(IHasImages item, CancellationToken cancellationToken) - { - var artist = (MusicArtist)item; - - var list = new List(); - - 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>(list); - } - - /// - /// Adds the images. - /// - /// The list. - /// The XML path. - /// The cancellation token. - private void AddImages(List 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; - } - } - } - } - } - } - - /// - /// Adds the images from music node. - /// - /// The list. - /// The reader. - /// The cancellation token. - private void AddImagesFromMusicNode(List 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; - } - } - } - } - } - - /// - /// Adds the images from albums node. - /// - /// The list. - /// The type. - /// The width. - /// The height. - /// The reader. - /// The cancellation token. - private void AddImagesFromImageTypeNode(List 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; - } - } - } - } - } - - /// - /// Adds the image. - /// - /// The list. - /// The reader. - /// The type. - /// The width. - /// The height. - private void AddImage(List 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 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 aa7d00fb67..b1e9fa9b39 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 416ada42cf..a04df581c6 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 50ce72a89d..6ab612784a 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 { /// /// Class FanArtSeasonProvider /// - class FanArtSeasonProvider : FanartBaseProvider + class FanArtSeasonProvider : BaseMetadataProvider { /// /// 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 286702b8c6..1f7109c610 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 46137a2110..0c5b3fabc2 100644 --- a/MediaBrowser.Providers/TV/FanArtTvUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/TV/FanArtTvUpdatesPrescanTask.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Providers.TV /// Task. public async Task Run(IProgress 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 1d6f82a3a5..6fdd7d0940 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 b88a94e4e4..f7e19a6c1f 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 c8094302c1..706ff67a7c 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);