diff --git a/MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs b/MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs
new file mode 100644
index 0000000000..cd7db91dd4
--- /dev/null
+++ b/MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Globalization;
+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
+ };
+ }
+}
diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
index cb369d8377..df4d40a100 100644
--- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
@@ -9,6 +9,7 @@ using System.Xml;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -929,29 +930,13 @@ namespace MediaBrowser.LocalMetadata.Parsers
{
case "Person":
case "Actor":
- {
- if (reader.IsEmptyElement)
+ var person = reader.GetPersonFromXmlNode();
+ if (person is not null)
{
- reader.Read();
- continue;
- }
-
- using (var subtree = reader.ReadSubtree())
- {
- foreach (var person in GetPersonsFromXmlNode(subtree))
- {
- if (string.IsNullOrWhiteSpace(person.Name))
- {
- continue;
- }
-
- item.AddPerson(person);
- }
+ item.AddPerson(person);
}
break;
- }
-
default:
reader.Skip();
break;
@@ -1041,83 +1026,6 @@ namespace MediaBrowser.LocalMetadata.Parsers
}
}
- ///
- /// Gets the persons from XML node.
- ///
- /// The reader.
- /// IEnumerable{PersonInfo}.
- private IEnumerable GetPersonsFromXmlNode(XmlReader reader)
- {
- var name = string.Empty;
- var type = PersonKind.Actor; // If type is not specified assume actor
- var role = string.Empty;
- int? sortOrder = null;
-
- reader.MoveToContent();
- reader.Read();
-
- // Loop through each element
- while (!reader.EOF && reader.ReadState == ReadState.Interactive)
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "Name":
- name = reader.ReadElementContentAsString();
- break;
-
- case "Type":
- {
- var val = reader.ReadElementContentAsString();
- _ = Enum.TryParse(val, true, out type);
-
- break;
- }
-
- case "Role":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- role = val;
- }
-
- break;
- }
-
- case "SortOrder":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intVal))
- {
- sortOrder = intVal;
- }
- }
-
- break;
- }
-
- default:
- reader.Skip();
- break;
- }
- }
- else
- {
- reader.Read();
- }
- }
-
- var personInfo = new PersonInfo { Name = name.Trim(), Role = role, Type = type, SortOrder = sortOrder };
-
- return new[] { personInfo };
- }
-
///
/// Get linked child.
///
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index 5b68924acb..e11378c786 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -13,6 +13,7 @@ using MediaBrowser.Common.Providers;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -581,27 +582,13 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
case "actor":
+ var person = reader.GetPersonFromXmlNode();
+ if (person is not null)
{
- if (!reader.IsEmptyElement)
- {
- using (var subtree = reader.ReadSubtree())
- {
- var person = GetPersonFromXmlNode(subtree);
-
- if (!string.IsNullOrWhiteSpace(person.Name))
- {
- itemResult.AddPerson(person);
- }
- }
- }
- else
- {
- reader.Read();
- }
-
- break;
+ itemResult.AddPerson(person);
}
+ break;
case "trailer":
{
var val = reader.ReadElementContentAsString();
@@ -1196,102 +1183,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
}
- ///
- /// Gets the persons from a XML node.
- ///
- /// The .
- /// IEnumerable{PersonInfo}.
- private PersonInfo GetPersonFromXmlNode(XmlReader reader)
- {
- 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;
-
- reader.MoveToContent();
- reader.Read();
-
- // Loop through each element
- while (!reader.EOF && reader.ReadState == ReadState.Interactive)
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- switch (reader.Name)
- {
- case "name":
- name = reader.ReadElementContentAsString();
- break;
-
- case "role":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- role = val;
- }
-
- break;
- }
-
- case "type":
- {
- var val = reader.ReadElementContentAsString();
- if (!Enum.TryParse(val, true, out type))
- {
- type = PersonKind.Actor;
- }
-
- break;
- }
-
- case "order":
- case "sortorder":
- {
- var val = reader.ReadElementContentAsString();
-
- if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intVal))
- {
- sortOrder = intVal;
- }
-
- break;
- }
-
- case "thumb":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- imageUrl = val;
- }
-
- break;
- }
-
- default:
- reader.Skip();
- break;
- }
- }
- else
- {
- reader.Read();
- }
- }
-
- return new PersonInfo
- {
- Name = name.Trim(),
- Role = role,
- Type = type,
- SortOrder = sortOrder,
- ImageUrl = imageUrl
- };
- }
-
internal XmlReaderSettings GetXmlReaderSettings()
=> new XmlReaderSettings()
{