aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.XbmcMetadata
diff options
context:
space:
mode:
authorStepan Goremykin <goremukin@gmail.com>2023-10-12 20:11:16 +0200
committerStepan Goremykin <goremukin@gmail.com>2023-10-12 20:11:16 +0200
commit8d7e4229ca694d8222cd7b97519b63a5c79f770b (patch)
tree81def03b33fb5bb737467c2f92a289e17fb9a53d /MediaBrowser.XbmcMetadata
parent96c3bde3463ad0457d894ed532093ed28e868ba8 (diff)
parent075b828cbf42804439fd847b5ae3701061906fda (diff)
Merge branch 'master' into fix-resharper-warnings
# Conflicts: # Emby.Server.Implementations/Net/SocketFactory.cs # RSSDP/SsdpCommunicationsServer.cs # RSSDP/SsdpDeviceLocator.cs # RSSDP/SsdpDevicePublisher.cs
Diffstat (limited to 'MediaBrowser.XbmcMetadata')
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs859
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs175
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs29
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs29
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs21
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs4
6 files changed, 325 insertions, 792 deletions
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index af01b8be2..70e5b66c1 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;
@@ -261,158 +262,84 @@ namespace MediaBrowser.XbmcMetadata.Parsers
protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult<T> itemResult)
{
var item = itemResult.Item;
-
var nfoConfiguration = _config.GetNfoConfiguration();
- UserItemData? userData = null;
+ UserItemData? userData;
switch (reader.Name)
{
- // DateCreated
case "dateadded":
+ if (reader.TryReadDateTime(out var dateCreated))
{
- var val = reader.ReadElementContentAsString();
-
- if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var added))
- {
- item.DateCreated = added;
- }
- else
- {
- Logger.LogWarning("Invalid Added value found: {Value}", val);
- }
-
- break;
+ item.DateCreated = dateCreated;
}
+ break;
case "originaltitle":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrEmpty(val))
- {
- item.OriginalTitle = val;
- }
-
- break;
- }
-
+ item.OriginalTitle = reader.ReadNormalizedString();
+ break;
case "name":
case "title":
case "localtitle":
- item.Name = reader.ReadElementContentAsString();
+ item.Name = reader.ReadNormalizedString();
break;
-
case "sortname":
- item.SortName = reader.ReadElementContentAsString();
+ item.SortName = reader.ReadNormalizedString();
break;
-
case "criticrating":
+ var criticRatingText = reader.ReadElementContentAsString();
+ if (float.TryParse(criticRatingText, CultureInfo.InvariantCulture, out var value))
{
- var text = reader.ReadElementContentAsString();
-
- if (float.TryParse(text, CultureInfo.InvariantCulture, out var value))
- {
- item.CriticRating = value;
- }
-
- break;
+ item.CriticRating = value;
}
+ break;
case "sorttitle":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.ForcedSortName = val;
- }
-
- break;
- }
-
+ item.ForcedSortName = reader.ReadNormalizedString();
+ break;
case "biography":
case "plot":
case "review":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.Overview = val;
- }
-
- break;
- }
-
+ item.Overview = reader.ReadNormalizedString();
+ break;
case "language":
- {
- var val = reader.ReadElementContentAsString();
-
- item.PreferredMetadataLanguage = val;
-
- break;
- }
-
+ item.PreferredMetadataLanguage = reader.ReadNormalizedString();
+ break;
case "watched":
+ var played = reader.ReadElementContentAsBoolean();
+ if (!string.IsNullOrWhiteSpace(nfoConfiguration.UserId))
{
- var val = reader.ReadElementContentAsBoolean();
-
- if (!string.IsNullOrWhiteSpace(nfoConfiguration.UserId))
- {
- var user = _userManager.GetUserById(Guid.Parse(nfoConfiguration.UserId));
- userData = _userDataManager.GetUserData(user, item);
- userData.Played = val;
- _userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
- }
-
- break;
+ var user = _userManager.GetUserById(Guid.Parse(nfoConfiguration.UserId));
+ userData = _userDataManager.GetUserData(user, item);
+ userData.Played = played;
+ _userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
}
+ break;
case "playcount":
+ if (reader.TryReadInt(out var count)
+ && Guid.TryParse(nfoConfiguration.UserId, out var playCountUserId))
{
- var val = reader.ReadElementContentAsString();
- if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var count)
- && Guid.TryParse(nfoConfiguration.UserId, out var guid))
- {
- var user = _userManager.GetUserById(guid);
- userData = _userDataManager.GetUserData(user, item);
- userData.PlayCount = count;
- _userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
- }
-
- break;
+ var user = _userManager.GetUserById(playCountUserId);
+ userData = _userDataManager.GetUserData(user, item);
+ userData.PlayCount = count;
+ _userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
}
+ break;
case "lastplayed":
+ if (reader.TryReadDateTime(out var lastPlayed)
+ && Guid.TryParse(nfoConfiguration.UserId, out var lastPlayedUserId))
{
- var val = reader.ReadElementContentAsString();
- if (Guid.TryParse(nfoConfiguration.UserId, out var guid))
- {
- if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var added))
- {
- var user = _userManager.GetUserById(guid);
- userData = _userDataManager.GetUserData(user, item);
- userData.LastPlayedDate = added;
- _userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
- }
- else
- {
- Logger.LogWarning("Invalid lastplayed value found: {Value}", val);
- }
- }
-
- break;
+ var user = _userManager.GetUserById(lastPlayedUserId);
+ userData = _userDataManager.GetUserData(user, item);
+ userData.LastPlayedDate = lastPlayed;
+ _userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
}
+ break;
case "countrycode":
- {
- var val = reader.ReadElementContentAsString();
-
- item.PreferredMetadataCountryCode = val;
-
- break;
- }
-
+ item.PreferredMetadataCountryCode = reader.ReadNormalizedString();
+ break;
case "lockedfields":
{
var val = reader.ReadElementContentAsString();
@@ -434,9 +361,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
case "tagline":
- item.Tagline = reader.ReadElementContentAsString();
+ item.Tagline = reader.ReadNormalizedString();
break;
-
case "country":
{
var val = reader.ReadElementContentAsString();
@@ -453,94 +379,45 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
case "mpaa":
- {
- var rating = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(rating))
- {
- item.OfficialRating = rating;
- }
-
- break;
- }
-
+ item.OfficialRating = reader.ReadNormalizedString();
+ break;
case "customrating":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.CustomRating = val;
- }
-
- break;
- }
-
+ item.CustomRating = reader.ReadNormalizedString();
+ break;
case "runtime":
+ var runtimeText = reader.ReadElementContentAsString();
+ if (int.TryParse(runtimeText.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime))
{
- var text = reader.ReadElementContentAsString();
-
- if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime))
- {
- item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
- }
-
- break;
+ item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
}
+ break;
case "aspectratio":
+ var aspectRatio = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(aspectRatio) && item is IHasAspectRatio hasAspectRatio)
{
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val)
- && item is IHasAspectRatio hasAspectRatio)
- {
- hasAspectRatio.AspectRatio = val;
- }
-
- break;
+ hasAspectRatio.AspectRatio = aspectRatio;
}
+ break;
case "lockdata":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.IsLocked = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
- }
-
- break;
- }
-
+ item.IsLocked = string.Equals(reader.ReadElementContentAsString(), "true", StringComparison.OrdinalIgnoreCase);
+ break;
case "studio":
+ var studio = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(studio))
{
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.AddStudio(val);
- }
-
- break;
+ item.AddStudio(studio);
}
+ break;
case "director":
+ foreach (var director in reader.GetPersonArray(PersonKind.Director))
{
- var val = reader.ReadElementContentAsString();
- foreach (var p in SplitNames(val).Select(v => new PersonInfo { Name = v.Trim(), Type = PersonKind.Director }))
- {
- if (string.IsNullOrWhiteSpace(p.Name))
- {
- continue;
- }
-
- itemResult.AddPerson(p);
- }
-
- break;
+ itemResult.AddPerson(director);
}
+ break;
case "credits":
{
var val = reader.ReadElementContentAsString();
@@ -565,141 +442,76 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
case "writer":
+ foreach (var writer in reader.GetPersonArray(PersonKind.Writer))
{
- var val = reader.ReadElementContentAsString();
- foreach (var p in SplitNames(val).Select(v => new PersonInfo { Name = v.Trim(), Type = PersonKind.Writer }))
- {
- if (string.IsNullOrWhiteSpace(p.Name))
- {
- continue;
- }
-
- itemResult.AddPerson(p);
- }
-
- break;
+ itemResult.AddPerson(writer);
}
+ break;
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 trailer = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(trailer))
{
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", BaseNfoSaver.YouTubeWatchUrl, StringComparison.OrdinalIgnoreCase);
-
- item.AddTrailerUrl(val);
- }
-
- break;
+ item.AddTrailerUrl(trailer.Replace(
+ "plugin://plugin.video.youtube/?action=play_video&videoid=",
+ BaseNfoSaver.YouTubeWatchUrl,
+ StringComparison.OrdinalIgnoreCase));
}
+ break;
case "displayorder":
+ var displayOrder = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(displayOrder) && item is IHasDisplayOrder hasDisplayOrder)
{
- var val = reader.ReadElementContentAsString();
-
- if (item is IHasDisplayOrder hasDisplayOrder && !string.IsNullOrWhiteSpace(val))
- {
- hasDisplayOrder.DisplayOrder = val;
- }
-
- break;
+ hasDisplayOrder.DisplayOrder = displayOrder;
}
+ break;
case "year":
+ if (reader.TryReadInt(out var productionYear) && productionYear > 1850)
{
- var val = reader.ReadElementContentAsString();
-
- if (int.TryParse(val, out var productionYear) && productionYear > 1850)
- {
- item.ProductionYear = productionYear;
- }
-
- break;
+ item.ProductionYear = productionYear;
}
+ break;
case "rating":
+ var rating = reader.ReadElementContentAsString().Replace(',', '.');
+ // All external meta is saving this as '.' for decimal I believe...but just to be sure
+ if (float.TryParse(rating, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var communityRating))
{
- var rating = reader.ReadElementContentAsString();
-
- // All external meta is saving this as '.' for decimal I believe...but just to be sure
- if (float.TryParse(rating.Replace(',', '.'), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var val))
- {
- item.CommunityRating = val;
- }
-
- break;
+ item.CommunityRating = communityRating;
}
+ break;
case "ratings":
- {
- if (!reader.IsEmptyElement)
- {
- using var subtree = reader.ReadSubtree();
- FetchFromRatingsNode(subtree, item);
- }
- else
- {
- reader.Read();
- }
-
- break;
- }
-
+ FetchFromRatingsNode(reader, item);
+ break;
case "aired":
case "formed":
case "premiered":
case "releasedate":
+ if (reader.TryReadDateTimeExact(nfoConfiguration.ReleaseDateFormat, out var releaseDate))
{
- var formatString = nfoConfiguration.ReleaseDateFormat;
-
- var val = reader.ReadElementContentAsString();
-
- if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var date) && date.Year > 1850)
- {
- item.PremiereDate = date;
- item.ProductionYear = date.Year;
- }
-
- break;
+ item.PremiereDate = releaseDate;
+ item.ProductionYear = releaseDate.Year;
}
+ break;
case "enddate":
+ if (reader.TryReadDateTimeExact(nfoConfiguration.ReleaseDateFormat, out var endDate))
{
- var formatString = nfoConfiguration.ReleaseDateFormat;
-
- var val = reader.ReadElementContentAsString();
-
- if (DateTime.TryParseExact(val, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var date) && date.Year > 1850)
- {
- item.EndDate = date;
- }
-
- break;
+ item.EndDate = endDate;
}
+ break;
case "genre":
{
var val = reader.ReadElementContentAsString();
@@ -721,57 +533,34 @@ namespace MediaBrowser.XbmcMetadata.Parsers
case "style":
case "tag":
+ var tag = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(tag))
{
- var val = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.AddTag(val);
- }
-
- break;
+ item.AddTag(tag);
}
+ break;
case "fileinfo":
- {
- if (!reader.IsEmptyElement)
- {
- using (var subtree = reader.ReadSubtree())
- {
- FetchFromFileInfoNode(subtree, item);
- }
- }
- else
- {
- reader.Read();
- }
-
- break;
- }
-
+ FetchFromFileInfoNode(reader, item);
+ break;
case "uniqueid":
+ if (reader.IsEmptyElement)
{
- if (reader.IsEmptyElement)
- {
- reader.Read();
- break;
- }
-
- var provider = reader.GetAttribute("type");
- var id = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(provider) && !string.IsNullOrWhiteSpace(id))
- {
- item.SetProviderId(provider, id);
- }
-
+ reader.Read();
break;
}
- case "thumb":
+ var provider = reader.GetAttribute("type");
+ var providerId = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(provider) && !string.IsNullOrWhiteSpace(providerId))
{
- FetchThumbNode(reader, itemResult, "thumb");
- break;
+ item.SetProviderId(provider, providerId);
}
+ break;
+ case "thumb":
+ FetchThumbNode(reader, itemResult, "thumb");
+ break;
case "fanart":
{
if (reader.IsEmptyElement)
@@ -876,242 +665,188 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
}
- private void FetchFromFileInfoNode(XmlReader reader, T item)
+ private void FetchFromFileInfoNode(XmlReader parentReader, T item)
{
+ if (parentReader.IsEmptyElement)
+ {
+ parentReader.Read();
+ return;
+ }
+
+ using var reader = parentReader.ReadSubtree();
reader.MoveToContent();
reader.Read();
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
{
- if (reader.NodeType == XmlNodeType.Element)
+ if (reader.NodeType != XmlNodeType.Element)
{
- switch (reader.Name)
- {
- case "streamdetails":
- {
- if (reader.IsEmptyElement)
- {
- reader.Read();
- continue;
- }
-
- using (var subtree = reader.ReadSubtree())
- {
- FetchFromStreamDetailsNode(subtree, item);
- }
-
- break;
- }
-
- default:
- reader.Skip();
- break;
- }
+ reader.Read();
+ continue;
}
- else
+
+ switch (reader.Name)
{
- reader.Read();
+ case "streamdetails":
+ FetchFromStreamDetailsNode(reader, item);
+ break;
+ default:
+ reader.Skip();
+ break;
}
}
}
- private void FetchFromStreamDetailsNode(XmlReader reader, T item)
+ private void FetchFromStreamDetailsNode(XmlReader parentReader, T item)
{
+ if (parentReader.IsEmptyElement)
+ {
+ parentReader.Read();
+ return;
+ }
+
+ using var reader = parentReader.ReadSubtree();
reader.MoveToContent();
reader.Read();
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
{
- if (reader.NodeType == XmlNodeType.Element)
+ if (reader.NodeType != XmlNodeType.Element)
{
- switch (reader.Name)
- {
- case "video":
- {
- if (reader.IsEmptyElement)
- {
- reader.Read();
- continue;
- }
-
- using (var subtree = reader.ReadSubtree())
- {
- FetchFromVideoNode(subtree, item);
- }
-
- break;
- }
-
- case "subtitle":
- {
- if (reader.IsEmptyElement)
- {
- reader.Read();
- continue;
- }
-
- using (var subtree = reader.ReadSubtree())
- {
- FetchFromSubtitleNode(subtree, item);
- }
-
- break;
- }
-
- default:
- reader.Skip();
- break;
- }
+ reader.Read();
+ continue;
}
- else
+
+ switch (reader.Name)
{
- reader.Read();
+ case "video":
+ FetchFromVideoNode(reader, item);
+ break;
+ case "subtitle":
+ FetchFromSubtitleNode(reader, item);
+ break;
+ default:
+ reader.Skip();
+ break;
}
}
}
- private void FetchFromVideoNode(XmlReader reader, T item)
+ private void FetchFromVideoNode(XmlReader parentReader, T item)
{
+ if (parentReader.IsEmptyElement)
+ {
+ parentReader.Read();
+ return;
+ }
+
+ using var reader = parentReader.ReadSubtree();
reader.MoveToContent();
reader.Read();
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
{
- if (reader.NodeType == XmlNodeType.Element)
+ if (reader.NodeType != XmlNodeType.Element || item is not Video video)
{
- switch (reader.Name)
- {
- case "format3d":
- {
- var val = reader.ReadElementContentAsString();
-
- var video = item as Video;
-
- if (video is not null)
- {
- if (string.Equals("HSBS", val, StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfSideBySide;
- }
- else if (string.Equals("HTAB", val, StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
- }
- else if (string.Equals("FTAB", val, StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.FullTopAndBottom;
- }
- else if (string.Equals("FSBS", val, StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.FullSideBySide;
- }
- else if (string.Equals("MVC", val, StringComparison.OrdinalIgnoreCase))
- {
- video.Video3DFormat = Video3DFormat.MVC;
- }
- }
-
- break;
- }
-
- case "aspect":
- {
- var val = reader.ReadElementContentAsString();
-
- if (item is Video video)
- {
- video.AspectRatio = val;
- }
-
- break;
- }
-
- case "width":
- {
- var val = reader.ReadElementContentAsInt();
-
- if (item is Video video)
- {
- video.Width = val;
- }
-
- break;
- }
-
- case "height":
- {
- var val = reader.ReadElementContentAsInt();
-
- if (item is Video video)
- {
- video.Height = val;
- }
-
- break;
- }
-
- case "durationinseconds":
- {
- var val = reader.ReadElementContentAsInt();
-
- if (item is Video video)
- {
- video.RunTimeTicks = new TimeSpan(0, 0, val).Ticks;
- }
-
- break;
- }
-
- default:
- reader.Skip();
- break;
- }
+ reader.Read();
+ continue;
}
- else
+
+ switch (reader.Name)
{
- reader.Read();
+ case "format3d":
+ var format = reader.ReadElementContentAsString();
+ if (string.Equals("HSBS", format, StringComparison.OrdinalIgnoreCase))
+ {
+ video.Video3DFormat = Video3DFormat.HalfSideBySide;
+ }
+ else if (string.Equals("HTAB", format, StringComparison.OrdinalIgnoreCase))
+ {
+ video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
+ }
+ else if (string.Equals("FTAB", format, StringComparison.OrdinalIgnoreCase))
+ {
+ video.Video3DFormat = Video3DFormat.FullTopAndBottom;
+ }
+ else if (string.Equals("FSBS", format, StringComparison.OrdinalIgnoreCase))
+ {
+ video.Video3DFormat = Video3DFormat.FullSideBySide;
+ }
+ else if (string.Equals("MVC", format, StringComparison.OrdinalIgnoreCase))
+ {
+ video.Video3DFormat = Video3DFormat.MVC;
+ }
+
+ break;
+ case "aspect":
+ video.AspectRatio = reader.ReadNormalizedString();
+ break;
+ case "width":
+ video.Width = reader.ReadElementContentAsInt();
+ break;
+ case "height":
+ video.Height = reader.ReadElementContentAsInt();
+ break;
+ case "durationinseconds":
+ video.RunTimeTicks = new TimeSpan(0, 0, reader.ReadElementContentAsInt()).Ticks;
+ break;
+ default:
+ reader.Skip();
+ break;
}
}
}
- private void FetchFromSubtitleNode(XmlReader reader, T item)
+ private void FetchFromSubtitleNode(XmlReader parentReader, T item)
{
+ if (parentReader.IsEmptyElement)
+ {
+ parentReader.Read();
+ return;
+ }
+
+ using var reader = parentReader.ReadSubtree();
reader.MoveToContent();
reader.Read();
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
{
- if (reader.NodeType == XmlNodeType.Element)
+ if (reader.NodeType != XmlNodeType.Element)
{
- switch (reader.Name)
- {
- case "language":
- _ = reader.ReadElementContentAsString();
- if (item is Video video)
- {
- video.HasSubtitles = true;
- }
-
- break;
-
- default:
- reader.Skip();
- break;
- }
+ reader.Read();
+ continue;
}
- else
+
+ switch (reader.Name)
{
- reader.Read();
+ case "language":
+ _ = reader.ReadElementContentAsString();
+ if (item is Video video)
+ {
+ video.HasSubtitles = true;
+ }
+
+ break;
+ default:
+ reader.Skip();
+ break;
}
}
}
- private void FetchFromRatingsNode(XmlReader reader, T item)
+ private void FetchFromRatingsNode(XmlReader parentReader, T item)
{
+ if (parentReader.IsEmptyElement)
+ {
+ parentReader.Read();
+ return;
+ }
+
+ using var reader = parentReader.ReadSubtree();
reader.MoveToContent();
reader.Read();
@@ -1196,102 +931,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
}
- /// <summary>
- /// Gets the persons from a XML node.
- /// </summary>
- /// <param name="reader">The <see cref="XmlReader"/>.</param>
- /// <returns>IEnumerable{PersonInfo}.</returns>
- 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()
{
@@ -1302,24 +941,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
};
/// <summary>
- /// Used to split names of comma or pipe delimited genres and people.
- /// </summary>
- /// <param name="value">The value.</param>
- /// <returns>IEnumerable{System.String}.</returns>
- private IEnumerable<string> SplitNames(string value)
- {
- // 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[] { '|', ';' };
-
- value = value.Trim().Trim(separator);
-
- return string.IsNullOrWhiteSpace(value) ? Array.Empty<string>() : value.Split(separator, StringSplitOptions.RemoveEmptyEntries);
- }
-
- /// <summary>
/// Parses the <see cref="ImageType"/> from the NFO aspect property.
/// </summary>
/// <param name="aspect">The NFO aspect property.</param>
diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
index d2f349ad7..044efb51e 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
@@ -1,10 +1,11 @@
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.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using Microsoft.Extensions.Logging;
@@ -81,7 +82,10 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
// Extract the last episode number from nfo
+ // Retrieves all title and plot tags from the rest of the nfo and concatenates them with the first episode
// This is needed because XBMC metadata uses multiple episodedetails blocks instead of episodenumberend tag
+ var name = new StringBuilder(item.Item.Name);
+ var overview = new StringBuilder(item.Item.Overview);
while ((index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase)) != -1)
{
xml = xmlFile.Substring(0, index + srch.Length);
@@ -92,12 +96,44 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
reader.MoveToContent();
- if (reader.ReadToDescendant("episode") && int.TryParse(reader.ReadElementContentAsString(), out var num))
+ while (!reader.EOF && reader.ReadState == ReadState.Interactive)
{
- item.Item.IndexNumberEnd = Math.Max(num, item.Item.IndexNumberEnd ?? num);
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (reader.NodeType == XmlNodeType.Element)
+ {
+ switch (reader.Name)
+ {
+ case "name":
+ case "title":
+ case "localtitle":
+ name.Append(" / ").Append(reader.ReadElementContentAsString());
+ break;
+ case "episode":
+ {
+ if (int.TryParse(reader.ReadElementContentAsString(), out var num))
+ {
+ item.Item.IndexNumberEnd = Math.Max(num, item.Item.IndexNumberEnd ?? num);
+ }
+
+ break;
+ }
+
+ case "biography":
+ case "plot":
+ case "review":
+ overview.Append(" / ").Append(reader.ReadElementContentAsString());
+ break;
+ }
+ }
+
+ reader.Read();
}
}
}
+
+ item.Item.Name = name.ToString();
+ item.Item.Overview = overview.ToString();
}
catch (XmlException)
{
@@ -112,142 +148,53 @@ namespace MediaBrowser.XbmcMetadata.Parsers
switch (reader.Name)
{
case "season":
+ if (reader.TryReadInt(out var seasonNumber))
{
- var number = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(number))
- {
- if (int.TryParse(number, out var num))
- {
- item.ParentIndexNumber = num;
- }
- }
-
- break;
+ item.ParentIndexNumber = seasonNumber;
}
+ break;
case "episode":
+ if (reader.TryReadInt(out var episodeNumber))
{
- var number = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(number))
- {
- if (int.TryParse(number, out var num))
- {
- item.IndexNumber = num;
- }
- }
-
- break;
+ item.IndexNumber = episodeNumber;
}
+ break;
case "episodenumberend":
+ if (reader.TryReadInt(out var episodeNumberEnd))
{
- var number = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(number))
- {
- if (int.TryParse(number, out var num))
- {
- item.IndexNumberEnd = num;
- }
- }
-
- break;
+ item.IndexNumberEnd = episodeNumberEnd;
}
+ break;
case "airsbefore_episode":
+ case "displayepisode":
+ if (reader.TryReadInt(out var airsBeforeEpisode))
{
- 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, CultureInfo.InvariantCulture, out var rval))
- {
- item.AirsBeforeEpisodeNumber = rval;
- }
- }
-
- break;
+ item.AirsBeforeEpisodeNumber = airsBeforeEpisode;
}
+ break;
case "airsafter_season":
+ case "displayafterseason":
+ if (reader.TryReadInt(out var airsAfterSeason))
{
- 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, CultureInfo.InvariantCulture, out var rval))
- {
- item.AirsAfterSeasonNumber = rval;
- }
- }
-
- break;
+ item.AirsAfterSeasonNumber = airsAfterSeason;
}
+ 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, CultureInfo.InvariantCulture, out var rval))
- {
- item.AirsBeforeSeasonNumber = rval;
- }
- }
-
- break;
- }
-
case "displayseason":
+ if (reader.TryReadInt(out var airsBeforeSeason))
{
- 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, CultureInfo.InvariantCulture, 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, CultureInfo.InvariantCulture, out var rval))
- {
- item.AirsBeforeEpisodeNumber = rval;
- }
- }
-
- break;
+ item.AirsBeforeSeasonNumber = airsBeforeSeason;
}
+ break;
case "showtitle":
- {
- var showtitle = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(showtitle))
- {
- item.SeriesName = showtitle;
- }
-
- break;
- }
-
+ item.SeriesName = reader.ReadNormalizedString();
+ break;
default:
base.FetchDataFromXmlNode(reader, itemResult);
break;
diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
index ecfed6873..16ea5e3ea 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
@@ -5,6 +5,7 @@ using System.Xml;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -113,31 +114,23 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
case "artist":
+ var artist = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(artist) && item is MusicVideo artistVideo)
{
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val) && item is MusicVideo movie)
- {
- var list = movie.Artists.ToList();
- list.Add(val);
- movie.Artists = list.ToArray();
- }
-
- break;
+ var list = artistVideo.Artists.ToList();
+ list.Add(artist);
+ artistVideo.Artists = list.ToArray();
}
+ break;
case "album":
+ var album = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(album) && item is MusicVideo albumVideo)
{
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val) && item is MusicVideo movie)
- {
- movie.Album = val;
- }
-
- break;
+ albumVideo.Album = album;
}
+ break;
default:
base.FetchDataFromXmlNode(reader, itemResult);
break;
diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs
index 51d5f932b..e13f0d997 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs
@@ -1,7 +1,7 @@
-using System.Globalization;
using System.Xml;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using Microsoft.Extensions.Logging;
@@ -41,32 +41,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers
switch (reader.Name)
{
case "seasonnumber":
+ if (reader.TryReadInt(out var seasonNumber))
{
- var number = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(number))
- {
- if (int.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out var num))
- {
- item.IndexNumber = num;
- }
- }
-
- break;
+ item.IndexNumber = seasonNumber;
}
+ break;
case "seasonname":
- {
- var name = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(name))
- {
- item.Name = name;
- }
-
- break;
- }
-
+ item.Name = reader.ReadNormalizedString();
+ break;
default:
base.FetchDataFromXmlNode(reader, itemResult);
break;
diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
index f4b4eccf8..dbcfe7997 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
@@ -3,6 +3,7 @@ using System.Globalization;
using System.Xml;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -75,23 +76,11 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
case "airs_dayofweek":
- {
- item.AirDays = TVUtils.GetAirDays(reader.ReadElementContentAsString());
- break;
- }
-
+ item.AirDays = TVUtils.GetAirDays(reader.ReadElementContentAsString());
+ break;
case "airs_time":
- {
- var val = reader.ReadElementContentAsString();
-
- if (!string.IsNullOrWhiteSpace(val))
- {
- item.AirTime = val;
- }
-
- break;
- }
-
+ item.AirTime = reader.ReadNormalizedString();
+ break;
case "status":
{
var status = reader.ReadElementContentAsString();
diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
index 82e1dc860..8fa22fad9 100644
--- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
@@ -60,13 +60,13 @@ namespace MediaBrowser.XbmcMetadata.Savers
}
else
{
- yield return Path.ChangeExtension(item.Path, ".nfo");
-
// only allow movie object to read movie.nfo, not owned videos (which will be itemtype video, not movie)
if (!item.IsInMixedFolder && item.ItemType == typeof(Movie))
{
yield return Path.Combine(item.ContainingFolderPath, "movie.nfo");
}
+
+ yield return Path.ChangeExtension(item.Path, ".nfo");
}
}