using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Xml; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Extensions; /// /// Provides extension methods for to parse 's. /// public static class XmlReaderExtensions { /// /// Parses a from the xml node. /// /// The . /// A , or null if none is found. public static PersonInfo? GetPersonFromXmlNode(this XmlReader reader) { ArgumentNullException.ThrowIfNull(reader); if (reader.IsEmptyElement) { reader.Read(); return null; } var name = string.Empty; var type = PersonKind.Actor; // If type is not specified assume actor var role = string.Empty; int? sortOrder = null; string? imageUrl = null; using var subtree = reader.ReadSubtree(); subtree.MoveToContent(); subtree.Read(); while (subtree is { EOF: false, ReadState: ReadState.Interactive }) { if (subtree.NodeType != XmlNodeType.Element) { subtree.Read(); continue; } switch (subtree.Name) { case "name": case "Name": name = subtree.ReadElementContentAsString(); break; case "role": case "Role": var roleValue = subtree.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(roleValue)) { role = roleValue; } break; case "type": case "Type": Enum.TryParse(subtree.ReadElementContentAsString(), true, out type); break; case "order": case "sortorder": case "SortOrder": if (int.TryParse( subtree.ReadElementContentAsString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var intVal)) { sortOrder = intVal; } break; case "thumb": var thumb = subtree.ReadElementContentAsString(); if (!string.IsNullOrWhiteSpace(thumb)) { imageUrl = thumb; } break; default: subtree.Skip(); break; } } if (string.IsNullOrWhiteSpace(name)) { return null; } return new PersonInfo { Name = name.Trim(), Role = role, Type = type, SortOrder = sortOrder, ImageUrl = imageUrl }; } /// /// Used to split names of comma or pipe delimited genres and people. /// /// The . /// IEnumerable{System.String}. public static IEnumerable GetStringArray(this XmlReader reader) { ArgumentNullException.ThrowIfNull(reader); var value = reader.ReadElementContentAsString(); // Only split by comma if there is no pipe in the string // We have to be careful to not split names like Matthew, Jr. var separator = !value.Contains('|', StringComparison.Ordinal) && !value.Contains(';', StringComparison.Ordinal) ? new[] { ',' } : new[] { '|', ';' }; foreach (var part in value.Trim().Trim(separator).Split(separator)) { if (!string.IsNullOrWhiteSpace(part)) { yield return part.Trim(); } } } /// /// Parses a array from the xml node. /// /// The . /// The . /// The . public static IEnumerable GetPersonArray(this XmlReader reader, PersonKind personKind) => reader.GetStringArray() .Select(part => new PersonInfo { Name = part, Type = personKind }); }