change RemoteSeriesProvide to XmlReader

This commit is contained in:
Luke Pulverenti 2013-09-15 14:16:28 -04:00
parent 29cc8c1d4c
commit 7ecbf44590

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Configuration;
using System.Collections.Generic;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@ -8,7 +9,6 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Providers.Extensions;
using System;
using System.Globalization;
using System.IO;
@ -18,7 +18,6 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace MediaBrowser.Providers.TV
{
@ -240,10 +239,7 @@ namespace MediaBrowser.Providers.TV
var seriesXmlPath = Path.Combine(seriesDataPath, seriesXmlFilename);
var actorsXmlPath = Path.Combine(seriesDataPath, "actors.xml");
var seriesDoc = new XmlDocument();
seriesDoc.Load(seriesXmlPath);
FetchMainInfo(series, seriesDoc);
FetchSeriesInfo(series, seriesXmlPath, cancellationToken);
if (!series.LockedFields.Contains(MetadataFields.Cast))
{
@ -317,114 +313,365 @@ namespace MediaBrowser.Providers.TV
return dataPath;
}
/// <summary>
/// Fetches the main info.
/// </summary>
/// <param name="series">The series.</param>
/// <param name="doc">The doc.</param>
private void FetchMainInfo(Series series, XmlDocument doc)
private void FetchSeriesInfo(Series item, string seriesXmlPath, CancellationToken cancellationToken)
{
if (!series.LockedFields.Contains(MetadataFields.Name))
var settings = new XmlReaderSettings
{
series.Name = doc.SafeGetString("//SeriesName");
}
if (!series.LockedFields.Contains(MetadataFields.Overview))
CheckCharacters = false,
IgnoreProcessingInstructions = true,
IgnoreComments = true,
ValidationType = ValidationType.None
};
var episiodeAirDates = new List<DateTime>();
using (var streamReader = new StreamReader(seriesXmlPath, Encoding.UTF8))
{
series.Overview = doc.SafeGetString("//Overview");
}
var imdbId = doc.SafeGetString("//IMDB_ID");
if (!string.IsNullOrWhiteSpace(imdbId))
{
series.SetProviderId(MetadataProviders.Imdb, imdbId);
}
var zap2ItId = doc.SafeGetString("//zap2it_id");
if (!string.IsNullOrWhiteSpace(zap2ItId))
{
series.SetProviderId(MetadataProviders.Zap2It, zap2ItId);
}
// Only fill this if it doesn't already have a value, since we get it from imdb which has better data
if (!series.CommunityRating.HasValue || string.IsNullOrWhiteSpace(series.GetProviderId(MetadataProviders.Imdb)))
{
series.CommunityRating = doc.SafeGetSingle("//Rating", 0, 10);
}
series.AirDays = TVUtils.GetAirDays(doc.SafeGetString("//Airs_DayOfWeek"));
series.AirTime = doc.SafeGetString("//Airs_Time");
SeriesStatus seriesStatus;
if(Enum.TryParse(doc.SafeGetString("//Status"), true, out seriesStatus))
series.Status = seriesStatus;
series.PremiereDate = doc.SafeGetDateTime("//FirstAired");
if (series.PremiereDate.HasValue)
series.ProductionYear = series.PremiereDate.Value.Year;
if (!series.LockedFields.Contains(MetadataFields.Runtime))
{
series.RunTimeTicks = TimeSpan.FromMinutes(doc.SafeGetInt32("//Runtime")).Ticks;
}
if (!series.LockedFields.Contains(MetadataFields.Studios))
{
string s = doc.SafeGetString("//Network");
if (!string.IsNullOrWhiteSpace(s))
// Use XmlReader for best performance
using (var reader = XmlReader.Create(streamReader, settings))
{
series.Studios.Clear();
reader.MoveToContent();
foreach (var studio in s.Trim().Split('|'))
// Loop through each element
while (reader.Read())
{
series.AddStudio(studio);
}
}
}
cancellationToken.ThrowIfCancellationRequested();
series.OfficialRating = doc.SafeGetString("//ContentRating");
// 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");
if (g != null)
{
string[] genres = g.Trim('|').Split('|');
if (g.Length > 0)
{
series.Genres.Clear();
foreach (var genre in genres)
if (reader.NodeType == XmlNodeType.Element)
{
series.AddGenre(genre);
switch (reader.Name)
{
case "Series":
{
using (var subtree = reader.ReadSubtree())
{
FetchDataFromSeriesNode(item, subtree, cancellationToken);
}
break;
}
case "Episode":
{
using (var subtree = reader.ReadSubtree())
{
var date = GetFirstAiredDateFromEpisodeNode(subtree, cancellationToken);
if (date.HasValue)
{
episiodeAirDates.Add(date.Value);
}
}
break;
}
default:
reader.Skip();
break;
}
}
}
}
}
if (series.Status == SeriesStatus.Ended) {
var document = XDocument.Load(new XmlNodeReader(doc));
var dates = document.Descendants("Episode").Where(x => {
var seasonNumber = x.Element("SeasonNumber");
var firstAired = x.Element("FirstAired");
return firstAired != null && seasonNumber != null && (!string.IsNullOrEmpty(seasonNumber.Value) && seasonNumber.Value != "0") && !string.IsNullOrEmpty(firstAired.Value);
}).Select(x => {
DateTime? date = null;
DateTime tempDate;
var firstAired = x.Element("FirstAired");
if (firstAired != null && DateTime.TryParse(firstAired.Value, out tempDate))
{
date = tempDate;
}
return date;
}).ToList();
if(dates.Any(x=>x.HasValue))
series.EndDate = dates.Where(x => x.HasValue).Max();
if (item.Status.HasValue && item.Status.Value == SeriesStatus.Ended && episiodeAirDates.Count > 0)
{
item.EndDate = episiodeAirDates.Max();
}
}
private void FetchDataFromSeriesNode(Series item, XmlReader reader, CancellationToken cancellationToken)
{
reader.MoveToContent();
// Loop through each element
while (reader.Read())
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "SeriesName":
{
if (!item.LockedFields.Contains(MetadataFields.Name))
{
item.Name = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
}
break;
}
case "Overview":
{
if (!item.LockedFields.Contains(MetadataFields.Overview))
{
item.Overview = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
}
break;
}
case "Airs_DayOfWeek":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.AirDays = TVUtils.GetAirDays(val);
}
break;
}
case "Airs_Time":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.AirTime = val;
}
break;
}
case "ContentRating":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.OfficialRating = val;
}
break;
}
case "Rating":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
// Only fill this if it doesn't already have a value, since we get it from imdb which has better data
if (!item.CommunityRating.HasValue || string.IsNullOrWhiteSpace(item.GetProviderId(MetadataProviders.Imdb)))
{
float rval;
// float.TryParse is local aware, so it can be probamatic, force us culture
if (float.TryParse(val, NumberStyles.AllowDecimalPoint, UsCulture, out rval))
{
item.CommunityRating = rval;
}
}
}
break;
}
case "IMDB_ID":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.SetProviderId(MetadataProviders.Imdb, val);
}
break;
}
case "zap2it_id":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
item.SetProviderId(MetadataProviders.Zap2It, val);
}
break;
}
case "Status":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
SeriesStatus seriesStatus;
if (Enum.TryParse(val, true, out seriesStatus))
item.Status = seriesStatus;
}
break;
}
case "FirstAired":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
DateTime date;
if (DateTime.TryParse(val, out date))
{
date = date.ToUniversalTime();
item.PremiereDate = date;
item.ProductionYear = date.Year;
}
}
break;
}
case "Runtime":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val) && !item.LockedFields.Contains(MetadataFields.Runtime))
{
int rval;
// int.TryParse is local aware, so it can be probamatic, force us culture
if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval))
{
item.RunTimeTicks = TimeSpan.FromMinutes(rval).Ticks;
}
}
break;
}
case "Genre":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
// Only fill this in if there's no existing genres, because Imdb data from Omdb is preferred
if (!item.LockedFields.Contains(MetadataFields.Genres) && (item.Genres.Count == 0 || !string.Equals(ConfigurationManager.Configuration.PreferredMetadataLanguage, "en", StringComparison.OrdinalIgnoreCase)))
{
var vals = val
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
.Select(i => i.Trim())
.Where(i => !string.IsNullOrWhiteSpace(i))
.ToArray();
if (vals.Length > 0)
{
item.Genres.Clear();
foreach (var genre in vals)
{
item.AddGenre(genre);
}
}
}
}
break;
}
case "Network":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
if (!item.LockedFields.Contains(MetadataFields.Studios))
{
var vals = val
.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
.Select(i => i.Trim())
.Where(i => !string.IsNullOrWhiteSpace(i))
.ToArray();
if (vals.Length > 0)
{
item.Studios.Clear();
foreach (var genre in vals)
{
item.AddStudio(genre);
}
}
}
}
break;
}
default:
reader.Skip();
break;
}
}
}
}
private DateTime? GetFirstAiredDateFromEpisodeNode(XmlReader reader, CancellationToken cancellationToken)
{
DateTime? airDate = null;
int? seasonNumber = null;
reader.MoveToContent();
// Loop through each element
while (reader.Read())
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "FirstAired":
{
var val = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(val))
{
DateTime date;
if (DateTime.TryParse(val, out date))
{
airDate = date.ToUniversalTime();
}
}
break;
}
case "SeasonNumber":
{
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))
{
seasonNumber = rval;
}
}
break;
}
default:
reader.Skip();
break;
}
}
}
if (seasonNumber.HasValue && seasonNumber.Value != 0)
{
return airDate;
}
return null;
}
/// <summary>
/// Fetches the actors.
/// </summary>
@ -503,7 +750,7 @@ namespace MediaBrowser.Providers.TV
personInfo.Role = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
break;
}
default:
reader.Skip();
break;