using System; using System.Globalization; using System.IO; using System.Text; using System.Threading; using System.Xml; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using Microsoft.Extensions.Logging; namespace MediaBrowser.XbmcMetadata.Parsers { /// /// Nfo parser for episodes. /// public class EpisodeNfoParser : BaseNfoParser { /// /// Initializes a new instance of the class. /// /// The logger. /// the configuration manager. /// The provider manager. public EpisodeNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager) : base(logger, config, providerManager) { } /// protected override void Fetch(MetadataResult item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken) { using (var fileStream = File.OpenRead(metadataFile)) using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { item.ResetPeople(); var xml = streamReader.ReadToEnd(); var srch = ""; var index = xml.IndexOf(srch, StringComparison.OrdinalIgnoreCase); if (index != -1) { xml = xml.Substring(0, index + srch.Length); } // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions try { using (var stringReader = new StringReader(xml)) using (var reader = XmlReader.Create(stringReader, settings)) { reader.MoveToContent(); reader.Read(); // Loop through each element while (!reader.EOF && reader.ReadState == ReadState.Interactive) { cancellationToken.ThrowIfCancellationRequested(); if (reader.NodeType == XmlNodeType.Element) { FetchDataFromXmlNode(reader, item); } else { reader.Read(); } } } } catch (XmlException) { } } } /// protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult itemResult) { var item = itemResult.Item; switch (reader.Name) { case "season": { var number = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(number)) { if (int.TryParse(number, out var num)) { item.ParentIndexNumber = num; } } break; } case "episode": { var number = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(number)) { if (int.TryParse(number, out var num)) { item.IndexNumber = num; } } break; } case "episodenumberend": { var number = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(number)) { if (int.TryParse(number, out var num)) { item.IndexNumberEnd = num; } } break; } case "airsbefore_episode": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) { item.AirsBeforeEpisodeNumber = rval; } } break; } case "airsafter_season": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) { item.AirsAfterSeasonNumber = rval; } } break; } case "airsbefore_season": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) { item.AirsBeforeSeasonNumber = rval; } } break; } case "displayseason": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) { item.AirsBeforeSeasonNumber = rval; } } break; } case "displayepisode": { var val = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(val)) { // int.TryParse is local aware, so it can be problematic, force us culture if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var rval)) { item.AirsBeforeEpisodeNumber = rval; } } break; } case "showtitle": { var showtitle = reader.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(showtitle)) { item.SeriesName = showtitle; } break; } default: base.FetchDataFromXmlNode(reader, itemResult); break; } } } }