change RemoteSeriesProvide to XmlReader

pull/702/head
Luke Pulverenti 11 years ago
parent 29cc8c1d4c
commit 7ecbf44590

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

Loading…
Cancel
Save