From c702fb21794c030abffdf5e73794316119872060 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 24 May 2013 11:29:10 -0400 Subject: [PATCH] added separate tvdb series images provider --- .../MediaBrowser.Controller.csproj | 1 + .../Providers/TV/RemoteSeriesProvider.cs | 92 +----- .../Providers/TV/TvdbSeriesImageProvider.cs | 280 ++++++++++++++++++ 3 files changed, 286 insertions(+), 87 deletions(-) create mode 100644 MediaBrowser.Controller/Providers/TV/TvdbSeriesImageProvider.cs diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 017f3dead1..9f345e06d8 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -75,6 +75,7 @@ + diff --git a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs index 62cc21510a..cf3bcbd70a 100644 --- a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs +++ b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs @@ -228,15 +228,13 @@ namespace MediaBrowser.Controller.Providers.TV cancellationToken.ThrowIfCancellationRequested(); - var status = ProviderRefreshStatus.Success; - if (!string.IsNullOrEmpty(seriesId)) { series.SetProviderId(MetadataProviders.Tvdb, seriesId); var seriesDataPath = GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId); - status = await FetchSeriesData(series, seriesId, seriesDataPath, cancellationToken).ConfigureAwait(false); + await FetchSeriesData(series, seriesId, seriesDataPath, cancellationToken).ConfigureAwait(false); } BaseProviderInfo data; @@ -247,8 +245,8 @@ namespace MediaBrowser.Controller.Providers.TV } data.Data = GetComparisonData(item); - - SetLastRefreshed(item, DateTime.UtcNow, status); + + SetLastRefreshed(item, DateTime.UtcNow); return true; } @@ -260,10 +258,8 @@ namespace MediaBrowser.Controller.Providers.TV /// The series data path. /// The cancellation token. /// Task{System.Boolean}. - private async Task FetchSeriesData(Series series, string seriesId, string seriesDataPath, CancellationToken cancellationToken) + private async Task FetchSeriesData(Series series, string seriesId, string seriesDataPath, CancellationToken cancellationToken) { - var status = ProviderRefreshStatus.Success; - var files = Directory.EnumerateFiles(seriesDataPath, "*.xml", SearchOption.TopDirectoryOnly).Select(Path.GetFileName).ToArray(); var seriesXmlFilename = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower() + ".xml"; @@ -299,24 +295,6 @@ namespace MediaBrowser.Controller.Providers.TV await _providerManager.SaveToLibraryFilesystem(series, Path.Combine(series.MetaLocation, LocalMetaFileName), ms, cancellationToken).ConfigureAwait(false); } } - - // Process images - var imagesXmlPath = Path.Combine(seriesDataPath, "banners.xml"); - - try - { - var xmlDoc = new XmlDocument(); - xmlDoc.Load(imagesXmlPath); - - await FetchImages(series, xmlDoc, cancellationToken).ConfigureAwait(false); - } - catch (HttpException) - { - // Have the provider try again next time, but don't let it fail here - status = ProviderRefreshStatus.CompletedWithErrors; - } - - return status; } /// @@ -329,7 +307,7 @@ namespace MediaBrowser.Controller.Providers.TV internal async Task DownloadSeriesZip(string seriesId, string seriesDataPath, CancellationToken cancellationToken) { var url = string.Format(SeriesGetZip, TVUtils.TvdbApiKey, seriesId, ConfigurationManager.Configuration.PreferredMetadataLanguage); - + using (var zipStream = await HttpClient.Get(new HttpRequestOptions { Url = url, @@ -486,66 +464,6 @@ namespace MediaBrowser.Controller.Providers.TV /// protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// - /// Fetches the images. - /// - /// The series. - /// The images. - /// The cancellation token. - /// Task. - private async Task FetchImages(Series series, XmlDocument images, CancellationToken cancellationToken) - { - if (ConfigurationManager.Configuration.RefreshItemImages || !series.HasImage(ImageType.Primary)) - { - var n = images.SelectSingleNode("//Banner[BannerType='poster']"); - if (n != null) - { - n = n.SelectSingleNode("./BannerPath"); - if (n != null) - { - series.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false); - } - } - } - - if (ConfigurationManager.Configuration.DownloadSeriesImages.Banner && (ConfigurationManager.Configuration.RefreshItemImages || !series.HasImage(ImageType.Banner))) - { - var n = images.SelectSingleNode("//Banner[BannerType='series']"); - if (n != null) - { - n = n.SelectSingleNode("./BannerPath"); - if (n != null) - { - var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken); - - series.SetImage(ImageType.Banner, bannerImagePath); - } - } - } - - if (series.BackdropImagePaths.Count < ConfigurationManager.Configuration.MaxBackdrops) - { - var bdNo = series.BackdropImagePaths.Count; - var xmlNodeList = images.SelectNodes("//Banner[BannerType='fanart']"); - if (xmlNodeList != null) - { - foreach (XmlNode b in xmlNodeList) - { - var p = b.SelectSingleNode("./BannerPath"); - - if (p != null) - { - var bdName = "backdrop" + (bdNo > 0 ? bdNo.ToString(UsCulture) : ""); - series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false)); - bdNo++; - } - - if (series.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) break; - } - } - } - } - /// /// Determines whether [has local meta] [the specified item]. /// diff --git a/MediaBrowser.Controller/Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Controller/Providers/TV/TvdbSeriesImageProvider.cs new file mode 100644 index 0000000000..423e90efb3 --- /dev/null +++ b/MediaBrowser.Controller/Providers/TV/TvdbSeriesImageProvider.cs @@ -0,0 +1,280 @@ +using System.Globalization; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; + +namespace MediaBrowser.Controller.Providers.TV +{ + public class TvdbSeriesImageProvider : BaseMetadataProvider + { + /// + /// Gets the HTTP client. + /// + /// The HTTP client. + protected IHttpClient HttpClient { get; private set; } + + /// + /// The _provider manager + /// + private readonly IProviderManager _providerManager; + + /// + /// Initializes a new instance of the class. + /// + /// The HTTP client. + /// The log manager. + /// The configuration manager. + /// The provider manager. + /// httpClient + public TvdbSeriesImageProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager) + : base(logManager, configurationManager) + { + if (httpClient == null) + { + throw new ArgumentNullException("httpClient"); + } + HttpClient = httpClient; + _providerManager = providerManager; + } + + /// + /// Supportses the specified item. + /// + /// The item. + /// true if XXXX, false otherwise + public override bool Supports(BaseItem item) + { + return item is Series; + } + + /// + /// 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; + } + } + + /// + /// Returns true or false indicating if the provider should refresh when the contents of it's directory changes + /// + /// true if [refresh on file system stamp change]; otherwise, false. + protected override bool RefreshOnFileSystemStampChange + { + get + { + return ConfigurationManager.Configuration.SaveLocalMeta; + } + } + + /// + /// 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 "1"; + } + } + + /// + /// Needses the refresh internal. + /// + /// The item. + /// The provider info. + /// true if XXXX, false otherwise + protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) + { + if (GetComparisonData(item) != providerInfo.Data) + { + return true; + } + + return base.NeedsRefreshInternal(item, providerInfo); + } + + /// + /// Gets the comparison data. + /// + /// The item. + /// Guid. + private Guid GetComparisonData(BaseItem item) + { + var seriesId = item.GetProviderId(MetadataProviders.Tvdb); + + if (!string.IsNullOrEmpty(seriesId)) + { + // Process images + var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml"); + + var imagesFileInfo = new FileInfo(imagesXmlPath); + + return GetComparisonData(imagesFileInfo); + } + + return Guid.Empty; + } + + /// + /// Gets the comparison data. + /// + /// The images file info. + /// Guid. + private Guid GetComparisonData(FileInfo imagesFileInfo) + { + var date = imagesFileInfo.Exists ? imagesFileInfo.LastWriteTimeUtc : DateTime.MinValue; + + var key = date.Ticks + imagesFileInfo.FullName; + + return key.GetMD5(); + } + + /// + /// 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, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var series = (Series)item; + var seriesId = series.GetProviderId(MetadataProviders.Tvdb); + + if (!string.IsNullOrEmpty(seriesId)) + { + // Process images + var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml"); + + var imagesFileInfo = new FileInfo(imagesXmlPath); + + if (imagesFileInfo.Exists) + { + if (!series.HasImage(ImageType.Primary) || !series.HasImage(ImageType.Banner) || series.BackdropImagePaths.Count == 0) + { + var xmlDoc = new XmlDocument(); + xmlDoc.Load(imagesXmlPath); + + await FetchImages(series, xmlDoc, cancellationToken).ConfigureAwait(false); + } + } + + BaseProviderInfo data; + if (!item.ProviderData.TryGetValue(Id, out data)) + { + data = new BaseProviderInfo(); + item.ProviderData[Id] = data; + } + + data.Data = GetComparisonData(imagesFileInfo); + + SetLastRefreshed(item, DateTime.UtcNow); + return true; + } + + return false; + } + + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// Fetches the images. + /// + /// The series. + /// The images. + /// The cancellation token. + /// Task. + private async Task FetchImages(Series series, XmlDocument images, CancellationToken cancellationToken) + { + if (ConfigurationManager.Configuration.RefreshItemImages || !series.HasImage(ImageType.Primary)) + { + var n = images.SelectSingleNode("//Banner[BannerType='poster']"); + if (n != null) + { + n = n.SelectSingleNode("./BannerPath"); + if (n != null) + { + series.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false); + } + } + } + + if (ConfigurationManager.Configuration.DownloadSeriesImages.Banner && (ConfigurationManager.Configuration.RefreshItemImages || !series.HasImage(ImageType.Banner))) + { + var n = images.SelectSingleNode("//Banner[BannerType='series']"); + if (n != null) + { + n = n.SelectSingleNode("./BannerPath"); + if (n != null) + { + var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken); + + series.SetImage(ImageType.Banner, bannerImagePath); + } + } + } + + if (series.BackdropImagePaths.Count < ConfigurationManager.Configuration.MaxBackdrops) + { + var bdNo = series.BackdropImagePaths.Count; + var xmlNodeList = images.SelectNodes("//Banner[BannerType='fanart']"); + if (xmlNodeList != null) + { + foreach (XmlNode b in xmlNodeList) + { + var p = b.SelectSingleNode("./BannerPath"); + + if (p != null) + { + var bdName = "backdrop" + (bdNo > 0 ? bdNo.ToString(UsCulture) : ""); + series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false)); + bdNo++; + } + + if (series.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) break; + } + } + } + } + } +}