diff options
| author | Cody Robibero <cody@robibe.ro> | 2023-10-10 15:58:51 -0600 |
|---|---|---|
| committer | Cody Robibero <cody@robibe.ro> | 2023-10-10 15:59:34 -0600 |
| commit | 6bd6fb6e0a4828cc5cb16a4e48a8fba20a7d6305 (patch) | |
| tree | 208e41ce44cb66107843dd2fdb80cbe673bc1240 /MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs | |
| parent | bc88c96cbe13301ee6e5f6a2d688a4c90338281d (diff) | |
| parent | 74f61fbd79ef2e2ad4a986f5f886581b2827de07 (diff) | |
Merge branch 'master' into chromecast-config
# Conflicts:
# Emby.Server.Implementations/ApplicationHost.cs
Diffstat (limited to 'MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs')
| -rw-r--r-- | MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs b/MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs new file mode 100644 index 000000000..2742f21e3 --- /dev/null +++ b/MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs @@ -0,0 +1,193 @@ +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; + +/// <summary> +/// Provides extension methods for <see cref="XmlReader"/> to parse <see cref="BaseItem"/>'s. +/// </summary> +public static class XmlReaderExtensions +{ + /// <summary> + /// Reads a trimmed string from the current node. + /// </summary> + /// <param name="reader">The <see cref="XmlReader"/>.</param> + /// <returns>The trimmed content.</returns> + public static string ReadNormalizedString(this XmlReader reader) + { + ArgumentNullException.ThrowIfNull(reader); + + return reader.ReadElementContentAsString().Trim(); + } + + /// <summary> + /// Reads an int from the current node. + /// </summary> + /// <param name="reader">The <see cref="XmlReader"/>.</param> + /// <param name="value">The parsed <c>int</c>.</param> + /// <returns>A value indicating whether the parsing succeeded.</returns> + public static bool TryReadInt(this XmlReader reader, out int value) + { + ArgumentNullException.ThrowIfNull(reader); + + return int.TryParse(reader.ReadElementContentAsString(), CultureInfo.InvariantCulture, out value); + } + + /// <summary> + /// Parses a <see cref="DateTime"/> from the current node. + /// </summary> + /// <param name="reader">The <see cref="XmlReader"/>.</param> + /// <param name="value">The parsed <see cref="DateTime"/>.</param> + /// <returns>A value indicating whether the parsing succeeded.</returns> + public static bool TryReadDateTime(this XmlReader reader, out DateTime value) + { + ArgumentNullException.ThrowIfNull(reader); + + return DateTime.TryParse( + reader.ReadElementContentAsString(), + CultureInfo.InvariantCulture, + DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, + out value); + } + + /// <summary> + /// Parses a <see cref="DateTime"/> from the current node. + /// </summary> + /// <param name="reader">The <see cref="XmlReader"/>.</param> + /// <param name="formatString">The date format string.</param> + /// <param name="value">The parsed <see cref="DateTime"/>.</param> + /// <returns>A value indicating whether the parsing succeeded.</returns> + public static bool TryReadDateTimeExact(this XmlReader reader, string formatString, out DateTime value) + { + ArgumentNullException.ThrowIfNull(reader); + ArgumentNullException.ThrowIfNull(formatString); + + return DateTime.TryParseExact( + reader.ReadElementContentAsString(), + formatString, + CultureInfo.InvariantCulture, + DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, + out value); + } + + /// <summary> + /// Parses a <see cref="PersonInfo"/> from the xml node. + /// </summary> + /// <param name="reader">The <see cref="XmlReader"/>.</param> + /// <returns>A <see cref="PersonInfo"/>, or <c>null</c> if none is found.</returns> + 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.ReadNormalizedString(); + break; + case "role": + case "Role": + role = subtree.ReadNormalizedString(); + break; + case "type": + case "Type": + Enum.TryParse(subtree.ReadElementContentAsString(), true, out type); + break; + case "order": + case "sortorder": + case "SortOrder": + if (subtree.TryReadInt(out var sortOrderVal)) + { + sortOrder = sortOrderVal; + } + + break; + case "thumb": + imageUrl = subtree.ReadNormalizedString(); + break; + default: + subtree.Skip(); + break; + } + } + + if (string.IsNullOrWhiteSpace(name)) + { + return null; + } + + return new PersonInfo + { + Name = name, + Role = role, + Type = type, + SortOrder = sortOrder, + ImageUrl = imageUrl + }; + } + + /// <summary> + /// Used to split names of comma or pipe delimited genres and people. + /// </summary> + /// <param name="reader">The <see cref="XmlReader"/>.</param> + /// <returns>IEnumerable{System.String}.</returns> + public static IEnumerable<string> 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(); + } + } + } + + /// <summary> + /// Parses a <see cref="PersonInfo"/> array from the xml node. + /// </summary> + /// <param name="reader">The <see cref="XmlReader"/>.</param> + /// <param name="personKind">The <see cref="PersonKind"/>.</param> + /// <returns>The <see cref="IEnumerable{PersonInfo}"/>.</returns> + public static IEnumerable<PersonInfo> GetPersonArray(this XmlReader reader, PersonKind personKind) + => reader.GetStringArray() + .Select(part => new PersonInfo { Name = part, Type = personKind }); +} |
