From 30ebfab8e0ae39213a5a550fbcbaa2463d6a74da Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 3 Feb 2014 00:35:43 -0500 Subject: [PATCH] converted season providers --- MediaBrowser.Controller/Entities/BaseItem.cs | 8 + MediaBrowser.Controller/Entities/Folder.cs | 9 +- MediaBrowser.Controller/Entities/User.cs | 27 -- .../BoxSets/BoxSetXmlProvider.cs | 2 +- .../Games/GameSystemXmlProvider.cs | 2 +- .../Games/GameXmlProvider.cs | 2 +- .../LiveTv/ChannelXmlProvider.cs | 2 +- .../Manager/MetadataService.cs | 31 +- .../MediaBrowser.Providers.csproj | 13 +- .../Music/AlbumXmlProvider.cs | 2 +- .../Music/ArtistXmlProvider.cs | 2 +- .../People/PersonXmlProvider.cs | 2 +- .../Savers/AlbumXmlSaver.cs | 2 +- .../Savers/ArtistXmlSaver.cs | 2 +- .../Savers/BoxSetXmlSaver.cs | 2 +- .../Savers/ChannelXmlSaver.cs | 2 +- .../Savers/EpisodeXmlSaver.cs | 2 +- .../Savers/FolderXmlSaver.cs | 2 +- .../Savers/GameSystemXmlSaver.cs | 2 +- MediaBrowser.Providers/Savers/GameXmlSaver.cs | 2 +- .../Savers/MovieXmlSaver.cs | 2 +- .../Savers/PersonXmlSaver.cs | 2 +- .../Savers/SeasonXmlSaver.cs | 2 +- .../Savers/SeriesXmlSaver.cs | 2 +- .../TV/FanArtSeasonProvider.cs | 405 +++++++++++------- MediaBrowser.Providers/TV/FanArtTVProvider.cs | 23 +- .../TV/ManualFanartSeasonProvider.cs | 276 ------------ .../TV/SeasonIndexNumberProvider.cs | 83 ---- .../TV/SeasonMetadataService.cs | 58 +++ .../TV/SeasonProviderFromXml.cs | 97 ----- .../TV/SeasonXmlProvider.cs | 63 +++ ...Provider.cs => TvdbSeasonImageProvider.cs} | 47 +- .../TV/TvdbSeasonProvider.cs | 211 --------- .../TV/TvdbSeriesProvider.cs | 20 + Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 37 files changed, 526 insertions(+), 893 deletions(-) delete mode 100644 MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs delete mode 100644 MediaBrowser.Providers/TV/SeasonIndexNumberProvider.cs create mode 100644 MediaBrowser.Providers/TV/SeasonMetadataService.cs delete mode 100644 MediaBrowser.Providers/TV/SeasonProviderFromXml.cs create mode 100644 MediaBrowser.Providers/TV/SeasonXmlProvider.cs rename MediaBrowser.Providers/TV/{ManualTvdbSeasonImageProvider.cs => TvdbSeasonImageProvider.cs} (87%) delete mode 100644 MediaBrowser.Providers/TV/TvdbSeasonProvider.cs diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index d9579d79f8..5a041860bb 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -784,11 +784,19 @@ namespace MediaBrowser.Controller.Entities ResetResolveArgs(); } + await BeforeRefreshMetadata(options, cancellationToken).ConfigureAwait(false); + await ProviderManager.RefreshMetadata(this, options, cancellationToken).ConfigureAwait(false); return false; } + private readonly Task _cachedTask = Task.FromResult(true); + protected virtual Task BeforeRefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken) + { + return _cachedTask; + } + [Obsolete] public virtual async Task RefreshMetadataDirect(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) { diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index a4257b2a5b..94db048647 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -914,11 +914,14 @@ namespace MediaBrowser.Controller.Entities return item; } - public override async Task RefreshMetadataDirect(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) + protected override Task BeforeRefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken) { - var changed = await base.RefreshMetadataDirect(cancellationToken, forceSave, forceRefresh).ConfigureAwait(false); + if (SupportsShortcutChildren && LocationType == LocationType.FileSystem) + { + RefreshLinkedChildren(); + } - return (SupportsShortcutChildren && LocationType == LocationType.FileSystem && RefreshLinkedChildren()) || changed; + return base.BeforeRefreshMetadata(options, cancellationToken); } /// diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index c109e1d0cd..5feb000afd 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -274,33 +274,6 @@ namespace MediaBrowser.Controller.Entities serializer.SerializeToFile(Configuration, xmlPath); } - /// - /// Refresh metadata on us by execution our provider chain - /// The item will be persisted if a change is made by a provider, or if it's new or changed. - /// - /// The cancellation token. - /// if set to true [is new item]. - /// if set to true [force]. - /// true if a provider reports we changed - public override async Task RefreshMetadataDirect(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false) - { - // Reload this - ResetResolveArgs(); - - var updateReason = await ProviderManager.ExecuteMetadataProviders(this, cancellationToken, forceRefresh).ConfigureAwait(false); - - var changed = updateReason.HasValue; - - if (changed || forceSave) - { - cancellationToken.ThrowIfCancellationRequested(); - - await UserManager.UpdateUser(this).ConfigureAwait(false); - } - - return changed; - } - /// /// Updates the configuration. /// diff --git a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs index 391dd456eb..64de1c37f9 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Providers.BoxSets public string Name { - get { return "Media Browser xml"; } + get { return "Media Browser Xml"; } } protected override FileInfo GetXmlFile(string path) diff --git a/MediaBrowser.Providers/Games/GameSystemXmlProvider.cs b/MediaBrowser.Providers/Games/GameSystemXmlProvider.cs index f2001f5861..61fb791e61 100644 --- a/MediaBrowser.Providers/Games/GameSystemXmlProvider.cs +++ b/MediaBrowser.Providers/Games/GameSystemXmlProvider.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Games public string Name { - get { return "Media Browser xml"; } + get { return "Media Browser Xml"; } } protected override FileInfo GetXmlFile(string path) diff --git a/MediaBrowser.Providers/Games/GameXmlProvider.cs b/MediaBrowser.Providers/Games/GameXmlProvider.cs index fb64c2a61b..e2a67de8d4 100644 --- a/MediaBrowser.Providers/Games/GameXmlProvider.cs +++ b/MediaBrowser.Providers/Games/GameXmlProvider.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Games public string Name { - get { return "Media Browser xml"; } + get { return "Media Browser Xml"; } } protected override FileInfo GetXmlFile(string path) diff --git a/MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs b/MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs index 096e68a8aa..701cc9f85f 100644 --- a/MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs +++ b/MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.LiveTv public string Name { - get { return "Media Browser xml"; } + get { return "Media Browser Xml"; } } protected override FileInfo GetXmlFile(string path) diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index f6e27238e7..47345126db 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -89,6 +89,8 @@ namespace MediaBrowser.Providers.Manager // Next run metadata providers if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) { + updateType = updateType | BeforeMetadataRefresh(itemOfType); + var providers = GetProviders(item, lastResult.DateLastMetadataRefresh.HasValue, refreshOptions).ToList(); if (providers.Count > 0) @@ -100,6 +102,8 @@ namespace MediaBrowser.Providers.Manager refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow); refreshResult.AddImageProvidersRefreshed(result.Providers); } + + updateType = updateType | AfterMetadataRefresh(itemOfType); } // Next run remote image providers, but only if local image providers didn't throw an exception @@ -116,8 +120,6 @@ namespace MediaBrowser.Providers.Manager refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow); refreshResult.AddImageProvidersRefreshed(result.Providers); } - - updateType = updateType | AfterMetadataRefresh(itemOfType); } var providersHadChanges = updateType > ItemUpdateType.Unspecified; @@ -157,6 +159,16 @@ namespace MediaBrowser.Providers.Manager return ItemUpdateType.Unspecified; } + /// + /// Befores the metadata refresh. + /// + /// The item. + /// ItemUpdateType. + protected virtual ItemUpdateType BeforeMetadataRefresh(TItemType item) + { + return ItemUpdateType.Unspecified; + } + /// /// Gets the providers. /// @@ -261,12 +273,17 @@ namespace MediaBrowser.Providers.Manager if (localItem.HasMetadata) { - MergeData(localItem.Item, temp, new List(), !options.ReplaceAllMetadata, true); - refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; + if (!string.IsNullOrEmpty(localItem.Item.Name)) + { + MergeData(localItem.Item, temp, new List(), !options.ReplaceAllMetadata, true); + refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; - // Only one local provider allowed per item - hasLocalMetadata = true; - break; + // Only one local provider allowed per item + hasLocalMetadata = true; + break; + } + + Logger.Error("Invalid local metadata found for: " + item.Path); } } catch (OperationCanceledException) diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 9170e7268c..282facfc8b 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -65,6 +65,7 @@ + @@ -151,26 +152,24 @@ - - + - + - + - + - + - diff --git a/MediaBrowser.Providers/Music/AlbumXmlProvider.cs b/MediaBrowser.Providers/Music/AlbumXmlProvider.cs index e0d830369c..7c7de61829 100644 --- a/MediaBrowser.Providers/Music/AlbumXmlProvider.cs +++ b/MediaBrowser.Providers/Music/AlbumXmlProvider.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Music public string Name { - get { return "Media Browser xml"; } + get { return "Media Browser Xml"; } } protected override FileInfo GetXmlFile(string path) diff --git a/MediaBrowser.Providers/Music/ArtistXmlProvider.cs b/MediaBrowser.Providers/Music/ArtistXmlProvider.cs index 3f073d512d..30c38bdaa6 100644 --- a/MediaBrowser.Providers/Music/ArtistXmlProvider.cs +++ b/MediaBrowser.Providers/Music/ArtistXmlProvider.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Music public string Name { - get { return "Media Browser xml"; } + get { return "Media Browser Xml"; } } protected override FileInfo GetXmlFile(string path) diff --git a/MediaBrowser.Providers/People/PersonXmlProvider.cs b/MediaBrowser.Providers/People/PersonXmlProvider.cs index 72aef7a4cf..c23458f686 100644 --- a/MediaBrowser.Providers/People/PersonXmlProvider.cs +++ b/MediaBrowser.Providers/People/PersonXmlProvider.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.People public string Name { - get { return "Media Browser xml"; } + get { return "Media Browser Xml"; } } protected override FileInfo GetXmlFile(string path) diff --git a/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs b/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs index 34f91ba284..bc51a52863 100644 --- a/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/AlbumXmlSaver.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs b/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs index 5c40f3b388..1ae1eaa644 100644 --- a/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/ArtistXmlSaver.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs b/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs index 35c53115d0..06a17528b6 100644 --- a/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/BoxSetXmlSaver.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/ChannelXmlSaver.cs b/MediaBrowser.Providers/Savers/ChannelXmlSaver.cs index 3d8cbb4151..0c857c5ec8 100644 --- a/MediaBrowser.Providers/Savers/ChannelXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/ChannelXmlSaver.cs @@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs index c1f6bb7de4..e60acaa389 100644 --- a/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/EpisodeXmlSaver.cs @@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/FolderXmlSaver.cs b/MediaBrowser.Providers/Savers/FolderXmlSaver.cs index fe8eec3a59..e0ae638e95 100644 --- a/MediaBrowser.Providers/Savers/FolderXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/FolderXmlSaver.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs b/MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs index 38af319236..017f17f8d4 100644 --- a/MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/GameSystemXmlSaver.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/GameXmlSaver.cs b/MediaBrowser.Providers/Savers/GameXmlSaver.cs index b9abb37733..a6225b58c1 100644 --- a/MediaBrowser.Providers/Savers/GameXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/GameXmlSaver.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs index 2c19cb628a..e5ba1aefd0 100644 --- a/MediaBrowser.Providers/Savers/MovieXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/MovieXmlSaver.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/PersonXmlSaver.cs b/MediaBrowser.Providers/Savers/PersonXmlSaver.cs index 12703aa3c5..167e514a82 100644 --- a/MediaBrowser.Providers/Savers/PersonXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/PersonXmlSaver.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs index 6c4d3fb19a..5773fc1de3 100644 --- a/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/SeasonXmlSaver.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs index 21019fa0ed..b76167868e 100644 --- a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.Savers { get { - return "Media Browser xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs index 50db33b3da..60643252b4 100644 --- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs @@ -1,190 +1,303 @@ using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; using MediaBrowser.Model.Providers; +using MediaBrowser.Providers.Music; 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 MediaBrowser.Providers.Music; +using System.Xml; namespace MediaBrowser.Providers.TV { - /// - /// Class FanArtSeasonProvider - /// - class FanArtSeasonProvider : BaseMetadataProvider + public class FanartSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor { - /// - /// The _provider manager - /// - private readonly IProviderManager _providerManager; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + private readonly IServerConfigurationManager _config; + private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; - /// - /// Initializes a new instance of the class. - /// - /// The log manager. - /// The configuration manager. - /// The provider manager. - public FanArtSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem) - : base(logManager, configurationManager) + public FanartSeasonImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem) { - _providerManager = providerManager; + _config = config; + _httpClient = httpClient; _fileSystem = fileSystem; } - public override ItemUpdateType ItemUpdateType + public string Name { - get - { - return ItemUpdateType.ImageUpdate; - } + get { return ProviderName; } } - - /// - /// Supportses the specified item. - /// - /// The item. - /// true if XXXX, false otherwise - public override bool Supports(BaseItem item) + + public static string ProviderName + { + get { return "FanArt"; } + } + + public bool Supports(IHasImages item) { return item is Season; } - /// - /// Gets the priority. - /// - /// The priority. - public override MetadataProviderPriority Priority + public IEnumerable GetSupportedImages(IHasImages item) { - get { return MetadataProviderPriority.Third; } + return new List + { + ImageType.Backdrop, + ImageType.Thumb + }; } - protected override DateTime CompareDate(BaseItem item) + 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 async Task> GetAllImages(IHasImages item, CancellationToken cancellationToken) + { + var list = new List(); + + var season = (Season)item; + var series = season.Series; + + if (series != null) + { + var id = series.GetProviderId(MetadataProviders.Tvdb); + + if (!string.IsNullOrEmpty(id) && season.IndexNumber.HasValue) + { + await FanArtTvProvider.Current.EnsureSeriesXml(id, cancellationToken).ConfigureAwait(false); + + var xmlPath = FanArtTvProvider.Current.GetFanartXmlPath(id); + + try + { + AddImages(list, season.IndexNumber.Value, xmlPath, cancellationToken); + } + catch (FileNotFoundException) + { + // No biggie. Don't blow up + } + } + } + + 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); + } + + private void AddImages(List list, int seasonNumber, 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 "series": + { + using (var subReader = reader.ReadSubtree()) + { + AddImages(list, subReader, seasonNumber, cancellationToken); + } + break; + } + + default: + reader.Skip(); + break; + } + } + } + } + } + } + + private void AddImages(List list, XmlReader reader, int seasonNumber, CancellationToken cancellationToken) + { + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "seasonthumbs": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281, seasonNumber); + } + break; + } + case "showbackgrounds": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080, seasonNumber); + } + break; + } + default: + { + using (reader.ReadSubtree()) + { + } + break; + } + } + } + } + } + + private void PopulateImageCategory(List list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, int seasonNumber) + { + reader.MoveToContent(); + + while (reader.Read()) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "seasonthumb": + case "showbackground": + { + var url = reader.GetAttribute("url"); + var season = reader.GetAttribute("season"); + + int imageSeasonNumber; + + if (!string.IsNullOrEmpty(url) && + !string.IsNullOrEmpty(season) && + int.TryParse(season, NumberStyles.Any, _usCulture, out imageSeasonNumber) && + seasonNumber == imageSeasonNumber) + { + 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); + } + + break; + } + default: + reader.Skip(); + break; + } + } + } + } + + public int Order + { + get { return 1; } + } + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url, + ResourcePool = FanartArtistProvider.FanArtResourcePool + }); + } + + public bool HasChanged(IHasMetadata item, DateTime date) { var season = (Season)item; - var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null; + var series = season.Series; - if (!string.IsNullOrEmpty(seriesId)) + if (series == null) + { + return false; + } + + var tvdbId = series.GetProviderId(MetadataProviders.Tvdb); + + if (!String.IsNullOrEmpty(tvdbId)) { // Process images - var imagesXmlPath = FanArtTvProvider.Current.GetFanartXmlPath(seriesId); + var imagesXmlPath = FanArtTvProvider.Current.GetFanartXmlPath(tvdbId); - var imagesFileInfo = new FileInfo(imagesXmlPath); + var fileInfo = new FileInfo(imagesXmlPath); - if (imagesFileInfo.Exists) - { - return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo); - } + return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date; } - return base.CompareDate(item); - } - - /// - /// 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 season = (Season) item; - - // Process images - var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualFanartSeasonImageProvider.ProviderName).ConfigureAwait(false); - await FetchImages(season, images.ToList(), cancellationToken).ConfigureAwait(false); - - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - return true; - } - - /// - /// Fetches the images. - /// - /// The season. - /// The images. - /// The cancellation token. - /// Task. - private async Task FetchImages(Season season, List images, CancellationToken cancellationToken) - { - var options = ConfigurationManager.Configuration.GetMetadataOptions("Season") ?? new MetadataOptions(); - - if (options.IsEnabled(ImageType.Thumb) && !season.HasImage(ImageType.Thumb) && !season.LockedFields.Contains(MetadataFields.Images)) - { - await SaveImage(season, images, ImageType.Thumb, cancellationToken).ConfigureAwait(false); - } - } - - private async Task SaveImage(BaseItem item, List images, ImageType type, CancellationToken cancellationToken) - { - foreach (var image in images.Where(i => i.Type == type)) - { - try - { - await _providerManager.SaveImage(item, image.Url, FanartArtistProvider.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; - } - } - } - - /// - /// Gets a value indicating whether [requires internet]. - /// - /// true if [requires internet]; otherwise, false. - public override bool RequiresInternet - { - get - { - return true; - } - } - - /// - /// Gets a value indicating whether [refresh on version change]. - /// - /// true if [refresh on version change]; otherwise, false. - protected override bool RefreshOnVersionChange - { - get - { - return true; - } - } - - /// - /// Gets the provider version. - /// - /// The provider version. - protected override string ProviderVersion - { - get - { - return "3"; - } + return false; } } } diff --git a/MediaBrowser.Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Providers/TV/FanArtTVProvider.cs index 3f2199fc41..baadf350fa 100644 --- a/MediaBrowser.Providers/TV/FanArtTVProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtTVProvider.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.TV return ItemUpdateType.ImageUpdate; } } - + /// /// Needses the refresh internal. /// @@ -160,7 +160,7 @@ namespace MediaBrowser.Providers.TV var dataPath = GetSeriesDataPath(ConfigurationManager.ApplicationPaths, tvdbId); return Path.Combine(dataPath, "fanart.xml"); } - + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); public override async Task FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken) @@ -199,7 +199,7 @@ namespace MediaBrowser.Providers.TV private async Task FetchFromXml(BaseItem item, List images, CancellationToken cancellationToken) { var options = ConfigurationManager.Configuration.GetMetadataOptions("Series") ?? new MetadataOptions(); - + if (!item.LockedFields.Contains(MetadataFields.Images)) { cancellationToken.ThrowIfCancellationRequested(); @@ -278,6 +278,23 @@ namespace MediaBrowser.Providers.TV } } + internal Task EnsureSeriesXml(string tvdbId, CancellationToken cancellationToken) + { + var xmlPath = GetSeriesDataPath(ConfigurationManager.ApplicationPaths, tvdbId); + + var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath); + + if (fileInfo.Exists) + { + if (ConfigurationManager.Configuration.EnableFanArtUpdates || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7) + { + return Task.FromResult(true); + } + } + + return DownloadSeriesXml(tvdbId, cancellationToken); + } + /// /// Downloads the series XML. /// diff --git a/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs b/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs deleted file mode 100644 index c7b2f595be..0000000000 --- a/MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs +++ /dev/null @@ -1,276 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; -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; -using MediaBrowser.Providers.Music; - -namespace MediaBrowser.Providers.TV -{ - public class ManualFanartSeasonImageProvider : IRemoteImageProvider, IHasOrder - { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private readonly IServerConfigurationManager _config; - private readonly IHttpClient _httpClient; - - public ManualFanartSeasonImageProvider(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 Season; - } - - public IEnumerable GetSupportedImages(IHasImages item) - { - return new List - { - ImageType.Backdrop, - ImageType.Thumb - }; - } - - 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 list = new List(); - - var season = (Season)item; - var series = season.Series; - - if (series != null) - { - var id = series.GetProviderId(MetadataProviders.Tvdb); - - if (!string.IsNullOrEmpty(id) && season.IndexNumber.HasValue) - { - var xmlPath = FanArtTvProvider.Current.GetFanartXmlPath(id); - - try - { - AddImages(list, season.IndexNumber.Value, xmlPath, cancellationToken); - } - catch (FileNotFoundException) - { - // No biggie. Don't blow up - } - } - } - - 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); - } - - private void AddImages(List list, int seasonNumber, 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 "series": - { - using (var subReader = reader.ReadSubtree()) - { - AddImages(list, subReader, seasonNumber, cancellationToken); - } - break; - } - - default: - reader.Skip(); - break; - } - } - } - } - } - } - - private void AddImages(List list, XmlReader reader, int seasonNumber, CancellationToken cancellationToken) - { - reader.MoveToContent(); - - while (reader.Read()) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "seasonthumbs": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281, seasonNumber); - } - break; - } - case "showbackgrounds": - { - using (var subReader = reader.ReadSubtree()) - { - PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080, seasonNumber); - } - break; - } - default: - { - using (reader.ReadSubtree()) - { - } - break; - } - } - } - } - } - - private void PopulateImageCategory(List list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, int seasonNumber) - { - reader.MoveToContent(); - - while (reader.Read()) - { - cancellationToken.ThrowIfCancellationRequested(); - - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "seasonthumb": - case "showbackground": - { - var url = reader.GetAttribute("url"); - var season = reader.GetAttribute("season"); - - int imageSeasonNumber; - - if (!string.IsNullOrEmpty(url) && - !string.IsNullOrEmpty(season) && - int.TryParse(season, NumberStyles.Any, _usCulture, out imageSeasonNumber) && - seasonNumber == imageSeasonNumber) - { - 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); - } - - break; - } - default: - reader.Skip(); - break; - } - } - } - } - - public int Order - { - get { return 1; } - } - - public Task GetImageResponse(string url, CancellationToken cancellationToken) - { - return _httpClient.GetResponse(new HttpRequestOptions - { - CancellationToken = cancellationToken, - Url = url, - ResourcePool = FanartArtistProvider.FanArtResourcePool - }); - } - } -} diff --git a/MediaBrowser.Providers/TV/SeasonIndexNumberProvider.cs b/MediaBrowser.Providers/TV/SeasonIndexNumberProvider.cs deleted file mode 100644 index 5937842018..0000000000 --- a/MediaBrowser.Providers/TV/SeasonIndexNumberProvider.cs +++ /dev/null @@ -1,83 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Providers.TV -{ - class SeasonIndexNumberProvider : BaseMetadataProvider - { - /// - /// Initializes a new instance of the class. - /// - /// The log manager. - /// The configuration manager. - public SeasonIndexNumberProvider(ILogManager logManager, IServerConfigurationManager configurationManager) - : base(logManager, configurationManager) - { - } - - protected override bool RefreshOnVersionChange - { - get - { - return true; - } - } - - protected override string ProviderVersion - { - get - { - return "2"; - } - } - - /// - /// Supportses the specified item. - /// - /// The item. - /// true if XXXX, false otherwise - public override bool Supports(BaseItem item) - { - if (item is Season) - { - var locationType = item.LocationType; - return locationType != LocationType.Virtual && locationType != LocationType.Remote; - } - return false; - } - - /// - /// Fetches metadata and returns true or false indicating if any work that requires persistence was done - /// - /// The item. - /// if set to true [force]. - /// The provider information. - /// The cancellation token. - /// Task{System.Boolean}. - public override Task FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken) - { - item.IndexNumber = TVUtils.GetSeasonNumberFromPath(item.Path); - - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - - return TrueTaskResult; - } - - /// - /// Gets the priority. - /// - /// The priority. - public override MetadataProviderPriority Priority - { - get { return MetadataProviderPriority.First; } - } - } -} diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs new file mode 100644 index 0000000000..da276221b6 --- /dev/null +++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs @@ -0,0 +1,58 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Providers.Manager; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.TV +{ + public class SeasonMetadataService : MetadataService + { + private readonly ILibraryManager _libraryManager; + + public SeasonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, ILibraryManager libraryManager) + : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem) + { + _libraryManager = libraryManager; + } + + /// + /// Merges the specified source. + /// + /// The source. + /// The target. + /// The locked fields. + /// if set to true [replace data]. + /// if set to true [merge metadata settings]. + protected override void MergeData(Season source, Season target, List lockedFields, bool replaceData, bool mergeMetadataSettings) + { + ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + } + + protected override Task SaveItem(Season item, ItemUpdateType reason, CancellationToken cancellationToken) + { + return _libraryManager.UpdateItem(item, reason, cancellationToken); + } + + protected override ItemUpdateType BeforeMetadataRefresh(Season item) + { + var updateType = base.BeforeMetadataRefresh(item); + + var currentIndexNumber = item.IndexNumber; + + item.IndexNumber = item.IndexNumber ?? TVUtils.GetSeasonNumberFromPath(item.Path); + + if ((currentIndexNumber ?? -1) != (item.IndexNumber ?? -1)) + { + updateType = updateType | ItemUpdateType.MetadataImport; + } + return updateType; + } + } +} diff --git a/MediaBrowser.Providers/TV/SeasonProviderFromXml.cs b/MediaBrowser.Providers/TV/SeasonProviderFromXml.cs deleted file mode 100644 index 9fbcad7c0c..0000000000 --- a/MediaBrowser.Providers/TV/SeasonProviderFromXml.cs +++ /dev/null @@ -1,97 +0,0 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.IO; -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.TV -{ - /// - /// Class SeriesProviderFromXml - /// - public class SeasonProviderFromXml : BaseMetadataProvider - { - private readonly IFileSystem _fileSystem; - - public SeasonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem) - : base(logManager, configurationManager) - { - _fileSystem = fileSystem; - } - - /// - /// Supportses the specified item. - /// - /// The item. - /// true if XXXX, false otherwise - public override bool Supports(BaseItem item) - { - return item is Season && item.LocationType == LocationType.FileSystem; - } - - /// - /// Gets the priority. - /// - /// The priority. - public override MetadataProviderPriority Priority - { - get { return MetadataProviderPriority.Second; } - } - - private const string XmlFileName = "season.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; - } - - /// - /// 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 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(Logger).Fetch((Season)item, path, cancellationToken); - } - finally - { - XmlParsingResourcePool.Release(); - } - - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - - return true; - } - - return false; - } - } -} diff --git a/MediaBrowser.Providers/TV/SeasonXmlProvider.cs b/MediaBrowser.Providers/TV/SeasonXmlProvider.cs new file mode 100644 index 0000000000..9dcc9fe4f2 --- /dev/null +++ b/MediaBrowser.Providers/TV/SeasonXmlProvider.cs @@ -0,0 +1,63 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Logging; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Providers.TV +{ + /// + /// Class SeriesProviderFromXml + /// + public class SeasonXmlProvider : BaseXmlProvider, ILocalMetadataProvider + { + private readonly ILogger _logger; + + public SeasonXmlProvider(IFileSystem fileSystem, ILogger logger) + : base(fileSystem) + { + _logger = logger; + } + + public async Task> GetMetadata(string path, CancellationToken cancellationToken) + { + path = GetXmlFile(path).FullName; + + var result = new MetadataResult(); + + await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + var person = new Season(); + + new BaseItemXmlParser(_logger).Fetch(person, path, cancellationToken); + result.HasMetadata = true; + result.Item = person; + } + catch (FileNotFoundException) + { + result.HasMetadata = false; + } + finally + { + XmlParsingResourcePool.Release(); + } + + return result; + } + + public string Name + { + get { return "Media Browser Xml"; } + } + + protected override FileInfo GetXmlFile(string path) + { + return new FileInfo(Path.Combine(path, "season.xml")); + } + } +} + diff --git a/MediaBrowser.Providers/TV/ManualTvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs similarity index 87% rename from MediaBrowser.Providers/TV/ManualTvdbSeasonImageProvider.cs rename to MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs index 458482bf6d..a63f3ee241 100644 --- a/MediaBrowser.Providers/TV/ManualTvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.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.TV; @@ -19,16 +20,18 @@ using System.Xml; namespace MediaBrowser.Providers.TV { - public class ManualTvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder + public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor { private readonly IServerConfigurationManager _config; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IHttpClient _httpClient; + private readonly IFileSystem _fileSystem; - public ManualTvdbSeasonImageProvider(IServerConfigurationManager config, IHttpClient httpClient) + public TvdbSeasonImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem) { _config = config; _httpClient = httpClient; + _fileSystem = fileSystem; } public string Name @@ -63,14 +66,17 @@ namespace MediaBrowser.Providers.TV return images.Where(i => i.Type == imageType); } - public Task> GetAllImages(IHasImages item, CancellationToken cancellationToken) + public async Task> GetAllImages(IHasImages item, CancellationToken cancellationToken) { var season = (Season)item; + var series = season.Series; - var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null; + var seriesId = series != null ? series.GetProviderId(MetadataProviders.Tvdb) : null; if (!string.IsNullOrEmpty(seriesId) && season.IndexNumber.HasValue) { + await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesId, series.GetPreferredMetadataLanguage(), cancellationToken).ConfigureAwait(false); + // Process images var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId); @@ -78,9 +84,7 @@ namespace MediaBrowser.Providers.TV try { - var result = GetImages(path, item.GetPreferredMetadataLanguage(), season.IndexNumber.Value, cancellationToken); - - return Task.FromResult(result); + return GetImages(path, item.GetPreferredMetadataLanguage(), season.IndexNumber.Value, cancellationToken); } catch (FileNotFoundException) { @@ -88,7 +92,7 @@ namespace MediaBrowser.Providers.TV } } - return Task.FromResult>(new RemoteImageInfo[] { }); + return new RemoteImageInfo[] { }; } private IEnumerable GetImages(string xmlPath, string preferredLanguage, int seasonNumber, CancellationToken cancellationToken) @@ -335,5 +339,30 @@ namespace MediaBrowser.Providers.TV ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool }); } + + public bool HasChanged(IHasMetadata item, DateTime date) + { + var season = (Season)item; + var series = season.Series; + + if (series == null) + { + return false; + } + + var tvdbId = series.GetProviderId(MetadataProviders.Tvdb); + + if (!String.IsNullOrEmpty(tvdbId)) + { + // Process images + var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId), "banners.xml"); + + var fileInfo = new FileInfo(imagesXmlPath); + + return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date; + } + + return false; + } } } diff --git a/MediaBrowser.Providers/TV/TvdbSeasonProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonProvider.cs deleted file mode 100644 index d7281ac218..0000000000 --- a/MediaBrowser.Providers/TV/TvdbSeasonProvider.cs +++ /dev/null @@ -1,211 +0,0 @@ -using System.Net; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; -using MediaBrowser.Model.Providers; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Providers.TV -{ - /// - /// Class RemoteSeasonProvider - /// - class TvdbSeasonProvider : BaseMetadataProvider - { - /// - /// The _provider manager - /// - private readonly IProviderManager _providerManager; - private readonly IFileSystem _fileSystem; - - /// - /// Initializes a new instance of the class. - /// - /// The log manager. - /// The configuration manager. - /// The provider manager. - /// httpClient - public TvdbSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem) - : base(logManager, configurationManager) - { - _providerManager = providerManager; - _fileSystem = fileSystem; - } - - /// - /// Supportses the specified item. - /// - /// The item. - /// true if XXXX, false otherwise - public override bool Supports(BaseItem item) - { - return item is Season; - } - - /// - /// Gets the priority. - /// - /// The priority. - public override MetadataProviderPriority Priority - { - // Run after fanart - get { return MetadataProviderPriority.Fourth; } - } - - /// - /// Gets a value indicating whether [requires internet]. - /// - /// true if [requires internet]; otherwise, false. - public override bool RequiresInternet - { - get - { - return true; - } - } - - public override ItemUpdateType ItemUpdateType - { - get - { - return ItemUpdateType.ImageUpdate; - } - } - - /// - /// Gets a value indicating whether [refresh on version change]. - /// - /// true if [refresh on version change]; otherwise, false. - protected override bool RefreshOnVersionChange - { - get - { - return true; - } - } - - /// - /// Gets the provider version. - /// - /// The provider version. - protected override string ProviderVersion - { - get - { - return "2"; - } - } - - protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) - { - var season = (Season)item; - var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null; - - if (!string.IsNullOrEmpty(seriesId)) - { - // Process images - var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml"); - - var imagesFileInfo = new FileInfo(imagesXmlPath); - - if (imagesFileInfo.Exists) - { - return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo) > providerInfo.LastRefreshed; - } - } - return false; - } - - protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) - { - if (item.HasImage(ImageType.Primary) && item.HasImage(ImageType.Banner) && item.BackdropImagePaths.Count > 0) - { - return false; - } - return base.NeedsRefreshInternal(item, providerInfo); - } - - /// - /// 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 images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualTvdbSeasonImageProvider.ProviderName).ConfigureAwait(false); - - await DownloadImages(item, images.ToList(), cancellationToken).ConfigureAwait(false); - - SetLastRefreshed(item, DateTime.UtcNow, providerInfo); - return true; - } - - private async Task DownloadImages(BaseItem item, List images, CancellationToken cancellationToken) - { - var options = ConfigurationManager.Configuration.GetMetadataOptions("Season") ?? new MetadataOptions(); - var backdropLimit = options.GetLimit(ImageType.Backdrop); - - if (!item.LockedFields.Contains(MetadataFields.Images)) - { - if (!item.HasImage(ImageType.Primary)) - { - await SaveImage(item, images, ImageType.Primary, cancellationToken).ConfigureAwait(false); - } - - if (options.IsEnabled(ImageType.Banner) && !item.HasImage(ImageType.Banner)) - { - await SaveImage(item, images, ImageType.Banner, cancellationToken).ConfigureAwait(false); - } - } - - if (options.IsEnabled(ImageType.Backdrop) && item.BackdropImagePaths.Count < backdropLimit && !item.LockedFields.Contains(MetadataFields.Backdrops)) - { - foreach (var backdrop in images.Where(i => i.Type == ImageType.Backdrop)) - { - var url = backdrop.Url; - - await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, null, cancellationToken).ConfigureAwait(false); - - if (item.BackdropImagePaths.Count >= backdropLimit) break; - } - } - } - - private async Task SaveImage(BaseItem item, List images, ImageType type, CancellationToken cancellationToken) - { - foreach (var image in images.Where(i => i.Type == type)) - { - try - { - await _providerManager.SaveImage(item, image.Url, TvdbSeriesProvider.Current.TvDbResourcePool, 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; - } - } - } - } -} diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs index 4df391e2a8..8d7ef5af99 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs @@ -324,6 +324,26 @@ namespace MediaBrowser.Providers.TV await ExtractEpisodes(seriesDataPath, Path.Combine(seriesDataPath, preferredMetadataLanguage + ".xml"), lastTvDbUpdateTime).ConfigureAwait(false); } + internal async Task EnsureSeriesInfo(string seriesId, string preferredMetadataLanguage, CancellationToken cancellationToken) + { + var seriesDataPath = GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId); + + Directory.CreateDirectory(seriesDataPath); + + var files = Directory.EnumerateFiles(seriesDataPath, "*.xml", SearchOption.TopDirectoryOnly) + .Select(Path.GetFileName) + .ToList(); + + var seriesXmlFilename = preferredMetadataLanguage + ".xml"; + + // Only download if not already there + // The prescan task will take care of updates so we don't need to re-download here + if (!files.Contains("banners.xml", StringComparer.OrdinalIgnoreCase) || !files.Contains("actors.xml", StringComparer.OrdinalIgnoreCase) || !files.Contains(seriesXmlFilename, StringComparer.OrdinalIgnoreCase)) + { + await DownloadSeriesZip(seriesId, seriesDataPath, null, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false); + } + } + private void DeleteXmlFiles(string path) { try diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index daf905a8a9..d38e020faf 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.317 + 3.0.318 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 4a3c258802..5ad30a09fc 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.317 + 3.0.318 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 08f0a11888..a24d6c3ace 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.317 + 3.0.318 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - +