From 5fa577a9ee143ac570dbd237270d33374e8a15a2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 1 Nov 2013 17:26:07 -0400 Subject: [PATCH] #605 - Add manual image selection for Series --- .../MediaBrowser.Providers.csproj | 1 + MediaBrowser.Providers/TV/FanArtTVProvider.cs | 2 - .../TV/ManualFanartSeriesProvider.cs | 309 ++++++++++++++++++ 3 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index ef1aa6777..9906ad14c 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -111,6 +111,7 @@ + diff --git a/MediaBrowser.Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Providers/TV/FanArtTVProvider.cs index e349b82ce..0578887ad 100644 --- a/MediaBrowser.Providers/TV/FanArtTVProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtTVProvider.cs @@ -4,7 +4,6 @@ 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; @@ -12,7 +11,6 @@ using MediaBrowser.Model.Logging; using System; using System.Globalization; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml; diff --git a/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs b/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs new file mode 100644 index 000000000..21b8e278c --- /dev/null +++ b/MediaBrowser.Providers/TV/ManualFanartSeriesProvider.cs @@ -0,0 +1,309 @@ +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; + +namespace MediaBrowser.Providers.TV +{ + public class ManualFanartSeriesImageProvider : IImageProvider + { + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + private readonly IServerConfigurationManager _config; + + public ManualFanartSeriesImageProvider(IServerConfigurationManager config) + { + _config = config; + } + + public string Name + { + get { return ProviderName; } + } + + public static string ProviderName + { + get { return "FanArt"; } + } + + public bool Supports(BaseItem item) + { + return item is Series; + } + + public async Task> GetImages(BaseItem item, ImageType imageType, CancellationToken cancellationToken) + { + var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false); + + return images.Where(i => i.Type == imageType); + } + + public Task> GetAllImages(BaseItem item, CancellationToken cancellationToken) + { + var list = new List(); + + var series = (Series)item; + + var id = series.GetProviderId(MetadataProviders.Tvdb); + + if (!string.IsNullOrEmpty(id)) + { + var xmlPath = FanArtTvProvider.Current.GetFanartXmlPath(id); + + try + { + AddImages(list, xmlPath, cancellationToken); + } + catch (FileNotFoundException) + { + // No biggie. Don't blow up + } + } + + var language = _config.Configuration.PreferredMetadataLanguage; + + 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) + .ToList(); + + return Task.FromResult>(list); + } + + private void AddImages(List list, string xmlPath, CancellationToken cancellationToken) + { + using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8)) + { + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings + { + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true, + ValidationType = ValidationType.None + })) + { + reader.MoveToContent(); + + // Loop through each element + while (reader.Read()) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "series": + { + using (var subReader = reader.ReadSubtree()) + { + AddImages(list, subReader, cancellationToken); + } + break; + } + + default: + reader.Skip(); + break; + } + } + } + } + } + } + + private void AddImages(List list, XmlReader reader, CancellationToken cancellationToken) + { + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "hdtvlogos": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 800, 310); + } + break; + } + case "hdcleararts": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 1000, 562); + } + break; + } + case "clearlogos": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 400, 155); + } + break; + } + case "cleararts": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 500, 281); + } + break; + } + case "showbackgrounds": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080, true); + } + break; + } + case "seasonthumbs": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281); + } + break; + } + case "tvthumbs": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281); + } + break; + } + case "tvbanners": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Banner, 1000, 185); + } + break; + } + case "tvposters": + { + using (var subReader = reader.ReadSubtree()) + { + PopulateImageCategory(list, subReader, cancellationToken, ImageType.Primary, 1000, 1426); + } + break; + } + default: + { + using (reader.ReadSubtree()) + { + } + break; + } + } + } + } + } + + private void PopulateImageCategory(List list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, bool allowSeasonAll = false) + { + reader.MoveToContent(); + + while (reader.Read()) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "hdtvlogo": + case "hdclearart": + case "clearlogo": + case "clearart": + case "showbackground": + case "seasonthumb": + case "tvthumb": + case "tvbanner": + case "tvposter": + { + var url = reader.GetAttribute("url"); + var season = reader.GetAttribute("season"); + + var isSeasonValid = string.IsNullOrEmpty(season) || + (allowSeasonAll && string.Equals(season, "all", StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrEmpty(url) && isSeasonValid) + { + 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 Priority + { + get { return 1; } + } + } +}