switch some xmldocuments to xmlreaders
This commit is contained in:
parent
ebec1e159c
commit
29cc8c1d4c
|
@ -1,6 +1,7 @@
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
@ -21,6 +22,12 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
{
|
{
|
||||||
[ApiMember(Name = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public Guid UserId { get; set; }
|
public Guid UserId { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "ComedyGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
|
public string ComedyGenre { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "RomanceGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
|
public string RomanceGenre { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/MBT/DefaultTheme/Movies", "GET")]
|
[Route("/MBT/DefaultTheme/Movies", "GET")]
|
||||||
|
@ -31,6 +38,19 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
|
|
||||||
[ApiMember(Name = "FamilyRating", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "FamilyRating", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string FamilyRating { get; set; }
|
public string FamilyRating { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "ComedyGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
|
public string ComedyGenre { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "RomanceGenre", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||||
|
public string RomanceGenre { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/MBT/DefaultTheme/Home", "GET")]
|
||||||
|
public class GetHomeView : IReturn<HomeView>
|
||||||
|
{
|
||||||
|
[ApiMember(Name = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
|
public Guid UserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DefaultThemeService : BaseApiService
|
public class DefaultThemeService : BaseApiService
|
||||||
|
@ -51,6 +71,39 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object Get(GetHomeView request)
|
||||||
|
{
|
||||||
|
var result = GetHomeView(request).Result;
|
||||||
|
|
||||||
|
return ToOptimizedResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<HomeView> GetHomeView(GetHomeView request)
|
||||||
|
{
|
||||||
|
var user = _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
|
var allItems = user.RootFolder.GetRecursiveChildren(user)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var itemsWithBackdrops = allItems.Where(i => i.BackdropImagePaths.Count > 0).ToList();
|
||||||
|
|
||||||
|
var view = new HomeView();
|
||||||
|
|
||||||
|
var fields = new List<ItemFields>();
|
||||||
|
|
||||||
|
var eligibleSpotlightItems = itemsWithBackdrops
|
||||||
|
.Where(i => i is Game || i is Movie || i is Series || i is MusicArtist);
|
||||||
|
|
||||||
|
var spotlightItemTasks = FilterItemsForBackdropDisplay(eligibleSpotlightItems)
|
||||||
|
.OrderBy(i => Guid.NewGuid())
|
||||||
|
.Take(50)
|
||||||
|
.Select(i => _dtoService.GetBaseItemDto(i, fields, user));
|
||||||
|
|
||||||
|
view.SpotlightItems = await Task.WhenAll(spotlightItemTasks).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
public object Get(GetTvView request)
|
public object Get(GetTvView request)
|
||||||
{
|
{
|
||||||
var result = GetTvView(request).Result;
|
var result = GetTvView(request).Result;
|
||||||
|
@ -72,10 +125,9 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
|
|
||||||
var fields = new List<ItemFields>();
|
var fields = new List<ItemFields>();
|
||||||
|
|
||||||
var spotlightItemTasks = seriesWithBackdrops
|
var spotlightItemTasks = FilterItemsForBackdropDisplay(seriesWithBackdrops)
|
||||||
.OrderByDescending(i => GetResolution(i, i.BackdropImagePaths[0]))
|
|
||||||
.Take(60)
|
|
||||||
.OrderBy(i => Guid.NewGuid())
|
.OrderBy(i => Guid.NewGuid())
|
||||||
|
.Take(50)
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, fields, user));
|
.Select(i => _dtoService.GetBaseItemDto(i, fields, user));
|
||||||
|
|
||||||
view.SpotlightItems = await Task.WhenAll(spotlightItemTasks).ConfigureAwait(false);
|
view.SpotlightItems = await Task.WhenAll(spotlightItemTasks).ConfigureAwait(false);
|
||||||
|
@ -88,6 +140,25 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
.Take(3)
|
.Take(3)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
var romanceGenres = request.RomanceGenre.Split(',').ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var comedyGenres = request.ComedyGenre.Split(',').ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
view.RomanceItems = seriesWithBackdrops
|
||||||
|
.Where(i => i.Genres.Any(romanceGenres.ContainsKey))
|
||||||
|
.OrderBy(i => Guid.NewGuid())
|
||||||
|
.Select(i => GetItemStub(i, ImageType.Backdrop))
|
||||||
|
.Where(i => i != null)
|
||||||
|
.Take(3)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
view.ComedyItems = seriesWithBackdrops
|
||||||
|
.Where(i => i.Genres.Any(comedyGenres.ContainsKey))
|
||||||
|
.OrderBy(i => Guid.NewGuid())
|
||||||
|
.Select(i => GetItemStub(i, ImageType.Backdrop))
|
||||||
|
.Where(i => i != null)
|
||||||
|
.Take(3)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
view.ActorItems = await GetActors(series).ConfigureAwait(false);
|
view.ActorItems = await GetActors(series).ConfigureAwait(false);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
|
@ -137,10 +208,9 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
|
|
||||||
var fields = new List<ItemFields>();
|
var fields = new List<ItemFields>();
|
||||||
|
|
||||||
var spotlightItemTasks = itemsWithBackdrops
|
var spotlightItemTasks = FilterItemsForBackdropDisplay(itemsWithBackdrops)
|
||||||
.OrderByDescending(i => GetResolution(i, i.BackdropImagePaths[0]))
|
|
||||||
.Take(60)
|
|
||||||
.OrderBy(i => Guid.NewGuid())
|
.OrderBy(i => Guid.NewGuid())
|
||||||
|
.Take(50)
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, fields, user));
|
.Select(i => _dtoService.GetBaseItemDto(i, fields, user));
|
||||||
|
|
||||||
view.SpotlightItems = await Task.WhenAll(spotlightItemTasks).ConfigureAwait(false);
|
view.SpotlightItems = await Task.WhenAll(spotlightItemTasks).ConfigureAwait(false);
|
||||||
|
@ -178,9 +248,10 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
.Take(3)
|
.Take(3)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var romanceGenres = new[] { "romance" }.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
var romanceGenres = request.RomanceGenre.Split(',').ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var comedyGenres = request.ComedyGenre.Split(',').ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
view.RomanticItems = moviesWithBackdrops
|
view.RomanceItems = moviesWithBackdrops
|
||||||
.Where(i => i.Genres.Any(romanceGenres.ContainsKey))
|
.Where(i => i.Genres.Any(romanceGenres.ContainsKey))
|
||||||
.OrderBy(i => Guid.NewGuid())
|
.OrderBy(i => Guid.NewGuid())
|
||||||
.Select(i => GetItemStub(i, ImageType.Backdrop))
|
.Select(i => GetItemStub(i, ImageType.Backdrop))
|
||||||
|
@ -188,6 +259,14 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
.Take(3)
|
.Take(3)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
view.ComedyItems = moviesWithBackdrops
|
||||||
|
.Where(i => i.Genres.Any(comedyGenres.ContainsKey))
|
||||||
|
.OrderBy(i => Guid.NewGuid())
|
||||||
|
.Select(i => GetItemStub(i, ImageType.Backdrop))
|
||||||
|
.Where(i => i != null)
|
||||||
|
.Take(3)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
view.HDItems = hdMovies
|
view.HDItems = hdMovies
|
||||||
.Where(i => i.BackdropImagePaths.Count > 0)
|
.Where(i => i.BackdropImagePaths.Count > 0)
|
||||||
.OrderBy(i => Guid.NewGuid())
|
.OrderBy(i => Guid.NewGuid())
|
||||||
|
@ -209,6 +288,25 @@ namespace MediaBrowser.Api.DefaultTheme
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerable<BaseItem> FilterItemsForBackdropDisplay(IEnumerable<BaseItem> items)
|
||||||
|
{
|
||||||
|
var tuples = items
|
||||||
|
.Select(i => new Tuple<BaseItem, double>(i, GetResolution(i, i.BackdropImagePaths[0])))
|
||||||
|
.Where(i => i.Item2 > 0)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var topItems = tuples
|
||||||
|
.Where(i => i.Item2 >= 1920)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (topItems.Count >= 10)
|
||||||
|
{
|
||||||
|
return topItems.Select(i => i.Item1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tuples.Select(i => i.Item1);
|
||||||
|
}
|
||||||
|
|
||||||
private double GetResolution(BaseItem item, string path)
|
private double GetResolution(BaseItem item, string path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Linq;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Movies;
|
using MediaBrowser.Controller.Entities.Movies;
|
||||||
|
@ -10,6 +9,7 @@ using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ namespace MediaBrowser.Providers.Movies
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return "8";
|
return "9";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,9 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Net;
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
@ -98,7 +97,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return "1";
|
return "2";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,22 +137,21 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null;
|
var seriesId = season.Series != null ? season.Series.GetProviderId(MetadataProviders.Tvdb) : null;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(seriesId))
|
var seasonNumber = season.IndexNumber;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(seriesId) && seasonNumber.HasValue)
|
||||||
{
|
{
|
||||||
// Process images
|
// Process images
|
||||||
var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
|
var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
|
||||||
|
|
||||||
var imagesFileInfo = new FileInfo(imagesXmlPath);
|
try
|
||||||
|
|
||||||
if (imagesFileInfo.Exists)
|
|
||||||
{
|
{
|
||||||
if (!season.HasImage(ImageType.Primary) || !season.HasImage(ImageType.Banner) || season.BackdropImagePaths.Count == 0)
|
var fanartData = FetchFanartXmlData(imagesXmlPath, seasonNumber.Value, cancellationToken);
|
||||||
{
|
await DownloadImages(item, fanartData, ConfigurationManager.Configuration.MaxBackdrops, cancellationToken).ConfigureAwait(false);
|
||||||
var xmlDoc = new XmlDocument();
|
|
||||||
xmlDoc.Load(imagesXmlPath);
|
|
||||||
|
|
||||||
await FetchImages(season, xmlDoc, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
// No biggie. Not all series have images
|
||||||
}
|
}
|
||||||
|
|
||||||
SetLastRefreshed(item, DateTime.UtcNow);
|
SetLastRefreshed(item, DateTime.UtcNow);
|
||||||
|
@ -163,86 +161,169 @@ namespace MediaBrowser.Providers.TV
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private async Task DownloadImages(BaseItem item, FanartXmlData data, int backdropLimit, CancellationToken cancellationToken)
|
||||||
/// Fetches the images.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="season">The season.</param>
|
|
||||||
/// <param name="images">The images.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
private async Task FetchImages(Season season, XmlDocument images, CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
var seasonNumber = season.IndexNumber ?? -1;
|
if (!item.HasImage(ImageType.Primary))
|
||||||
|
{
|
||||||
|
var url = data.LanguagePoster ?? data.Poster;
|
||||||
|
if (!string.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
url = TVUtils.BannerUrl + url;
|
||||||
|
|
||||||
if (seasonNumber == -1)
|
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken)
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!season.HasImage(ImageType.Primary))
|
|
||||||
{
|
|
||||||
var n = images.SelectSingleNode("//Banner[BannerType='season'][BannerType2='season'][Season='" + seasonNumber + "'][Language='" + ConfigurationManager.Configuration.PreferredMetadataLanguage + "']") ??
|
|
||||||
images.SelectSingleNode("//Banner[BannerType='season'][BannerType2='season'][Season='" + seasonNumber + "'][Language='en']");
|
|
||||||
if (n != null)
|
|
||||||
{
|
|
||||||
n = n.SelectSingleNode("./BannerPath");
|
|
||||||
|
|
||||||
if (n != null)
|
|
||||||
{
|
|
||||||
var url = TVUtils.BannerUrl + n.InnerText;
|
|
||||||
|
|
||||||
await _providerManager.SaveImage(season, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken)
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ConfigurationManager.Configuration.DownloadSeasonImages.Banner && !season.HasImage(ImageType.Banner))
|
if (ConfigurationManager.Configuration.DownloadSeasonImages.Banner && !item.HasImage(ImageType.Banner))
|
||||||
{
|
{
|
||||||
var n = images.SelectSingleNode("//Banner[BannerType='season'][BannerType2='seasonwide'][Season='" + seasonNumber + "'][Language='" + ConfigurationManager.Configuration.PreferredMetadataLanguage + "']") ??
|
var url = data.LanguageBanner ?? data.Banner;
|
||||||
images.SelectSingleNode("//Banner[BannerType='season'][BannerType2='seasonwide'][Season='" + seasonNumber + "'][Language='en']");
|
if (!string.IsNullOrEmpty(url))
|
||||||
if (n != null)
|
|
||||||
{
|
{
|
||||||
n = n.SelectSingleNode("./BannerPath");
|
url = TVUtils.BannerUrl + url;
|
||||||
if (n != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var url = TVUtils.BannerUrl + n.InnerText;
|
|
||||||
|
|
||||||
await _providerManager.SaveImage(season, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken)
|
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (HttpException ex)
|
|
||||||
{
|
|
||||||
Logger.ErrorException("Error downloading season banner for {0}", ex, season.Path);
|
|
||||||
|
|
||||||
// Sometimes banners will come up not found even though they're reported in tvdb xml
|
|
||||||
if (ex.StatusCode.HasValue && ex.StatusCode.Value != HttpStatusCode.NotFound)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConfigurationManager.Configuration.DownloadSeasonImages.Backdrops && season.BackdropImagePaths.Count == 0)
|
if (ConfigurationManager.Configuration.DownloadSeasonImages.Backdrops && item.BackdropImagePaths.Count == 0)
|
||||||
{
|
{
|
||||||
var n = images.SelectSingleNode("//Banner[BannerType='fanart'][Season='" + seasonNumber + "']");
|
var bdNo = item.BackdropImagePaths.Count;
|
||||||
if (n != null)
|
|
||||||
{
|
|
||||||
n = n.SelectSingleNode("./BannerPath");
|
|
||||||
if (n != null)
|
|
||||||
{
|
|
||||||
var url = TVUtils.BannerUrl + n.InnerText;
|
|
||||||
|
|
||||||
await _providerManager.SaveImage(season, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, 0, cancellationToken)
|
foreach (var backdrop in data.Backdrops)
|
||||||
|
{
|
||||||
|
var url = TVUtils.BannerUrl + backdrop;
|
||||||
|
|
||||||
|
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
bdNo++;
|
||||||
|
|
||||||
|
if (item.BackdropImagePaths.Count >= backdropLimit) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FanartXmlData FetchFanartXmlData(string bannersXmlPath, int seasonNumber, 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, seasonNumber);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FetchInfoFromBannerNode(FanartXmlData data, XmlReader reader, int seasonNumber)
|
||||||
|
{
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
string bannerType = null;
|
||||||
|
string bannerType2 = null;
|
||||||
|
string url = null;
|
||||||
|
int? bannerSeason = null;
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case "BannerType":
|
||||||
|
{
|
||||||
|
bannerType = reader.ReadElementContentAsString() ?? string.Empty;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "BannerType2":
|
||||||
|
{
|
||||||
|
bannerType2 = reader.ReadElementContentAsString() ?? string.Empty;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "BannerPath":
|
||||||
|
{
|
||||||
|
url = reader.ReadElementContentAsString() ?? string.Empty;
|
||||||
|
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 && bannerSeason.Value == seasonNumber)
|
||||||
|
{
|
||||||
|
if (string.Equals(bannerType, "season", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (string.Equals(bannerType2, "season", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
data.Poster = url;
|
||||||
|
}
|
||||||
|
else if (string.Equals(bannerType2, "seasonwide", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
data.Banner = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (string.Equals(bannerType, "fanart", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
data.Backdrops.Add(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,10 +247,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
if (!series.LockedFields.Contains(MetadataFields.Cast))
|
if (!series.LockedFields.Contains(MetadataFields.Cast))
|
||||||
{
|
{
|
||||||
var actorsDoc = new XmlDocument();
|
FetchActors(series, actorsXmlPath, cancellationToken);
|
||||||
actorsDoc.Load(actorsXmlPath);
|
|
||||||
|
|
||||||
FetchActors(series, actorsDoc, seriesDoc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -384,8 +381,11 @@ namespace MediaBrowser.Providers.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
series.OfficialRating = doc.SafeGetString("//ContentRating");
|
series.OfficialRating = doc.SafeGetString("//ContentRating");
|
||||||
if (!series.LockedFields.Contains(MetadataFields.Genres))
|
|
||||||
|
// Only fill this in if there's no existing genres, because Imdb data from Omdb is preferred
|
||||||
|
if (!series.LockedFields.Contains(MetadataFields.Genres) && (series.Genres.Count == 0 || !string.Equals(ConfigurationManager.Configuration.PreferredMetadataLanguage, "en", StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
string g = doc.SafeGetString("//Genre");
|
string g = doc.SafeGetString("//Genre");
|
||||||
|
|
||||||
|
@ -429,30 +429,93 @@ namespace MediaBrowser.Providers.TV
|
||||||
/// Fetches the actors.
|
/// Fetches the actors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="series">The series.</param>
|
/// <param name="series">The series.</param>
|
||||||
/// <param name="actorsDoc">The actors doc.</param>
|
/// <param name="actorsXmlPath">The actors XML path.</param>
|
||||||
/// <param name="seriesDoc">The seriesDoc.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
private void FetchActors(Series series, string actorsXmlPath, CancellationToken cancellationToken)
|
||||||
private void FetchActors(Series series, XmlDocument actorsDoc, XmlDocument seriesDoc)
|
|
||||||
{
|
{
|
||||||
var xmlNodeList = actorsDoc.SelectNodes("Actors/Actor");
|
var settings = new XmlReaderSettings
|
||||||
|
{
|
||||||
|
CheckCharacters = false,
|
||||||
|
IgnoreProcessingInstructions = true,
|
||||||
|
IgnoreComments = true,
|
||||||
|
ValidationType = ValidationType.None
|
||||||
|
};
|
||||||
|
|
||||||
if (xmlNodeList != null)
|
using (var streamReader = new StreamReader(actorsXmlPath, Encoding.UTF8))
|
||||||
{
|
{
|
||||||
series.People.Clear();
|
// Use XmlReader for best performance
|
||||||
|
using (var reader = XmlReader.Create(streamReader, settings))
|
||||||
|
{
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
foreach (XmlNode p in xmlNodeList)
|
// Loop through each element
|
||||||
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
string actorName = p.SafeGetString("Name");
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
string actorRole = p.SafeGetString("Role");
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(actorName))
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
{
|
{
|
||||||
// Sometimes tvdb actors have leading spaces
|
switch (reader.Name)
|
||||||
series.AddPerson(new PersonInfo { Type = PersonType.Actor, Name = actorName.Trim(), Role = actorRole });
|
{
|
||||||
|
case "Actor":
|
||||||
|
{
|
||||||
|
using (var subtree = reader.ReadSubtree())
|
||||||
|
{
|
||||||
|
FetchDataFromActorNode(series, subtree);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches the data from actor node.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="series">The series.</param>
|
||||||
|
/// <param name="reader">The reader.</param>
|
||||||
|
private void FetchDataFromActorNode(Series series, XmlReader reader)
|
||||||
|
{
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
var personInfo = new PersonInfo();
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case "Name":
|
||||||
|
{
|
||||||
|
personInfo.Name = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "Role":
|
||||||
|
{
|
||||||
|
personInfo.Role = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(personInfo.Name))
|
||||||
|
{
|
||||||
|
series.AddPerson(personInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The us culture
|
/// The us culture
|
||||||
|
|
|
@ -5,10 +5,10 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Providers.Extensions;
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
@ -87,37 +87,113 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
var actorXmlPath = Path.Combine(tvdbPath, "actors.xml");
|
var actorXmlPath = Path.Combine(tvdbPath, "actors.xml");
|
||||||
|
|
||||||
var xmlDoc = new XmlDocument();
|
var url = FetchImageUrl(item, actorXmlPath, cancellationToken);
|
||||||
|
|
||||||
xmlDoc.Load(actorXmlPath);
|
if (!string.IsNullOrEmpty(url))
|
||||||
|
|
||||||
var actorNodes = xmlDoc.SelectNodes("//Actor");
|
|
||||||
|
|
||||||
if (actorNodes == null)
|
|
||||||
{
|
{
|
||||||
return;
|
url = TVUtils.BannerUrl + url;
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var actorNode in actorNodes.OfType<XmlNode>())
|
|
||||||
{
|
|
||||||
var name = actorNode.SafeGetString("Name");
|
|
||||||
|
|
||||||
if (string.Equals(item.Name, name, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var image = actorNode.SafeGetString("Image");
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(image))
|
|
||||||
{
|
|
||||||
var url = TVUtils.BannerUrl + image;
|
|
||||||
|
|
||||||
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool,
|
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool,
|
||||||
ImageType.Primary, null, cancellationToken).ConfigureAwait(false);
|
ImageType.Primary, null, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
private string FetchImageUrl(BaseItem item, string actorsXmlPath, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var settings = new XmlReaderSettings
|
||||||
|
{
|
||||||
|
CheckCharacters = false,
|
||||||
|
IgnoreProcessingInstructions = true,
|
||||||
|
IgnoreComments = true,
|
||||||
|
ValidationType = ValidationType.None
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var streamReader = new StreamReader(actorsXmlPath, 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 "Actor":
|
||||||
|
{
|
||||||
|
using (var subtree = reader.ReadSubtree())
|
||||||
|
{
|
||||||
|
var url = FetchImageUrlFromActorNode(item, subtree);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches the data from actor node.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="reader">The reader.</param>
|
||||||
|
private string FetchImageUrlFromActorNode(BaseItem item, XmlReader reader)
|
||||||
|
{
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
string name = null;
|
||||||
|
string image = null;
|
||||||
|
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case "Name":
|
||||||
|
{
|
||||||
|
name = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "Image":
|
||||||
|
{
|
||||||
|
image = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(image) &&
|
||||||
|
string.Equals(name, item.Name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public override MetadataProviderPriority Priority
|
public override MetadataProviderPriority Priority
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,6 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using MediaBrowser.Providers.Extensions;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
|
@ -102,11 +101,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
}).ConfigureAwait(false))
|
}).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
var doc = new XmlDocument();
|
newUpdateTime = GetUpdateTime(stream);
|
||||||
|
|
||||||
doc.Load(stream);
|
|
||||||
|
|
||||||
newUpdateTime = doc.SafeGetString("//Time");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await UpdateSeries(existingDirectories, path, progress, cancellationToken).ConfigureAwait(false);
|
await UpdateSeries(existingDirectories, path, progress, cancellationToken).ConfigureAwait(false);
|
||||||
|
@ -124,6 +119,51 @@ namespace MediaBrowser.Providers.TV
|
||||||
progress.Report(100);
|
progress.Report(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the update time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response">The response.</param>
|
||||||
|
/// <returns>System.String.</returns>
|
||||||
|
private string GetUpdateTime(Stream response)
|
||||||
|
{
|
||||||
|
var settings = new XmlReaderSettings
|
||||||
|
{
|
||||||
|
CheckCharacters = false,
|
||||||
|
IgnoreProcessingInstructions = true,
|
||||||
|
IgnoreComments = true,
|
||||||
|
ValidationType = ValidationType.None
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var streamReader = new StreamReader(response, Encoding.UTF8))
|
||||||
|
{
|
||||||
|
// Use XmlReader for best performance
|
||||||
|
using (var reader = XmlReader.Create(streamReader, settings))
|
||||||
|
{
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
// Loop through each element
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case "Time":
|
||||||
|
{
|
||||||
|
return (reader.ReadElementContentAsString() ?? string.Empty).Trim();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the series ids to update.
|
/// Gets the series ids to update.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -143,25 +183,67 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
}).ConfigureAwait(false))
|
}).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
var doc = new XmlDocument();
|
var data = GetUpdatedSeriesIdList(stream);
|
||||||
|
|
||||||
doc.Load(stream);
|
|
||||||
|
|
||||||
var newUpdateTime = doc.SafeGetString("//Time");
|
|
||||||
|
|
||||||
var seriesNodes = doc.SelectNodes("//Series");
|
|
||||||
|
|
||||||
var existingDictionary = existingSeriesIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
var existingDictionary = existingSeriesIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var seriesList = seriesNodes == null ? new string[] { } :
|
var seriesList = data.Item1
|
||||||
seriesNodes.Cast<XmlNode>()
|
|
||||||
.Select(i => i.InnerText)
|
|
||||||
.Where(i => !string.IsNullOrWhiteSpace(i) && existingDictionary.ContainsKey(i));
|
.Where(i => !string.IsNullOrWhiteSpace(i) && existingDictionary.ContainsKey(i));
|
||||||
|
|
||||||
return new Tuple<IEnumerable<string>, string>(seriesList, newUpdateTime);
|
return new Tuple<IEnumerable<string>, string>(seriesList, data.Item2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Tuple<List<string>, string> GetUpdatedSeriesIdList(Stream stream)
|
||||||
|
{
|
||||||
|
string updateTime = null;
|
||||||
|
var idList = new List<string>();
|
||||||
|
|
||||||
|
var settings = new XmlReaderSettings
|
||||||
|
{
|
||||||
|
CheckCharacters = false,
|
||||||
|
IgnoreProcessingInstructions = true,
|
||||||
|
IgnoreComments = true,
|
||||||
|
ValidationType = ValidationType.None
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var streamReader = new StreamReader(stream, Encoding.UTF8))
|
||||||
|
{
|
||||||
|
// Use XmlReader for best performance
|
||||||
|
using (var reader = XmlReader.Create(streamReader, settings))
|
||||||
|
{
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
// Loop through each element
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case "Time":
|
||||||
|
{
|
||||||
|
updateTime = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "Series":
|
||||||
|
{
|
||||||
|
var id = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
|
||||||
|
idList.Add(id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<List<string>, string>(idList, updateTime);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the series.
|
/// Updates the series.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -7,8 +7,10 @@ using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
@ -150,16 +152,18 @@ namespace MediaBrowser.Providers.TV
|
||||||
// Process images
|
// Process images
|
||||||
var imagesXmlPath = Path.Combine(RemoteSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");
|
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)
|
if (!series.HasImage(ImageType.Primary) || !series.HasImage(ImageType.Banner) || series.BackdropImagePaths.Count == 0)
|
||||||
{
|
{
|
||||||
var xmlDoc = new XmlDocument();
|
var backdropLimit = ConfigurationManager.Configuration.MaxBackdrops;
|
||||||
xmlDoc.Load(imagesXmlPath);
|
|
||||||
|
|
||||||
await FetchImages(series, xmlDoc, cancellationToken).ConfigureAwait(false);
|
try
|
||||||
|
{
|
||||||
|
var fanartData = FetchFanartXmlData(imagesXmlPath, backdropLimit, cancellationToken);
|
||||||
|
await DownloadImages(item, fanartData, backdropLimit, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
// No biggie. Not all series have images
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,72 +183,183 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
/// <summary>
|
private async Task DownloadImages(BaseItem item, FanartXmlData data, int backdropLimit, CancellationToken cancellationToken)
|
||||||
/// Fetches the images.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="series">The series.</param>
|
|
||||||
/// <param name="images">The images.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>Task.</returns>
|
|
||||||
private async Task FetchImages(Series series, XmlDocument images, CancellationToken cancellationToken)
|
|
||||||
{
|
{
|
||||||
if (!series.HasImage(ImageType.Primary))
|
if (!item.HasImage(ImageType.Primary))
|
||||||
{
|
{
|
||||||
var n = images.SelectSingleNode("//Banner[BannerType='poster']");
|
var url = data.LanguagePoster ?? data.Poster;
|
||||||
if (n != null)
|
if (!string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
n = n.SelectSingleNode("./BannerPath");
|
url = TVUtils.BannerUrl + url;
|
||||||
if (n != null)
|
|
||||||
{
|
|
||||||
var url = TVUtils.BannerUrl + n.InnerText;
|
|
||||||
|
|
||||||
await _providerManager.SaveImage(series, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken)
|
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ConfigurationManager.Configuration.DownloadSeriesImages.Banner && !series.HasImage(ImageType.Banner))
|
if (ConfigurationManager.Configuration.DownloadSeriesImages.Banner && !item.HasImage(ImageType.Banner))
|
||||||
{
|
{
|
||||||
var n = images.SelectSingleNode("//Banner[BannerType='series']");
|
var url = data.LanguageBanner ?? data.Banner;
|
||||||
if (n != null)
|
if (!string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
n = n.SelectSingleNode("./BannerPath");
|
url = TVUtils.BannerUrl + url;
|
||||||
if (n != null)
|
|
||||||
{
|
|
||||||
var url = TVUtils.BannerUrl + n.InnerText;
|
|
||||||
|
|
||||||
await _providerManager.SaveImage(series, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken)
|
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (series.BackdropImagePaths.Count == 0)
|
if (ConfigurationManager.Configuration.DownloadSeriesImages.Backdrops && item.BackdropImagePaths.Count == 0)
|
||||||
{
|
{
|
||||||
var bdNo = series.BackdropImagePaths.Count;
|
var bdNo = item.BackdropImagePaths.Count;
|
||||||
|
|
||||||
var xmlNodeList = images.SelectNodes("//Banner[BannerType='fanart']");
|
foreach (var backdrop in data.Backdrops)
|
||||||
if (xmlNodeList != null)
|
|
||||||
{
|
{
|
||||||
foreach (XmlNode b in xmlNodeList)
|
var url = TVUtils.BannerUrl + backdrop;
|
||||||
{
|
|
||||||
var p = b.SelectSingleNode("./BannerPath");
|
|
||||||
|
|
||||||
if (p != null)
|
await _providerManager.SaveImage(item, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken)
|
||||||
{
|
|
||||||
var url = TVUtils.BannerUrl + p.InnerText;
|
|
||||||
|
|
||||||
await _providerManager.SaveImage(series, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken)
|
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
bdNo++;
|
bdNo++;
|
||||||
|
|
||||||
|
if (item.BackdropImagePaths.Count >= backdropLimit) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (series.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) break;
|
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;
|
||||||
|
|
||||||
|
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 if (string.Equals(type, "fanart", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (data.Backdrops.Count >= backdropLimit)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "BannerPath":
|
||||||
|
{
|
||||||
|
url = reader.ReadElementContentAsString() ?? string.Empty;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
if (string.Equals(type, "poster", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
data.Poster = url;
|
||||||
|
}
|
||||||
|
else if (string.Equals(type, "series", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
data.Banner = url;
|
||||||
|
}
|
||||||
|
else if (string.Equals(type, "fanart", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
data.Backdrops.Add(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<string> Backdrops = new List<string>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user