From 142d0e5f48fcbd6d93896ba59b4363fd6b112b4c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 1 Nov 2013 11:55:25 -0400 Subject: [PATCH] fixes #607 - Add manual image selection for episodes --- .../MediaBrowser.Providers.csproj | 1 + .../Movies/FanArtMovieProvider.cs | 139 ++++++--------- .../Movies/FanArtMovieUpdatesPrescanTask.cs | 19 +- .../Movies/ManualFanartMovieImageProvider.cs | 6 + .../Movies/ManualMovieDbImageProvider.cs | 11 +- .../Movies/MovieDbImagesProvider.cs | 23 +-- .../Movies/MovieDbProvider.cs | 37 ++-- .../TV/ManualTvdbEpisodeImageProvider.cs | 166 ++++++++++++++++++ .../TV/RemoteEpisodeProvider.cs | 5 +- 9 files changed, 269 insertions(+), 138 deletions(-) create mode 100644 MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index e944787c6..6d0ab05f8 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -110,6 +110,7 @@ + diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs index 355d3df0d..30fb8c659 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs @@ -8,13 +8,13 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Providers; using System; -using System.Globalization; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using System.Xml; namespace MediaBrowser.Providers.Movies { @@ -193,18 +193,19 @@ namespace MediaBrowser.Providers.Movies if (!string.IsNullOrEmpty(movieId)) { - var movieDataPath = GetMovieDataPath(ConfigurationManager.ApplicationPaths, movieId); - var xmlPath = Path.Combine(movieDataPath, "fanart.xml"); + var xmlPath = GetFanartXmlPath(movieId); // Only download the xml if it doesn't already exist. The prescan task will take care of getting updates if (!File.Exists(xmlPath)) { - await DownloadMovieXml(movieDataPath, movieId, cancellationToken).ConfigureAwait(false); + await DownloadMovieXml(movieId, cancellationToken).ConfigureAwait(false); } if (File.Exists(xmlPath)) { - await FetchFromXml(item, xmlPath, cancellationToken).ConfigureAwait(false); + var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualFanartMovieImageProvider.ProviderName).ConfigureAwait(false); + + await FetchImages(item, images.ToList(), cancellationToken).ConfigureAwait(false); } } @@ -221,19 +222,18 @@ namespace MediaBrowser.Providers.Movies /// /// Downloads the movie XML. /// - /// The movie data path. /// The TMDB id. /// The cancellation token. /// Task. - internal async Task DownloadMovieXml(string movieDataPath, string tmdbId, CancellationToken cancellationToken) + internal async Task DownloadMovieXml(string tmdbId, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - string url = string.Format(FanArtBaseUrl, ApiKey, tmdbId); + var url = string.Format(FanArtBaseUrl, ApiKey, tmdbId); - var xmlPath = Path.Combine(movieDataPath, "fanart.xml"); + var xmlPath = GetFanartXmlPath(tmdbId); - Directory.CreateDirectory(movieDataPath); + Directory.CreateDirectory(Path.GetDirectoryName(xmlPath)); using (var response = await HttpClient.Get(new HttpRequestOptions { @@ -250,82 +250,53 @@ namespace MediaBrowser.Providers.Movies } } - /// - /// Fetches from XML. - /// - /// The item. - /// The XML file path. - /// The cancellation token. - /// Task. - private async Task FetchFromXml(BaseItem item, string xmlFilePath, CancellationToken cancellationToken) + private async Task FetchImages(BaseItem item, List images, CancellationToken cancellationToken) { - var doc = new XmlDocument(); - doc.Load(xmlFilePath); - - var language = ConfigurationManager.Configuration.PreferredMetadataLanguage.ToLower(); - cancellationToken.ThrowIfCancellationRequested(); - string path; - if (ConfigurationManager.Configuration.DownloadMovieImages.Primary && !item.HasImage(ImageType.Primary)) { - var node = doc.SelectSingleNode("//fanart/movie/movieposters/movieposter[@lang = \"" + language + "\"]/@url") ?? - doc.SelectSingleNode("//fanart/movie/movieposters/movieposter/@url"); - path = node != null ? node.Value : null; - if (!string.IsNullOrEmpty(path)) + var image = images.FirstOrDefault(i => i.Type == ImageType.Primary); + + if (image != null) { - await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Primary, null, cancellationToken) - .ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Primary, null, cancellationToken).ConfigureAwait(false); } } cancellationToken.ThrowIfCancellationRequested(); - + if (ConfigurationManager.Configuration.DownloadMovieImages.Logo && !item.HasImage(ImageType.Logo)) { - var node = - doc.SelectSingleNode("//fanart/movie/hdmovielogos/hdmovielogo[@lang = \"" + language + "\"]/@url") ?? - doc.SelectSingleNode("//fanart/movie/movielogos/movielogo[@lang = \"" + language + "\"]/@url"); - if (node == null && language != "en") + var image = images.FirstOrDefault(i => i.Type == ImageType.Logo); + + if (image != null) { - //maybe just couldn't find language - try just first one - node = doc.SelectSingleNode("//fanart/movie/hdmovielogos/hdmovielogo/@url") ?? - doc.SelectSingleNode("//fanart/movie/movielogos/movielogo/@url"); - } - path = node != null ? node.Value : null; - if (!string.IsNullOrEmpty(path)) - { - await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Logo, null, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Logo, null, cancellationToken).ConfigureAwait(false); } } + cancellationToken.ThrowIfCancellationRequested(); if (ConfigurationManager.Configuration.DownloadMovieImages.Art && !item.HasImage(ImageType.Art)) { - var node = - doc.SelectSingleNode("//fanart/movie/hdmoviecleararts/hdmovieclearart[@lang = \"" + language + "\"]/@url") ?? - doc.SelectSingleNode("//fanart/movie/hdmoviecleararts/hdmovieclearart/@url") ?? - doc.SelectSingleNode("//fanart/movie/moviearts/movieart[@lang = \"" + language + "\"]/@url") ?? - doc.SelectSingleNode("//fanart/movie/moviearts/movieart/@url"); - path = node != null ? node.Value : null; - if (!string.IsNullOrEmpty(path)) + var image = images.FirstOrDefault(i => i.Type == ImageType.Art); + + if (image != null) { - await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Art, null, cancellationToken) - .ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Art, null, cancellationToken).ConfigureAwait(false); } } + cancellationToken.ThrowIfCancellationRequested(); if (ConfigurationManager.Configuration.DownloadMovieImages.Disc && !item.HasImage(ImageType.Disc)) { - var node = doc.SelectSingleNode("//fanart/movie/moviediscs/moviedisc[@lang = \"" + language + "\"]/@url") ?? - doc.SelectSingleNode("//fanart/movie/moviediscs/moviedisc/@url"); - path = node != null ? node.Value : null; - if (!string.IsNullOrEmpty(path)) + var image = images.FirstOrDefault(i => i.Type == ImageType.Disc); + + if (image != null) { - await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Disc, null, cancellationToken) - .ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Disc, null, cancellationToken).ConfigureAwait(false); } } @@ -333,13 +304,11 @@ namespace MediaBrowser.Providers.Movies if (ConfigurationManager.Configuration.DownloadMovieImages.Banner && !item.HasImage(ImageType.Banner)) { - var node = doc.SelectSingleNode("//fanart/movie/moviebanners/moviebanner[@lang = \"" + language + "\"]/@url") ?? - doc.SelectSingleNode("//fanart/movie/moviebanners/moviebanner/@url"); - path = node != null ? node.Value : null; - if (!string.IsNullOrEmpty(path)) + var image = images.FirstOrDefault(i => i.Type == ImageType.Banner); + + if (image != null) { - await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Banner, null, cancellationToken) - .ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Banner, null, cancellationToken).ConfigureAwait(false); } } @@ -347,40 +316,30 @@ namespace MediaBrowser.Providers.Movies if (ConfigurationManager.Configuration.DownloadMovieImages.Thumb && !item.HasImage(ImageType.Thumb)) { - var node = doc.SelectSingleNode("//fanart/movie/moviethumbs/moviethumb[@lang = \"" + language + "\"]/@url") ?? - doc.SelectSingleNode("//fanart/movie/moviethumbs/moviethumb/@url"); - path = node != null ? node.Value : null; - if (!string.IsNullOrEmpty(path)) + var image = images.FirstOrDefault(i => i.Type == ImageType.Thumb); + + if (image != null) { - await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Thumb, null, cancellationToken) - .ConfigureAwait(false); + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Thumb, null, cancellationToken).ConfigureAwait(false); } } + cancellationToken.ThrowIfCancellationRequested(); + var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops; - if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && item.BackdropImagePaths.Count < backdropLimit) + if (ConfigurationManager.Configuration.DownloadMovieImages.Backdrops && + item.BackdropImagePaths.Count < backdropLimit) { - var nodes = doc.SelectNodes("//fanart/movie/moviebackgrounds//@url"); + var numBackdrops = item.BackdropImagePaths.Count; - if (nodes != null) + foreach (var image in images.Where(i => i.Type == ImageType.Backdrop)) { - var numBackdrops = item.BackdropImagePaths.Count; + await _providerManager.SaveImage(item, image.Url, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) + .ConfigureAwait(false); - foreach (XmlNode node in nodes) - { - path = node.Value; - - if (!string.IsNullOrEmpty(path) && !item.ContainsImageWithSourceUrl(path)) - { - await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) - .ConfigureAwait(false); - - numBackdrops++; - - if (item.BackdropImagePaths.Count >= backdropLimit) break; - } - } + numBackdrops++; + if (item.BackdropImagePaths.Count >= backdropLimit) break; } } } diff --git a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs index 706dffa7e..cc2293968 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs @@ -86,7 +86,7 @@ namespace MediaBrowser.Providers.Movies progress.Report(5); - await UpdateMovies(moviesToUpdate, path, progress, cancellationToken).ConfigureAwait(false); + await UpdateMovies(moviesToUpdate, progress, cancellationToken).ConfigureAwait(false); } var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture); @@ -127,14 +127,16 @@ namespace MediaBrowser.Providers.Movies } } - private async Task UpdateMovies(IEnumerable idList, string moviesDataPath, IProgress progress, CancellationToken cancellationToken) + private async Task UpdateMovies(IEnumerable idList, IProgress progress, CancellationToken cancellationToken) { var list = idList.ToList(); var numComplete = 0; foreach (var id in list) { - await UpdateMovie(id, moviesDataPath, cancellationToken).ConfigureAwait(false); + _logger.Info("Updating movie " + id); + + await FanArtMovieProvider.Current.DownloadMovieXml(id, cancellationToken).ConfigureAwait(false); numComplete++; double percent = numComplete; @@ -145,17 +147,6 @@ namespace MediaBrowser.Providers.Movies } } - private Task UpdateMovie(string tmdbId, string movieDataPath, CancellationToken cancellationToken) - { - _logger.Info("Updating movie " + tmdbId); - - movieDataPath = Path.Combine(movieDataPath, tmdbId); - - Directory.CreateDirectory(movieDataPath); - - return FanArtMovieProvider.Current.DownloadMovieXml(movieDataPath, tmdbId, cancellationToken); - } - /// /// Dates the time to unix timestamp. /// diff --git a/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs index 85dd13936..64843de99 100644 --- a/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/ManualFanartMovieImageProvider.cs @@ -27,6 +27,11 @@ namespace MediaBrowser.Providers.Movies } public string Name + { + get { return ProviderName; } + } + + public static string ProviderName { get { return "FanArt"; } } @@ -67,6 +72,7 @@ namespace MediaBrowser.Providers.Movies 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 => { diff --git a/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs index c02c60f75..4ae15e91f 100644 --- a/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs +++ b/MediaBrowser.Providers/Movies/ManualMovieDbImageProvider.cs @@ -26,6 +26,11 @@ namespace MediaBrowser.Providers.Movies } public string Name + { + get { return ProviderName; } + } + + public static string ProviderName { get { return "TheMovieDb"; } } @@ -99,7 +104,7 @@ namespace MediaBrowser.Providers.Movies var eligiblePosters = images.posters == null ? new List() : - images.posters.Where(i => i.width >= _config.Configuration.MinMoviePosterWidth) + images.posters .ToList(); return eligiblePosters.OrderByDescending(i => @@ -135,7 +140,7 @@ namespace MediaBrowser.Providers.Movies private IEnumerable GetBackdrops(MovieDbProvider.Images images, BaseItem item) { var eligibleBackdrops = images.backdrops == null ? new List() : - images.backdrops.Where(i => i.width >= _config.Configuration.MinMovieBackdropWidth) + images.backdrops .ToList(); return eligibleBackdrops.OrderByDescending(i => i.vote_average).ThenByDescending(i => i.vote_count); @@ -149,7 +154,7 @@ namespace MediaBrowser.Providers.Movies /// Task{MovieImages}. private MovieDbProvider.Images FetchImages(BaseItem item, IJsonSerializer jsonSerializer) { - var path = MovieDbProvider.Current.GetDataFilePath(item, "default"); + var path = MovieDbProvider.Current.GetImagesDataFilePath(item); if (!string.IsNullOrEmpty(path)) { diff --git a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs index e34cbc54f..6c503ad3a 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs @@ -8,7 +8,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; using System; using System.Collections.Generic; using System.IO; @@ -28,10 +27,6 @@ namespace MediaBrowser.Providers.Movies /// private readonly IProviderManager _providerManager; - /// - /// The _json serializer - /// - private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; /// @@ -40,12 +35,10 @@ namespace MediaBrowser.Providers.Movies /// The log manager. /// The configuration manager. /// The provider manager. - /// The json serializer. - public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem) + public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem) : base(logManager, configurationManager) { _providerManager = providerManager; - _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; } @@ -149,12 +142,7 @@ namespace MediaBrowser.Providers.Movies protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) { - if (string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tmdb))) - { - return false; - } - - var path = MovieDbProvider.Current.GetDataFilePath(item, "default"); + var path = MovieDbProvider.Current.GetImagesDataFilePath(item); if (!string.IsNullOrEmpty(path)) { @@ -182,8 +170,7 @@ namespace MediaBrowser.Providers.Movies if (!string.IsNullOrEmpty(id)) { - var images = await new ManualMovieDbImageProvider(_jsonSerializer, ConfigurationManager).GetAllImages(item, - cancellationToken).ConfigureAwait(false); + var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualMovieDbImageProvider.ProviderName).ConfigureAwait(false); await ProcessImages(item, images.ToList(), cancellationToken).ConfigureAwait(false); } @@ -204,7 +191,7 @@ namespace MediaBrowser.Providers.Movies cancellationToken.ThrowIfCancellationRequested(); var eligiblePosters = images - .Where(i => i.Type == ImageType.Primary) + .Where(i => i.Type == ImageType.Primary && i.Width.HasValue && i.Width.Value >= ConfigurationManager.Configuration.MinMoviePosterWidth) .ToList(); // poster @@ -228,7 +215,7 @@ namespace MediaBrowser.Providers.Movies cancellationToken.ThrowIfCancellationRequested(); var eligibleBackdrops = images - .Where(i => i.Type == ImageType.Backdrop) + .Where(i => i.Type == ImageType.Backdrop && i.Width.HasValue && i.Width.Value >= ConfigurationManager.Configuration.MinMovieBackdropWidth) .ToList(); var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops; diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 50adda6bb..67cec7498 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -209,17 +209,17 @@ namespace MediaBrowser.Providers.Movies protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo) { - var language = ConfigurationManager.Configuration.PreferredMetadataLanguage; - - var path = GetDataFilePath(item, language); + var path = GetDataFilePath(item); if (!string.IsNullOrEmpty(path)) { - var fileInfo = new FileInfo(path); - var defaultFileInfo = new FileInfo(Path.Combine(Path.GetDirectoryName(path), "default.json")); + var imagesFilePath = GetImagesDataFilePath(item); - return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed || - !defaultFileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(defaultFileInfo) > providerInfo.LastRefreshed; + var fileInfo = new FileInfo(path); + var imagesFileInfo = new FileInfo(imagesFilePath); + + return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed || + !imagesFileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(imagesFileInfo) > providerInfo.LastRefreshed; } return true; @@ -505,9 +505,9 @@ namespace MediaBrowser.Providers.Movies var language = ConfigurationManager.Configuration.PreferredMetadataLanguage; - var dataFilePath = GetDataFilePath(item, language); + var dataFilePath = GetDataFilePath(item); - if (string.IsNullOrEmpty(dataFilePath) || !File.Exists(dataFilePath) || !File.Exists(Path.Combine(Path.GetDirectoryName(dataFilePath), "default.json"))) + if (string.IsNullOrEmpty(dataFilePath) || !File.Exists(dataFilePath) || !File.Exists(GetImagesDataFilePath(item))) { var isBoxSet = item is BoxSet; @@ -535,7 +535,7 @@ namespace MediaBrowser.Providers.Movies if (isForcedRefresh || ConfigurationManager.Configuration.EnableTmdbUpdates || !HasAltMeta(item)) { - dataFilePath = GetDataFilePath(item, language); + dataFilePath = GetDataFilePath(item); var mainResult = JsonSerializer.DeserializeFromFile(dataFilePath); @@ -577,10 +577,11 @@ namespace MediaBrowser.Providers.Movies /// Gets the data file path. /// /// The item. - /// The language. /// System.String. - internal string GetDataFilePath(BaseItem item, string language) + internal string GetDataFilePath(BaseItem item) { + var language = ConfigurationManager.Configuration.PreferredMetadataLanguage; + var id = item.GetProviderId(MetadataProviders.Tmdb); if (string.IsNullOrEmpty(id)) @@ -595,6 +596,18 @@ namespace MediaBrowser.Providers.Movies return path; } + internal string GetImagesDataFilePath(BaseItem item) + { + var path = GetDataFilePath(item); + + if (!string.IsNullOrEmpty(path)) + { + path = Path.Combine(Path.GetDirectoryName(path), "default.json"); + } + + return path; + } + /// /// Fetches the main result. /// diff --git a/MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs new file mode 100644 index 000000000..3d56b3c71 --- /dev/null +++ b/MediaBrowser.Providers/TV/ManualTvdbEpisodeImageProvider.cs @@ -0,0 +1,166 @@ +using System.Globalization; +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.Providers; +using System.Collections.Generic; +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 ManualTvdbEpisodeImageProvider : IImageProvider + { + private readonly IServerConfigurationManager _config; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + public ManualTvdbEpisodeImageProvider(IServerConfigurationManager config) + { + _config = config; + } + + public string Name + { + get { return "TvDb"; } + } + + public bool Supports(BaseItem item) + { + return item is Episode; + } + + public Task> GetImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken) + { + return GetAllImages(item, cancellationToken); + } + + public Task> GetAllImages(BaseItem item, CancellationToken cancellationToken) + { + var episode = (Episode)item; + + var seriesId = episode.Series != null ? episode.Series.GetProviderId(MetadataProviders.Tvdb) : null; + + if (!string.IsNullOrEmpty(seriesId)) + { + // Process images + var seriesDataPath = RemoteSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId); + + var files = RemoteEpisodeProvider.Current.GetEpisodeXmlFiles(episode, seriesDataPath); + + var result = files.Select(i => GetImageInfo(i, cancellationToken)).Where(i => i != null); + + return Task.FromResult(result); + } + + return Task.FromResult>(new RemoteImageInfo[] { }); + } + + private RemoteImageInfo GetImageInfo(FileInfo xmlFile, CancellationToken cancellationToken) + { + var height = 225; + var width = 400; + var url = string.Empty; + + using (var streamReader = new StreamReader(xmlFile.FullName, 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 "thumb_width": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + int rval; + + // int.TryParse is local aware, so it can be probamatic, force us culture + if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval)) + { + width = rval; + } + } + break; + } + + case "thumb_height": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + int rval; + + // int.TryParse is local aware, so it can be probamatic, force us culture + if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval)) + { + height = rval; + } + } + break; + } + + case "filename": + { + var val = reader.ReadElementContentAsString(); + if (!string.IsNullOrWhiteSpace(val)) + { + url = TVUtils.BannerUrl + val; + } + break; + } + + default: + reader.Skip(); + break; + } + } + } + } + } + + if (string.IsNullOrEmpty(url)) + { + return null; + } + + return new RemoteImageInfo + { + Width = width, + Height = height, + ProviderName = Name, + Url = url, + Type = ImageType.Primary + }; + } + + public int Priority + { + get { return 0; } + } + } +} diff --git a/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs b/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs index cc6bca0b3..63b755bf9 100644 --- a/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs @@ -39,6 +39,8 @@ namespace MediaBrowser.Providers.TV protected IHttpClient HttpClient { get; private set; } private readonly IFileSystem _fileSystem; + internal static RemoteEpisodeProvider Current; + /// /// Initializes a new instance of the class. /// @@ -52,6 +54,7 @@ namespace MediaBrowser.Providers.TV HttpClient = httpClient; _providerManager = providerManager; _fileSystem = fileSystem; + Current = this; } /// @@ -165,7 +168,7 @@ namespace MediaBrowser.Providers.TV /// The episode. /// The series data path. /// List{FileInfo}. - private List GetEpisodeXmlFiles(Episode episode, string seriesDataPath) + internal List GetEpisodeXmlFiles(Episode episode, string seriesDataPath) { var files = new List();