BaseNfoParser.cs 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. using MediaBrowser.Common.Configuration;
  2. using MediaBrowser.Controller.Entities;
  3. using MediaBrowser.Model.Entities;
  4. using MediaBrowser.Model.Logging;
  5. using MediaBrowser.XbmcMetadata.Configuration;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Globalization;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Xml;
  14. using MediaBrowser.XbmcMetadata.Savers;
  15. namespace MediaBrowser.XbmcMetadata.Parsers
  16. {
  17. public class BaseNfoParser<T>
  18. where T : BaseItem
  19. {
  20. /// <summary>
  21. /// The logger
  22. /// </summary>
  23. protected ILogger Logger { get; private set; }
  24. private readonly CultureInfo _usCulture = new CultureInfo("en-US");
  25. private readonly IConfigurationManager _config;
  26. /// <summary>
  27. /// Initializes a new instance of the <see cref="BaseNfoParser{T}" /> class.
  28. /// </summary>
  29. /// <param name="logger">The logger.</param>
  30. /// <param name="config">The configuration.</param>
  31. public BaseNfoParser(ILogger logger, IConfigurationManager config)
  32. {
  33. Logger = logger;
  34. _config = config;
  35. }
  36. /// <summary>
  37. /// Fetches metadata for an item from one xml file
  38. /// </summary>
  39. /// <param name="item">The item.</param>
  40. /// <param name="metadataFile">The metadata file.</param>
  41. /// <param name="cancellationToken">The cancellation token.</param>
  42. /// <exception cref="System.ArgumentNullException"></exception>
  43. public void Fetch(T item, string metadataFile, CancellationToken cancellationToken)
  44. {
  45. if (item == null)
  46. {
  47. throw new ArgumentNullException();
  48. }
  49. if (string.IsNullOrEmpty(metadataFile))
  50. {
  51. throw new ArgumentNullException();
  52. }
  53. var settings = new XmlReaderSettings
  54. {
  55. CheckCharacters = false,
  56. IgnoreProcessingInstructions = true,
  57. IgnoreComments = true,
  58. ValidationType = ValidationType.None
  59. };
  60. Fetch(item, metadataFile, settings, cancellationToken);
  61. }
  62. /// <summary>
  63. /// Fetches the specified item.
  64. /// </summary>
  65. /// <param name="item">The item.</param>
  66. /// <param name="metadataFile">The metadata file.</param>
  67. /// <param name="settings">The settings.</param>
  68. /// <param name="cancellationToken">The cancellation token.</param>
  69. private void Fetch(T item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken)
  70. {
  71. using (var streamReader = BaseNfoSaver.GetStreamReader(metadataFile))
  72. {
  73. // Use XmlReader for best performance
  74. using (var reader = XmlReader.Create(streamReader, settings))
  75. {
  76. reader.MoveToContent();
  77. // Loop through each element
  78. while (reader.Read())
  79. {
  80. cancellationToken.ThrowIfCancellationRequested();
  81. if (reader.NodeType == XmlNodeType.Element)
  82. {
  83. FetchDataFromXmlNode(reader, item);
  84. }
  85. }
  86. }
  87. }
  88. }
  89. protected virtual void FetchDataFromXmlNode(XmlReader reader, T item)
  90. {
  91. switch (reader.Name)
  92. {
  93. // DateCreated
  94. case "dateadded":
  95. {
  96. var val = reader.ReadElementContentAsString();
  97. if (!string.IsNullOrWhiteSpace(val))
  98. {
  99. DateTime added;
  100. if (DateTime.TryParse(val, out added))
  101. {
  102. item.DateCreated = added.ToUniversalTime();
  103. }
  104. else
  105. {
  106. Logger.Warn("Invalid Added value found: " + val);
  107. }
  108. }
  109. break;
  110. }
  111. case "title":
  112. case "localtitle":
  113. item.Name = reader.ReadElementContentAsString();
  114. break;
  115. case "criticrating":
  116. {
  117. var text = reader.ReadElementContentAsString();
  118. var hasCriticRating = item as IHasCriticRating;
  119. if (hasCriticRating != null && !string.IsNullOrEmpty(text))
  120. {
  121. float value;
  122. if (float.TryParse(text, NumberStyles.Any, _usCulture, out value))
  123. {
  124. hasCriticRating.CriticRating = value;
  125. }
  126. }
  127. break;
  128. }
  129. case "budget":
  130. {
  131. var text = reader.ReadElementContentAsString();
  132. var hasBudget = item as IHasBudget;
  133. if (hasBudget != null)
  134. {
  135. double value;
  136. if (double.TryParse(text, NumberStyles.Any, _usCulture, out value))
  137. {
  138. hasBudget.Budget = value;
  139. }
  140. }
  141. break;
  142. }
  143. case "revenue":
  144. {
  145. var text = reader.ReadElementContentAsString();
  146. var hasBudget = item as IHasBudget;
  147. if (hasBudget != null)
  148. {
  149. double value;
  150. if (double.TryParse(text, NumberStyles.Any, _usCulture, out value))
  151. {
  152. hasBudget.Revenue = value;
  153. }
  154. }
  155. break;
  156. }
  157. case "metascore":
  158. {
  159. var text = reader.ReadElementContentAsString();
  160. var hasMetascore = item as IHasMetascore;
  161. if (hasMetascore != null)
  162. {
  163. float value;
  164. if (float.TryParse(text, NumberStyles.Any, _usCulture, out value))
  165. {
  166. hasMetascore.Metascore = value;
  167. }
  168. }
  169. break;
  170. }
  171. case "awardsummary":
  172. {
  173. var text = reader.ReadElementContentAsString();
  174. var hasAwards = item as IHasAwards;
  175. if (hasAwards != null)
  176. {
  177. if (!string.IsNullOrWhiteSpace(text))
  178. {
  179. hasAwards.AwardSummary = text;
  180. }
  181. }
  182. break;
  183. }
  184. case "sorttitle":
  185. {
  186. var val = reader.ReadElementContentAsString();
  187. if (!string.IsNullOrWhiteSpace(val))
  188. {
  189. item.ForcedSortName = val;
  190. }
  191. break;
  192. }
  193. case "outline":
  194. {
  195. var val = reader.ReadElementContentAsString();
  196. if (!string.IsNullOrWhiteSpace(val))
  197. {
  198. var hasShortOverview = item as IHasShortOverview;
  199. if (hasShortOverview != null)
  200. {
  201. hasShortOverview.ShortOverview = val;
  202. }
  203. }
  204. break;
  205. }
  206. case "biography":
  207. case "plot":
  208. case "review":
  209. {
  210. var val = reader.ReadElementContentAsString();
  211. if (!string.IsNullOrWhiteSpace(val))
  212. {
  213. item.Overview = val;
  214. }
  215. break;
  216. }
  217. case "criticratingsummary":
  218. {
  219. var val = reader.ReadElementContentAsString();
  220. if (!string.IsNullOrWhiteSpace(val))
  221. {
  222. var hasCriticRating = item as IHasCriticRating;
  223. if (hasCriticRating != null)
  224. {
  225. hasCriticRating.CriticRatingSummary = val;
  226. }
  227. }
  228. break;
  229. }
  230. case "language":
  231. {
  232. var val = reader.ReadElementContentAsString();
  233. var hasLanguage = item as IHasPreferredMetadataLanguage;
  234. if (hasLanguage != null)
  235. {
  236. hasLanguage.PreferredMetadataLanguage = val;
  237. }
  238. break;
  239. }
  240. case "website":
  241. {
  242. var val = reader.ReadElementContentAsString();
  243. if (!string.IsNullOrWhiteSpace(val))
  244. {
  245. item.HomePageUrl = val;
  246. }
  247. break;
  248. }
  249. case "lockedfields":
  250. {
  251. var fields = new List<MetadataFields>();
  252. var val = reader.ReadElementContentAsString();
  253. if (!string.IsNullOrWhiteSpace(val))
  254. {
  255. var list = val.Split('|').Select(i =>
  256. {
  257. MetadataFields field;
  258. if (Enum.TryParse<MetadataFields>(i, true, out field))
  259. {
  260. return (MetadataFields?)field;
  261. }
  262. return null;
  263. }).Where(i => i.HasValue).Select(i => i.Value);
  264. fields.AddRange(list);
  265. }
  266. item.LockedFields = fields;
  267. break;
  268. }
  269. case "tagline":
  270. {
  271. var val = reader.ReadElementContentAsString();
  272. var hasTagline = item as IHasTaglines;
  273. if (hasTagline != null)
  274. {
  275. if (!string.IsNullOrWhiteSpace(val))
  276. {
  277. hasTagline.AddTagline(val);
  278. }
  279. }
  280. break;
  281. }
  282. case "country":
  283. {
  284. var val = reader.ReadElementContentAsString();
  285. var hasProductionLocations = item as IHasProductionLocations;
  286. if (hasProductionLocations != null)
  287. {
  288. if (!string.IsNullOrWhiteSpace(val))
  289. {
  290. var parts = val.Split('/')
  291. .Select(i => i.Trim())
  292. .Where(i => !string.IsNullOrWhiteSpace(i));
  293. foreach (var p in parts)
  294. {
  295. hasProductionLocations.AddProductionLocation(p);
  296. }
  297. }
  298. }
  299. break;
  300. }
  301. case "mpaa":
  302. {
  303. var rating = reader.ReadElementContentAsString();
  304. if (!string.IsNullOrWhiteSpace(rating))
  305. {
  306. item.OfficialRating = rating;
  307. }
  308. break;
  309. }
  310. case "mpaadescription":
  311. {
  312. var rating = reader.ReadElementContentAsString();
  313. if (!string.IsNullOrWhiteSpace(rating))
  314. {
  315. item.OfficialRatingDescription = rating;
  316. }
  317. break;
  318. }
  319. case "customrating":
  320. {
  321. var val = reader.ReadElementContentAsString();
  322. if (!string.IsNullOrWhiteSpace(val))
  323. {
  324. item.CustomRating = val;
  325. }
  326. break;
  327. }
  328. case "runtime":
  329. {
  330. var text = reader.ReadElementContentAsString();
  331. if (!string.IsNullOrWhiteSpace(text))
  332. {
  333. int runtime;
  334. if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, _usCulture, out runtime))
  335. {
  336. item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
  337. }
  338. }
  339. break;
  340. }
  341. case "aspectratio":
  342. {
  343. var val = reader.ReadElementContentAsString();
  344. var hasAspectRatio = item as IHasAspectRatio;
  345. if (!string.IsNullOrWhiteSpace(val) && hasAspectRatio != null)
  346. {
  347. hasAspectRatio.AspectRatio = val;
  348. }
  349. break;
  350. }
  351. case "lockdata":
  352. {
  353. var val = reader.ReadElementContentAsString();
  354. if (!string.IsNullOrWhiteSpace(val))
  355. {
  356. item.IsLocked = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
  357. }
  358. break;
  359. }
  360. case "studio":
  361. {
  362. var val = reader.ReadElementContentAsString();
  363. if (!string.IsNullOrWhiteSpace(val))
  364. {
  365. var parts = val.Split('/')
  366. .Select(i => i.Trim())
  367. .Where(i => !string.IsNullOrWhiteSpace(i));
  368. foreach (var p in parts)
  369. {
  370. item.AddStudio(p);
  371. }
  372. }
  373. break;
  374. }
  375. case "director":
  376. {
  377. foreach (var p in SplitNames(reader.ReadElementContentAsString()).Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Director }))
  378. {
  379. if (string.IsNullOrWhiteSpace(p.Name))
  380. {
  381. continue;
  382. }
  383. item.AddPerson(p);
  384. }
  385. break;
  386. }
  387. case "credits":
  388. {
  389. var val = reader.ReadElementContentAsString();
  390. if (!string.IsNullOrWhiteSpace(val))
  391. {
  392. var parts = val.Split('/').Select(i => i.Trim())
  393. .Where(i => !string.IsNullOrEmpty(i));
  394. foreach (var p in parts.Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Writer }))
  395. {
  396. if (string.IsNullOrWhiteSpace(p.Name))
  397. {
  398. continue;
  399. }
  400. item.AddPerson(p);
  401. }
  402. }
  403. break;
  404. }
  405. case "writer":
  406. {
  407. foreach (var p in SplitNames(reader.ReadElementContentAsString()).Select(v => new PersonInfo { Name = v.Trim(), Type = PersonType.Writer }))
  408. {
  409. if (string.IsNullOrWhiteSpace(p.Name))
  410. {
  411. continue;
  412. }
  413. item.AddPerson(p);
  414. }
  415. break;
  416. }
  417. case "actor":
  418. {
  419. using (var subtree = reader.ReadSubtree())
  420. {
  421. var person = GetPersonFromXmlNode(subtree);
  422. item.AddPerson(person);
  423. }
  424. break;
  425. }
  426. case "trailer":
  427. {
  428. var val = reader.ReadElementContentAsString();
  429. var hasTrailer = item as IHasTrailers;
  430. if (hasTrailer != null)
  431. {
  432. if (!string.IsNullOrWhiteSpace(val))
  433. {
  434. hasTrailer.AddTrailerUrl(val, false);
  435. }
  436. }
  437. break;
  438. }
  439. case "displayorder":
  440. {
  441. var val = reader.ReadElementContentAsString();
  442. var hasDisplayOrder = item as IHasDisplayOrder;
  443. if (hasDisplayOrder != null)
  444. {
  445. if (!string.IsNullOrWhiteSpace(val))
  446. {
  447. hasDisplayOrder.DisplayOrder = val;
  448. }
  449. }
  450. break;
  451. }
  452. case "year":
  453. {
  454. var val = reader.ReadElementContentAsString();
  455. if (!string.IsNullOrWhiteSpace(val))
  456. {
  457. int productionYear;
  458. if (int.TryParse(val, out productionYear) && productionYear > 1850)
  459. {
  460. item.ProductionYear = productionYear;
  461. }
  462. }
  463. break;
  464. }
  465. case "rating":
  466. {
  467. var rating = reader.ReadElementContentAsString();
  468. if (!string.IsNullOrWhiteSpace(rating))
  469. {
  470. float val;
  471. // All external meta is saving this as '.' for decimal I believe...but just to be sure
  472. if (float.TryParse(rating.Replace(',', '.'), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out val))
  473. {
  474. item.CommunityRating = val;
  475. }
  476. }
  477. break;
  478. }
  479. case "aired":
  480. case "formed":
  481. case "premiered":
  482. case "releasedate":
  483. {
  484. var formatString = _config.GetNfoConfiguration().ReleaseDateFormat;
  485. var val = reader.ReadElementContentAsString();
  486. if (!string.IsNullOrWhiteSpace(val))
  487. {
  488. DateTime date;
  489. if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out date) && date.Year > 1850)
  490. {
  491. item.PremiereDate = date.ToUniversalTime();
  492. item.ProductionYear = date.Year;
  493. }
  494. }
  495. break;
  496. }
  497. case "enddate":
  498. {
  499. var formatString = _config.GetNfoConfiguration().ReleaseDateFormat;
  500. var val = reader.ReadElementContentAsString();
  501. if (!string.IsNullOrWhiteSpace(val))
  502. {
  503. DateTime date;
  504. if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out date) && date.Year > 1850)
  505. {
  506. item.EndDate = date.ToUniversalTime();
  507. }
  508. }
  509. break;
  510. }
  511. case "tvdbid":
  512. var tvdbId = reader.ReadElementContentAsString();
  513. if (!string.IsNullOrWhiteSpace(tvdbId))
  514. {
  515. item.SetProviderId(MetadataProviders.Tvdb, tvdbId);
  516. }
  517. break;
  518. case "votes":
  519. {
  520. var val = reader.ReadElementContentAsString();
  521. if (!string.IsNullOrWhiteSpace(val))
  522. {
  523. int num;
  524. if (int.TryParse(val, NumberStyles.Integer, _usCulture, out num))
  525. {
  526. item.VoteCount = num;
  527. }
  528. }
  529. break;
  530. }
  531. case "musicbrainzalbumid":
  532. {
  533. var mbz = reader.ReadElementContentAsString();
  534. if (!string.IsNullOrWhiteSpace(mbz))
  535. {
  536. item.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbz);
  537. }
  538. break;
  539. }
  540. case "musicbrainzalbumartistid":
  541. {
  542. var mbz = reader.ReadElementContentAsString();
  543. if (!string.IsNullOrWhiteSpace(mbz))
  544. {
  545. item.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, mbz);
  546. }
  547. break;
  548. }
  549. case "musicbrainzartistid":
  550. {
  551. var mbz = reader.ReadElementContentAsString();
  552. if (!string.IsNullOrWhiteSpace(mbz))
  553. {
  554. item.SetProviderId(MetadataProviders.MusicBrainzArtist, mbz);
  555. }
  556. break;
  557. }
  558. case "musicbrainzreleasegroupid":
  559. {
  560. var mbz = reader.ReadElementContentAsString();
  561. if (!string.IsNullOrWhiteSpace(mbz))
  562. {
  563. item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, mbz);
  564. }
  565. break;
  566. }
  567. case "tvrageid":
  568. {
  569. var id = reader.ReadElementContentAsString();
  570. if (!string.IsNullOrWhiteSpace(id))
  571. {
  572. item.SetProviderId(MetadataProviders.TvRage, id);
  573. }
  574. break;
  575. }
  576. case "audiodbartistid":
  577. {
  578. var id = reader.ReadElementContentAsString();
  579. if (!string.IsNullOrWhiteSpace(id))
  580. {
  581. item.SetProviderId(MetadataProviders.AudioDbArtist, id);
  582. }
  583. break;
  584. }
  585. case "audiodbalbumid":
  586. {
  587. var id = reader.ReadElementContentAsString();
  588. if (!string.IsNullOrWhiteSpace(id))
  589. {
  590. item.SetProviderId(MetadataProviders.AudioDbAlbum, id);
  591. }
  592. break;
  593. }
  594. case "rottentomatoesid":
  595. var rtId = reader.ReadElementContentAsString();
  596. if (!string.IsNullOrWhiteSpace(rtId))
  597. {
  598. item.SetProviderId(MetadataProviders.RottenTomatoes, rtId);
  599. }
  600. break;
  601. case "tmdbid":
  602. var tmdb = reader.ReadElementContentAsString();
  603. if (!string.IsNullOrWhiteSpace(tmdb))
  604. {
  605. item.SetProviderId(MetadataProviders.Tmdb, tmdb);
  606. }
  607. break;
  608. case "collectionnumber":
  609. var tmdbCollection = reader.ReadElementContentAsString();
  610. if (!string.IsNullOrWhiteSpace(tmdbCollection))
  611. {
  612. item.SetProviderId(MetadataProviders.TmdbCollection, tmdbCollection);
  613. }
  614. break;
  615. case "tvcomid":
  616. var TVcomId = reader.ReadElementContentAsString();
  617. if (!string.IsNullOrWhiteSpace(TVcomId))
  618. {
  619. item.SetProviderId(MetadataProviders.Tvcom, TVcomId);
  620. }
  621. break;
  622. case "zap2itid":
  623. var zap2ItId = reader.ReadElementContentAsString();
  624. if (!string.IsNullOrWhiteSpace(zap2ItId))
  625. {
  626. item.SetProviderId(MetadataProviders.Zap2It, zap2ItId);
  627. }
  628. break;
  629. case "imdb_id":
  630. case "imdbid":
  631. var imDbId = reader.ReadElementContentAsString();
  632. if (!string.IsNullOrWhiteSpace(imDbId))
  633. {
  634. item.SetProviderId(MetadataProviders.Imdb, imDbId);
  635. }
  636. break;
  637. case "genre":
  638. {
  639. var val = reader.ReadElementContentAsString();
  640. if (!string.IsNullOrWhiteSpace(val))
  641. {
  642. var parts = val.Split('/')
  643. .Select(i => i.Trim())
  644. .Where(i => !string.IsNullOrWhiteSpace(i));
  645. foreach (var p in parts)
  646. {
  647. item.AddGenre(p);
  648. }
  649. }
  650. break;
  651. }
  652. case "style":
  653. case "tag":
  654. {
  655. var val = reader.ReadElementContentAsString();
  656. if (!string.IsNullOrWhiteSpace(val))
  657. {
  658. var hasTags = item as IHasTags;
  659. if (hasTags != null)
  660. {
  661. hasTags.AddTag(val);
  662. }
  663. }
  664. break;
  665. }
  666. case "plotkeyword":
  667. {
  668. var val = reader.ReadElementContentAsString();
  669. var hasKeywords = item as IHasKeywords;
  670. if (hasKeywords != null)
  671. {
  672. if (!string.IsNullOrWhiteSpace(val))
  673. {
  674. hasKeywords.AddKeyword(val);
  675. }
  676. }
  677. break;
  678. }
  679. case "fileinfo":
  680. {
  681. using (var subtree = reader.ReadSubtree())
  682. {
  683. FetchFromFileInfoNode(subtree, item);
  684. }
  685. break;
  686. }
  687. default:
  688. reader.Skip();
  689. break;
  690. }
  691. }
  692. private void FetchFromFileInfoNode(XmlReader reader, T item)
  693. {
  694. reader.MoveToContent();
  695. while (reader.Read())
  696. {
  697. if (reader.NodeType == XmlNodeType.Element)
  698. {
  699. switch (reader.Name)
  700. {
  701. case "streamdetails":
  702. {
  703. using (var subtree = reader.ReadSubtree())
  704. {
  705. FetchFromStreamDetailsNode(subtree, item);
  706. }
  707. break;
  708. }
  709. default:
  710. reader.Skip();
  711. break;
  712. }
  713. }
  714. }
  715. }
  716. private void FetchFromStreamDetailsNode(XmlReader reader, T item)
  717. {
  718. reader.MoveToContent();
  719. while (reader.Read())
  720. {
  721. if (reader.NodeType == XmlNodeType.Element)
  722. {
  723. switch (reader.Name)
  724. {
  725. case "video":
  726. {
  727. using (var subtree = reader.ReadSubtree())
  728. {
  729. FetchFromVideoNode(subtree, item);
  730. }
  731. break;
  732. }
  733. default:
  734. reader.Skip();
  735. break;
  736. }
  737. }
  738. }
  739. }
  740. private void FetchFromVideoNode(XmlReader reader, T item)
  741. {
  742. reader.MoveToContent();
  743. while (reader.Read())
  744. {
  745. if (reader.NodeType == XmlNodeType.Element)
  746. {
  747. switch (reader.Name)
  748. {
  749. case "format3d":
  750. {
  751. var video = item as Video;
  752. if (video != null)
  753. {
  754. var val = reader.ReadElementContentAsString();
  755. if (string.Equals("HSBS", val, StringComparison.CurrentCulture))
  756. {
  757. video.Video3DFormat = Video3DFormat.HalfSideBySide;
  758. }
  759. else if (string.Equals("HTAB", val, StringComparison.CurrentCulture))
  760. {
  761. video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
  762. }
  763. else if (string.Equals("FTAB", val, StringComparison.CurrentCulture))
  764. {
  765. video.Video3DFormat = Video3DFormat.FullTopAndBottom;
  766. }
  767. else if (string.Equals("FSBS", val, StringComparison.CurrentCulture))
  768. {
  769. video.Video3DFormat = Video3DFormat.FullSideBySide;
  770. }
  771. }
  772. break;
  773. }
  774. default:
  775. reader.Skip();
  776. break;
  777. }
  778. }
  779. }
  780. }
  781. /// <summary>
  782. /// Gets the persons from XML node.
  783. /// </summary>
  784. /// <param name="reader">The reader.</param>
  785. /// <returns>IEnumerable{PersonInfo}.</returns>
  786. private PersonInfo GetPersonFromXmlNode(XmlReader reader)
  787. {
  788. var name = string.Empty;
  789. var type = PersonType.Actor; // If type is not specified assume actor
  790. var role = string.Empty;
  791. int? sortOrder = null;
  792. reader.MoveToContent();
  793. while (reader.Read())
  794. {
  795. if (reader.NodeType == XmlNodeType.Element)
  796. {
  797. switch (reader.Name)
  798. {
  799. case "name":
  800. name = reader.ReadElementContentAsString() ?? string.Empty;
  801. break;
  802. case "type":
  803. {
  804. var val = reader.ReadElementContentAsString();
  805. if (!string.IsNullOrWhiteSpace(val))
  806. {
  807. type = val;
  808. }
  809. break;
  810. }
  811. case "role":
  812. {
  813. var val = reader.ReadElementContentAsString();
  814. if (!string.IsNullOrWhiteSpace(val))
  815. {
  816. role = val;
  817. }
  818. break;
  819. }
  820. case "sortorder":
  821. {
  822. var val = reader.ReadElementContentAsString();
  823. if (!string.IsNullOrWhiteSpace(val))
  824. {
  825. int intVal;
  826. if (int.TryParse(val, NumberStyles.Integer, _usCulture, out intVal))
  827. {
  828. sortOrder = intVal;
  829. }
  830. }
  831. break;
  832. }
  833. default:
  834. reader.Skip();
  835. break;
  836. }
  837. }
  838. }
  839. return new PersonInfo
  840. {
  841. Name = name.Trim(),
  842. Role = role,
  843. Type = type,
  844. SortOrder = sortOrder
  845. };
  846. }
  847. /// <summary>
  848. /// Used to split names of comma or pipe delimeted genres and people
  849. /// </summary>
  850. /// <param name="value">The value.</param>
  851. /// <returns>IEnumerable{System.String}.</returns>
  852. private IEnumerable<string> SplitNames(string value)
  853. {
  854. value = value ?? string.Empty;
  855. // Only split by comma if there is no pipe in the string
  856. // We have to be careful to not split names like Matthew, Jr.
  857. var separator = value.IndexOf('|') == -1 && value.IndexOf(';') == -1 ? new[] { ',' } : new[] { '|', ';' };
  858. value = value.Trim().Trim(separator);
  859. return string.IsNullOrWhiteSpace(value) ? new string[] { } : Split(value, separator, StringSplitOptions.RemoveEmptyEntries);
  860. }
  861. /// <summary>
  862. /// Provides an additional overload for string.split
  863. /// </summary>
  864. /// <param name="val">The val.</param>
  865. /// <param name="separators">The separators.</param>
  866. /// <param name="options">The options.</param>
  867. /// <returns>System.String[][].</returns>
  868. private static string[] Split(string val, char[] separators, StringSplitOptions options)
  869. {
  870. return val.Split(separators, options);
  871. }
  872. }
  873. }