2
0
Эх сурвалжийг харах

fixes #605 - Add manual image selection for Series

Luke Pulverenti 11 жил өмнө
parent
commit
403534f80e

+ 1 - 1
MediaBrowser.Api/RemoteImageService.cs

@@ -20,7 +20,7 @@ namespace MediaBrowser.Api
         [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
         public string Id { get; set; }
 
-        [ApiMember(Name = "Type", Description = "The image type", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        [ApiMember(Name = "Type", Description = "The image type", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public ImageType? Type { get; set; }
 
         /// <summary>

+ 4 - 3
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -114,9 +114,10 @@
     <Compile Include="TV\ManualFanartSeriesProvider.cs" />
     <Compile Include="TV\ManualTvdbEpisodeImageProvider.cs" />
     <Compile Include="TV\ManualTvdbSeasonImageProvider.cs" />
-    <Compile Include="TV\RemoteEpisodeProvider.cs" />
-    <Compile Include="TV\RemoteSeasonProvider.cs" />
-    <Compile Include="TV\RemoteSeriesProvider.cs" />
+    <Compile Include="TV\ManualTvdbSeriesImageProvider.cs" />
+    <Compile Include="TV\TvdbEpisodeProvider.cs" />
+    <Compile Include="TV\TvdbSeasonProvider.cs" />
+    <Compile Include="TV\TvdbSeriesProvider.cs" />
     <Compile Include="TV\SeasonProviderFromXml.cs" />
     <Compile Include="TV\SeriesDynamicInfoProvider.cs" />
     <Compile Include="TV\SeriesPostScanTask.cs" />

+ 1 - 1
MediaBrowser.Providers/TV/ManualFanartSeasonProvider.cs

@@ -245,7 +245,7 @@ namespace MediaBrowser.Providers.TV
 
         public int Priority
         {
-            get { return 1; }
+            get { return 0; }
         }
     }
 }

+ 1 - 1
MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs

@@ -303,7 +303,7 @@ namespace MediaBrowser.Providers.TV
 
         public int Priority
         {
-            get { return 1; }
+            get { return 0; }
         }
     }
 }

+ 2 - 2
MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs

@@ -52,9 +52,9 @@ namespace MediaBrowser.Providers.TV
             if (!string.IsNullOrEmpty(seriesId))
             {
                 // Process images
-                var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
+                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
 
-                var files = RemoteEpisodeProvider.Current.GetEpisodeXmlFiles(episode, seriesDataPath);
+                var files = TvdbEpisodeProvider.Current.GetEpisodeXmlFiles(episode, seriesDataPath);
 
                 var result = files.Select(i => GetImageInfo(i, cancellationToken)).Where(i => i != null);
 

+ 8 - 4
MediaBrowser.Providers/TV/ManualTvdbSeasonImageProvider.cs

@@ -59,7 +59,7 @@ namespace MediaBrowser.Providers.TV
             if (!string.IsNullOrEmpty(seriesId) && season.IndexNumber.HasValue)
             {
                 // Process images
-                var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
+                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
 
                 var path = Path.Combine(seriesDataPath, "banners.xml");
 
@@ -279,10 +279,14 @@ namespace MediaBrowser.Providers.TV
                     ProviderName = Name,
                     Language = language,
                     Width = width,
-                    Height = height,
-                    ThumbnailUrl = thumbnailUrl
+                    Height = height
                 };
 
+                if (!string.IsNullOrEmpty(thumbnailUrl))
+                {
+                    imageInfo.ThumbnailUrl = TVUtils.BannerUrl + thumbnailUrl;
+                }
+
                 if (string.Equals(bannerType, "season", StringComparison.OrdinalIgnoreCase))
                 {
                     if (string.Equals(bannerType2, "season", StringComparison.OrdinalIgnoreCase))
@@ -307,7 +311,7 @@ namespace MediaBrowser.Providers.TV
 
         public int Priority
         {
-            get { return 0; }
+            get { return 1; }
         }
     }
 }

+ 312 - 0
MediaBrowser.Providers/TV/ManualTvdbSeriesImageProvider.cs

@@ -0,0 +1,312 @@
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+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.TV
+{
+    public class ManualTvdbSeriesImageProvider : IImageProvider
+    {
+        private readonly IServerConfigurationManager _config;
+        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+
+        public ManualTvdbSeriesImageProvider(IServerConfigurationManager config)
+        {
+            _config = config;
+        }
+
+        public string Name
+        {
+            get { return ProviderName; }
+        }
+
+        public static string ProviderName
+        {
+            get { return "TvDb"; }
+        }
+
+        public bool Supports(BaseItem item)
+        {
+            return item is Series;
+        }
+
+        public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken)
+        {
+            var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false);
+
+            return images.Where(i => i.Type == imageType);
+        }
+
+        public Task<IEnumerable<RemoteImageInfo>> GetAllImages(BaseItem item, CancellationToken cancellationToken)
+        {
+            var seriesId = item.GetProviderId(MetadataProviders.Tvdb);
+
+            if (!string.IsNullOrEmpty(seriesId))
+            {
+                // Process images
+                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
+
+                var path = Path.Combine(seriesDataPath, "banners.xml");
+
+                try
+                {
+                    var result = GetImages(path, cancellationToken);
+
+                    return Task.FromResult(result);
+                }
+                catch (FileNotFoundException)
+                {
+                    // No tvdb data yet. Don't blow up
+                }
+            }
+
+            return Task.FromResult<IEnumerable<RemoteImageInfo>>(new RemoteImageInfo[] { });
+        }
+
+        private IEnumerable<RemoteImageInfo> GetImages(string xmlPath, CancellationToken cancellationToken)
+        {
+            var settings = new XmlReaderSettings
+            {
+                CheckCharacters = false,
+                IgnoreProcessingInstructions = true,
+                IgnoreComments = true,
+                ValidationType = ValidationType.None
+            };
+
+            var list = new List<RemoteImageInfo>();
+
+            using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
+            {
+                // Use XmlReader for best performance
+                using (var reader = XmlReader.Create(streamReader, settings))
+                {
+                    reader.MoveToContent();
+
+                    // Loop through each element
+                    while (reader.Read())
+                    {
+                        cancellationToken.ThrowIfCancellationRequested();
+
+                        if (reader.NodeType == XmlNodeType.Element)
+                        {
+                            switch (reader.Name)
+                            {
+                                case "Banner":
+                                    {
+                                        using (var subtree = reader.ReadSubtree())
+                                        {
+                                            AddImage(subtree, list);
+                                        }
+                                        break;
+                                    }
+                                default:
+                                    reader.Skip();
+                                    break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            var language = _config.Configuration.PreferredMetadataLanguage;
+
+            var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase);
+
+            return list.OrderByDescending(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)
+                .ToList();
+        }
+
+        private void AddImage(XmlReader reader, List<RemoteImageInfo> images)
+        {
+            reader.MoveToContent();
+
+            string bannerType = null;
+            string url = null;
+            int? bannerSeason = null;
+            int? width = null;
+            int? height = null;
+            string language = null;
+            double? rating = null;
+            int? voteCount = null;
+            string thumbnailUrl = null;
+
+            while (reader.Read())
+            {
+                if (reader.NodeType == XmlNodeType.Element)
+                {
+                    switch (reader.Name)
+                    {
+                        case "Rating":
+                            {
+                                var val = reader.ReadElementContentAsString() ?? string.Empty;
+
+                                double rval;
+
+                                if (double.TryParse(val, NumberStyles.Any, _usCulture, out rval))
+                                {
+                                    rating = rval;
+                                }
+
+                                break;
+                            }
+
+                        case "RatingCount":
+                            {
+                                var val = reader.ReadElementContentAsString() ?? string.Empty;
+
+                                int rval;
+
+                                if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
+                                {
+                                    voteCount = rval;
+                                }
+
+                                break;
+                            }
+
+                        case "Language":
+                            {
+                                language = reader.ReadElementContentAsString() ?? string.Empty;
+                                break;
+                            }
+
+                        case "ThumbnailPath":
+                            {
+                                thumbnailUrl = reader.ReadElementContentAsString() ?? string.Empty;
+                                break;
+                            }
+
+                        case "BannerType":
+                            {
+                                bannerType = reader.ReadElementContentAsString() ?? string.Empty;
+
+                                break;
+                            }
+
+                        case "BannerPath":
+                            {
+                                url = reader.ReadElementContentAsString() ?? string.Empty;
+                                break;
+                            }
+
+                        case "BannerType2":
+                            {
+                                var bannerType2 = reader.ReadElementContentAsString() ?? string.Empty;
+
+                                // Sometimes the resolution is stuffed in here
+                                var resolutionParts = bannerType2.Split('x');
+
+                                if (resolutionParts.Length == 2)
+                                {
+                                    int rval;
+
+                                    if (int.TryParse(resolutionParts[0], NumberStyles.Integer, _usCulture, out rval))
+                                    {
+                                        width = rval;
+                                    }
+
+                                    if (int.TryParse(resolutionParts[1], NumberStyles.Integer, _usCulture, out rval))
+                                    {
+                                        height = rval;
+                                    }
+
+                                }
+
+                                break;
+                            }
+
+                        case "Season":
+                            {
+                                var val = reader.ReadElementContentAsString();
+
+                                if (!string.IsNullOrWhiteSpace(val))
+                                {
+                                    bannerSeason = int.Parse(val);
+                                }
+                                break;
+                            }
+
+
+                        default:
+                            reader.Skip();
+                            break;
+                    }
+                }
+            }
+
+            if (!string.IsNullOrEmpty(url) && !bannerSeason.HasValue)
+            {
+                var imageInfo = new RemoteImageInfo
+                {
+                    RatingType = RatingType.Score,
+                    CommunityRating = rating,
+                    VoteCount = voteCount,
+                    Url = TVUtils.BannerUrl + url,
+                    ProviderName = Name,
+                    Language = language,
+                    Width = width,
+                    Height = height
+                };
+
+                if (!string.IsNullOrEmpty(thumbnailUrl))
+                {
+                    imageInfo.ThumbnailUrl = TVUtils.BannerUrl + thumbnailUrl;
+                }
+
+                if (string.Equals(bannerType, "poster", StringComparison.OrdinalIgnoreCase))
+                {
+                    imageInfo.Type = ImageType.Primary;
+                    images.Add(imageInfo);
+                }
+                else if (string.Equals(bannerType, "series", StringComparison.OrdinalIgnoreCase))
+                {
+                    imageInfo.Type = ImageType.Banner;
+                    images.Add(imageInfo);
+                }
+                else if (string.Equals(bannerType, "fanart", StringComparison.OrdinalIgnoreCase))
+                {
+                    imageInfo.Type = ImageType.Backdrop;
+                    images.Add(imageInfo);
+                }
+            }
+
+        }
+
+        public int Priority
+        {
+            get { return 1; }
+        }
+    }
+}

+ 1 - 1
MediaBrowser.Providers/TV/SeriesPostScanTask.cs

@@ -111,7 +111,7 @@ namespace MediaBrowser.Providers.TV
                 return;
             }
 
-            var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId);
+            var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId);
 
             var episodeFiles = Directory.EnumerateFiles(seriesDataPath, "*.xml", SearchOption.TopDirectoryOnly)
                 .Select(Path.GetFileNameWithoutExtension)

+ 7 - 7
MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs → MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs

@@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.TV
     /// <summary>
     /// Class RemoteEpisodeProvider
     /// </summary>
-    class RemoteEpisodeProvider : BaseMetadataProvider
+    class TvdbEpisodeProvider : BaseMetadataProvider
     {
         /// <summary>
         /// The _provider manager
@@ -39,16 +39,16 @@ namespace MediaBrowser.Providers.TV
         protected IHttpClient HttpClient { get; private set; }
         private readonly IFileSystem _fileSystem;
 
-        internal static RemoteEpisodeProvider Current;
+        internal static TvdbEpisodeProvider Current;
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="RemoteEpisodeProvider" /> class.
+        /// Initializes a new instance of the <see cref="TvdbEpisodeProvider" /> class.
         /// </summary>
         /// <param name="httpClient">The HTTP client.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
-        public RemoteEpisodeProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
+        public TvdbEpisodeProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             HttpClient = httpClient;
@@ -149,7 +149,7 @@ namespace MediaBrowser.Providers.TV
             if (!string.IsNullOrEmpty(seriesId))
             {
                 // Process images
-                var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
+                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
 
                 var files = GetEpisodeXmlFiles(episode, seriesDataPath);
 
@@ -254,7 +254,7 @@ namespace MediaBrowser.Providers.TV
 
             if (!string.IsNullOrEmpty(seriesId))
             {
-                var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
+                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
 
                 try
                 {
@@ -438,7 +438,7 @@ namespace MediaBrowser.Providers.TV
                                                 {
                                                     var url = TVUtils.BannerUrl + val;
 
-                                                    await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken).ConfigureAwait(false);
+                                                    await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken).ConfigureAwait(false);
                                                 }
                                                 catch (HttpException)
                                                 {

+ 2 - 2
MediaBrowser.Providers/TV/TvdbPersonImageProvider.cs

@@ -107,7 +107,7 @@ namespace MediaBrowser.Providers.TV
         /// <returns>Task.</returns>
         private async Task DownloadImageFromSeries(BaseItem item, Series series, CancellationToken cancellationToken)
         {
-            var tvdbPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, series.GetProviderId(MetadataProviders.Tvdb));
+            var tvdbPath = TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, series.GetProviderId(MetadataProviders.Tvdb));
 
             var actorXmlPath = Path.Combine(tvdbPath, "actors.xml");
 
@@ -117,7 +117,7 @@ namespace MediaBrowser.Providers.TV
             {
                 url = TVUtils.BannerUrl + url;
 
-                await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool,
+                await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool,
                                                ImageType.Primary, null, cancellationToken).ConfigureAwait(false);
             }
         }

+ 4 - 4
MediaBrowser.Providers/TV/TvdbPrescanTask.cs

@@ -77,7 +77,7 @@ namespace MediaBrowser.Providers.TV
                 return;
             }
 
-            var path = RemoteSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
+            var path = TvdbSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);
 
             Directory.CreateDirectory(path);
 
@@ -107,7 +107,7 @@ namespace MediaBrowser.Providers.TV
                     Url = ServerTimeUrl,
                     CancellationToken = cancellationToken,
                     EnableHttpCompression = true,
-                    ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool
+                    ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool
 
                 }).ConfigureAwait(false))
                 {
@@ -195,7 +195,7 @@ namespace MediaBrowser.Providers.TV
                 Url = string.Format(UpdatesUrl, lastUpdateTime),
                 CancellationToken = cancellationToken,
                 EnableHttpCompression = true,
-                ResourcePool = RemoteSeriesProvider.Current.TvDbResourcePool
+                ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool
 
             }).ConfigureAwait(false))
             {
@@ -315,7 +315,7 @@ namespace MediaBrowser.Providers.TV
 
             Directory.CreateDirectory(seriesDataPath);
 
-            return RemoteSeriesProvider.Current.DownloadSeriesZip(id, seriesDataPath, lastTvDbUpdateTime, cancellationToken);
+            return TvdbSeriesProvider.Current.DownloadSeriesZip(id, seriesDataPath, lastTvDbUpdateTime, cancellationToken);
         }
     }
 }

+ 8 - 8
MediaBrowser.Providers/TV/RemoteSeasonProvider.cs → MediaBrowser.Providers/TV/TvdbSeasonProvider.cs

@@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.TV
     /// <summary>
     /// Class RemoteSeasonProvider
     /// </summary>
-    class RemoteSeasonProvider : BaseMetadataProvider
+    class TvdbSeasonProvider : BaseMetadataProvider
     {
         /// <summary>
         /// The _provider manager
@@ -28,13 +28,13 @@ namespace MediaBrowser.Providers.TV
         private readonly IFileSystem _fileSystem;
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="RemoteSeasonProvider"/> class.
+        /// Initializes a new instance of the <see cref="TvdbSeasonProvider"/> class.
         /// </summary>
         /// <param name="logManager">The log manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
         /// <exception cref="System.ArgumentNullException">httpClient</exception>
-        public RemoteSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
+        public TvdbSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             _providerManager = providerManager;
@@ -113,7 +113,7 @@ namespace MediaBrowser.Providers.TV
             if (!string.IsNullOrEmpty(seriesId))
             {
                 // Process images
-                var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
+                var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
 
                 var imagesFileInfo = new FileInfo(imagesXmlPath);
 
@@ -145,7 +145,7 @@ namespace MediaBrowser.Providers.TV
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualFanartSeriesImageProvider.ProviderName).ConfigureAwait(false);
+            var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualTvdbSeasonImageProvider.ProviderName).ConfigureAwait(false);
 
             const int backdropLimit = 1;
 
@@ -163,7 +163,7 @@ namespace MediaBrowser.Providers.TV
 
                 if (image != null)
                 {
-                    await _providerManager.SaveImage(item, image.Url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken)
+                    await _providerManager.SaveImage(item, image.Url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken)
                       .ConfigureAwait(false);
                 }
             }
@@ -174,7 +174,7 @@ namespace MediaBrowser.Providers.TV
 
                 if (image != null)
                 {
-                    await _providerManager.SaveImage(item, image.Url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken)
+                    await _providerManager.SaveImage(item, image.Url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken)
                       .ConfigureAwait(false);
                 }
             }
@@ -192,7 +192,7 @@ namespace MediaBrowser.Providers.TV
                         continue;
                     }
 
-                    await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken).ConfigureAwait(false);
+                    await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken).ConfigureAwait(false);
 
                     bdNo++;
 

+ 21 - 225
MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs

@@ -3,20 +3,17 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Providers;
 using System;
 using System.Collections.Generic;
-using System.Globalization;
 using System.IO;
 using System.Linq;
-using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
-using System.Xml;
 
 namespace MediaBrowser.Providers.TV
 {
@@ -125,7 +122,7 @@ namespace MediaBrowser.Providers.TV
             if (!string.IsNullOrEmpty(seriesId))
             {
                 // Process images
-                var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
+                var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
 
                 var imagesFileInfo = new FileInfo(imagesXmlPath);
 
@@ -158,64 +155,36 @@ namespace MediaBrowser.Providers.TV
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            var series = (Series)item;
-            var seriesId = series.GetProviderId(MetadataProviders.Tvdb);
+            var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualTvdbSeriesImageProvider.ProviderName).ConfigureAwait(false);
 
-            if (!string.IsNullOrEmpty(seriesId))
-            {
-                // Process images
-                var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);
-
-                var imagesXmlPath = Path.Combine(seriesDataPath, "banners.xml");
-
-                var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
-
-                if (!series.HasImage(ImageType.Primary) || !series.HasImage(ImageType.Banner) || series.BackdropImagePaths.Count < backdropLimit)
-                {
-                    Directory.CreateDirectory(seriesDataPath);
-                    
-                    try
-                    {
-                        var fanartData = FetchFanartXmlData(imagesXmlPath, backdropLimit, cancellationToken);
-                        await DownloadImages(item, fanartData, backdropLimit, cancellationToken).ConfigureAwait(false);
-                    }
-                    catch (FileNotFoundException)
-                    {
-                        // No biggie. Not all series have images
-                    }
-                }
+            const int backdropLimit = 1;
 
-                SetLastRefreshed(item, DateTime.UtcNow);
-                return true;
-            }
+            await DownloadImages(item, images.ToList(), backdropLimit, cancellationToken).ConfigureAwait(false);
 
-            return false;
+            SetLastRefreshed(item, DateTime.UtcNow);
+            return true;
         }
 
-        protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
-        private async Task DownloadImages(BaseItem item, FanartXmlData data, int backdropLimit, CancellationToken cancellationToken)
+        private async Task DownloadImages(BaseItem item, List<RemoteImageInfo> images, int backdropLimit, CancellationToken cancellationToken)
         {
             if (!item.HasImage(ImageType.Primary))
             {
-                var url = data.LanguagePoster ?? data.Poster;
-                if (!string.IsNullOrEmpty(url))
-                {
-                    url = TVUtils.BannerUrl + url;
+                var image = images.FirstOrDefault(i => i.Type == ImageType.Primary);
 
-                    await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken)
+                if (image != null)
+                {
+                    await _providerManager.SaveImage(item, image.Url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken)
                       .ConfigureAwait(false);
                 }
             }
 
             if (ConfigurationManager.Configuration.DownloadSeriesImages.Banner && !item.HasImage(ImageType.Banner))
             {
-                var url = data.LanguageBanner ?? data.Banner;
-                if (!string.IsNullOrEmpty(url))
-                {
-                    url = TVUtils.BannerUrl + url;
+                var image = images.FirstOrDefault(i => i.Type == ImageType.Banner);
 
-                    await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken)
+                if (image != null)
+                {
+                    await _providerManager.SaveImage(item, image.Url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken)
                       .ConfigureAwait(false);
                 }
             }
@@ -224,38 +193,18 @@ namespace MediaBrowser.Providers.TV
             {
                 var bdNo = item.BackdropImagePaths.Count;
 
-                var eligibleBackdrops = data.Backdrops
-                    .Where(i =>
-                    {
-                        if (string.IsNullOrEmpty(i.Resolution))
-                        {
-                            return true;
-                        }
-
-                        var parts = i.Resolution.Split('x');
-
-                        int width;
-
-                        if (int.TryParse(parts[0], NumberStyles.Any, UsCulture, out width))
-                        {
-                            return width >= ConfigurationManager.Configuration.MinSeriesBackdropDownloadWidth;
-                        }
-
-                        return true;
-                    })
-                    .ToList();
-
-                foreach (var backdrop in eligibleBackdrops)
+                foreach (var backdrop in images.Where(i => i.Type == ImageType.Backdrop && 
+                    (!i.Width.HasValue || 
+                    i.Width.Value >= ConfigurationManager.Configuration.MinSeriesBackdropDownloadWidth)))
                 {
-                    var url = TVUtils.BannerUrl + backdrop.Url;
+                    var url = backdrop.Url;
 
                     if (item.ContainsImageWithSourceUrl(url))
                     {
                         continue;
                     }
 
-                    await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken)
-                      .ConfigureAwait(false);
+                    await _providerManager.SaveImage(item, url, TvdbSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken).ConfigureAwait(false);
 
                     bdNo++;
 
@@ -263,158 +212,5 @@ namespace MediaBrowser.Providers.TV
                 }
             }
         }
-
-        private FanartXmlData FetchFanartXmlData(string bannersXmlPath, int backdropLimit, CancellationToken cancellationToken)
-        {
-            var settings = new XmlReaderSettings
-            {
-                CheckCharacters = false,
-                IgnoreProcessingInstructions = true,
-                IgnoreComments = true,
-                ValidationType = ValidationType.None
-            };
-
-            var data = new FanartXmlData();
-
-            using (var streamReader = new StreamReader(bannersXmlPath, Encoding.UTF8))
-            {
-                // Use XmlReader for best performance
-                using (var reader = XmlReader.Create(streamReader, settings))
-                {
-                    reader.MoveToContent();
-
-                    // Loop through each element
-                    while (reader.Read())
-                    {
-                        cancellationToken.ThrowIfCancellationRequested();
-
-                        if (reader.NodeType == XmlNodeType.Element)
-                        {
-                            switch (reader.Name)
-                            {
-                                case "Banner":
-                                    {
-                                        using (var subtree = reader.ReadSubtree())
-                                        {
-                                            FetchInfoFromBannerNode(data, subtree, backdropLimit);
-                                        }
-                                        break;
-                                    }
-                                default:
-                                    reader.Skip();
-                                    break;
-                            }
-                        }
-                    }
-                }
-            }
-
-            return data;
-        }
-
-        private void FetchInfoFromBannerNode(FanartXmlData data, XmlReader reader, int backdropLimit)
-        {
-            reader.MoveToContent();
-
-            string type = null;
-            string url = null;
-            string resolution = null;
-
-            while (reader.Read())
-            {
-                if (reader.NodeType == XmlNodeType.Element)
-                {
-                    switch (reader.Name)
-                    {
-                        case "BannerType":
-                            {
-                                type = reader.ReadElementContentAsString() ?? string.Empty;
-
-                                if (string.Equals(type, "poster", StringComparison.OrdinalIgnoreCase))
-                                {
-                                    // Already got it
-                                    if (!string.IsNullOrEmpty(data.Poster))
-                                    {
-                                        return;
-                                    }
-                                }
-                                else if (string.Equals(type, "series", StringComparison.OrdinalIgnoreCase))
-                                {
-                                    // Already got it
-                                    if (!string.IsNullOrEmpty(data.Banner))
-                                    {
-                                        return;
-                                    }
-                                }
-                                else
-                                {
-                                    return;
-                                }
-
-                                break;
-                            }
-
-                        case "BannerPath":
-                            {
-                                url = reader.ReadElementContentAsString() ?? string.Empty;
-                                break;
-                            }
-
-                        case "BannerType2":
-                            {
-                                resolution = reader.ReadElementContentAsString() ?? string.Empty;
-                                break;
-                            }
-
-                        default:
-                            reader.Skip();
-                            break;
-                    }
-                }
-            }
-
-            if (!string.IsNullOrEmpty(url))
-            {
-                if (string.Equals(type, "poster", StringComparison.OrdinalIgnoreCase))
-                {
-                    // Just grab the first
-                    if (string.IsNullOrWhiteSpace(data.Poster))
-                    {
-                        data.Poster = url;
-                    }
-                }
-                else if (string.Equals(type, "series", StringComparison.OrdinalIgnoreCase))
-                {
-                    // Just grab the first
-                    if (string.IsNullOrWhiteSpace(data.Banner))
-                    {
-                        data.Banner = url;
-                    }
-                }
-                else if (string.Equals(type, "fanart", StringComparison.OrdinalIgnoreCase))
-                {
-                    data.Backdrops.Add(new ImageInfo
-                    {
-                        Url = url,
-                        Resolution = resolution
-                    });
-                }
-            }
-        }
-    }
-
-    internal class FanartXmlData
-    {
-        public string LanguagePoster { get; set; }
-        public string LanguageBanner { get; set; }
-        public string Poster { get; set; }
-        public string Banner { get; set; }
-        public List<ImageInfo> Backdrops = new List<ImageInfo>();
-    }
-
-    internal class ImageInfo
-    {
-        public string Url { get; set; }
-        public string Resolution { get; set; }
     }
 }

+ 4 - 4
MediaBrowser.Providers/TV/RemoteSeriesProvider.cs → MediaBrowser.Providers/TV/TvdbSeriesProvider.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.TV
     /// <summary>
     /// Class RemoteSeriesProvider
     /// </summary>
-    class RemoteSeriesProvider : BaseMetadataProvider, IDisposable
+    class TvdbSeriesProvider : BaseMetadataProvider, IDisposable
     {
         /// <summary>
         /// The tv db
@@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.TV
         /// Gets the current.
         /// </summary>
         /// <value>The current.</value>
-        internal static RemoteSeriesProvider Current { get; private set; }
+        internal static TvdbSeriesProvider Current { get; private set; }
 
         /// <summary>
         /// The _zip client
@@ -53,14 +53,14 @@ namespace MediaBrowser.Providers.TV
         private readonly IFileSystem _fileSystem;
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="RemoteSeriesProvider" /> class.
+        /// Initializes a new instance of the <see cref="TvdbSeriesProvider" /> class.
         /// </summary>
         /// <param name="httpClient">The HTTP client.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="zipClient">The zip client.</param>
         /// <exception cref="System.ArgumentNullException">httpClient</exception>
-        public RemoteSeriesProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IZipClient zipClient, IFileSystem fileSystem)
+        public TvdbSeriesProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IZipClient zipClient, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             if (httpClient == null)