|
|
@ -13,6 +13,7 @@ using MediaBrowser.Common.Providers;
|
|
|
|
using MediaBrowser.Controller.Entities;
|
|
|
|
using MediaBrowser.Controller.Entities;
|
|
|
|
using MediaBrowser.Controller.Entities.Movies;
|
|
|
|
using MediaBrowser.Controller.Entities.Movies;
|
|
|
|
using MediaBrowser.Controller.Entities.TV;
|
|
|
|
using MediaBrowser.Controller.Entities.TV;
|
|
|
|
|
|
|
|
using MediaBrowser.Controller.Extensions;
|
|
|
|
using MediaBrowser.Controller.Library;
|
|
|
|
using MediaBrowser.Controller.Library;
|
|
|
|
using MediaBrowser.Controller.Providers;
|
|
|
|
using MediaBrowser.Controller.Providers;
|
|
|
|
using MediaBrowser.Model.Entities;
|
|
|
|
using MediaBrowser.Model.Entities;
|
|
|
@ -261,158 +262,84 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|
|
|
protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult<T> itemResult)
|
|
|
|
protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult<T> itemResult)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var item = itemResult.Item;
|
|
|
|
var item = itemResult.Item;
|
|
|
|
|
|
|
|
|
|
|
|
var nfoConfiguration = _config.GetNfoConfiguration();
|
|
|
|
var nfoConfiguration = _config.GetNfoConfiguration();
|
|
|
|
UserItemData? userData = null;
|
|
|
|
UserItemData? userData;
|
|
|
|
|
|
|
|
|
|
|
|
switch (reader.Name)
|
|
|
|
switch (reader.Name)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// DateCreated
|
|
|
|
|
|
|
|
case "dateadded":
|
|
|
|
case "dateadded":
|
|
|
|
|
|
|
|
if (reader.TryReadDateTime(out var dateCreated))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
item.DateCreated = dateCreated;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "originaltitle":
|
|
|
|
case "originaltitle":
|
|
|
|
{
|
|
|
|
item.OriginalTitle = reader.ReadNormalizedString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(val))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
item.OriginalTitle = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "name":
|
|
|
|
case "name":
|
|
|
|
case "title":
|
|
|
|
case "title":
|
|
|
|
case "localtitle":
|
|
|
|
case "localtitle":
|
|
|
|
item.Name = reader.ReadElementContentAsString();
|
|
|
|
item.Name = reader.ReadNormalizedString();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "sortname":
|
|
|
|
case "sortname":
|
|
|
|
item.SortName = reader.ReadElementContentAsString();
|
|
|
|
item.SortName = reader.ReadNormalizedString();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "criticrating":
|
|
|
|
case "criticrating":
|
|
|
|
{
|
|
|
|
var criticRatingText = reader.ReadElementContentAsString();
|
|
|
|
var text = reader.ReadElementContentAsString();
|
|
|
|
if (float.TryParse(criticRatingText, CultureInfo.InvariantCulture, out var value))
|
|
|
|
|
|
|
|
|
|
|
|
if (float.TryParse(text, CultureInfo.InvariantCulture, out var value))
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
item.CriticRating = value;
|
|
|
|
item.CriticRating = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "sorttitle":
|
|
|
|
case "sorttitle":
|
|
|
|
{
|
|
|
|
item.ForcedSortName = reader.ReadNormalizedString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
item.ForcedSortName = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "biography":
|
|
|
|
case "biography":
|
|
|
|
case "plot":
|
|
|
|
case "plot":
|
|
|
|
case "review":
|
|
|
|
case "review":
|
|
|
|
{
|
|
|
|
item.Overview = reader.ReadNormalizedString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
item.Overview = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "language":
|
|
|
|
case "language":
|
|
|
|
{
|
|
|
|
item.PreferredMetadataLanguage = reader.ReadNormalizedString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
item.PreferredMetadataLanguage = val;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "watched":
|
|
|
|
case "watched":
|
|
|
|
{
|
|
|
|
var played = reader.ReadElementContentAsBoolean();
|
|
|
|
var val = reader.ReadElementContentAsBoolean();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(nfoConfiguration.UserId))
|
|
|
|
if (!string.IsNullOrWhiteSpace(nfoConfiguration.UserId))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var user = _userManager.GetUserById(Guid.Parse(nfoConfiguration.UserId));
|
|
|
|
var user = _userManager.GetUserById(Guid.Parse(nfoConfiguration.UserId));
|
|
|
|
userData = _userDataManager.GetUserData(user, item);
|
|
|
|
userData = _userDataManager.GetUserData(user, item);
|
|
|
|
userData.Played = val;
|
|
|
|
userData.Played = played;
|
|
|
|
_userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
|
|
|
|
_userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "playcount":
|
|
|
|
case "playcount":
|
|
|
|
|
|
|
|
if (reader.TryReadInt(out var count)
|
|
|
|
|
|
|
|
&& Guid.TryParse(nfoConfiguration.UserId, out var playCountUserId))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
var user = _userManager.GetUserById(playCountUserId);
|
|
|
|
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 = _userDataManager.GetUserData(user, item);
|
|
|
|
userData.PlayCount = count;
|
|
|
|
userData.PlayCount = count;
|
|
|
|
_userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
|
|
|
|
_userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "lastplayed":
|
|
|
|
case "lastplayed":
|
|
|
|
|
|
|
|
if (reader.TryReadDateTime(out var lastPlayed)
|
|
|
|
|
|
|
|
&& Guid.TryParse(nfoConfiguration.UserId, out var lastPlayedUserId))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
var user = _userManager.GetUserById(lastPlayedUserId);
|
|
|
|
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 = _userDataManager.GetUserData(user, item);
|
|
|
|
userData.LastPlayedDate = added;
|
|
|
|
userData.LastPlayedDate = lastPlayed;
|
|
|
|
_userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
|
|
|
|
_userDataManager.SaveUserData(user, item, userData, UserDataSaveReason.Import, CancellationToken.None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
Logger.LogWarning("Invalid lastplayed value found: {Value}", val);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "countrycode":
|
|
|
|
case "countrycode":
|
|
|
|
{
|
|
|
|
item.PreferredMetadataCountryCode = reader.ReadNormalizedString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
item.PreferredMetadataCountryCode = val;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "lockedfields":
|
|
|
|
case "lockedfields":
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
@ -434,9 +361,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case "tagline":
|
|
|
|
case "tagline":
|
|
|
|
item.Tagline = reader.ReadElementContentAsString();
|
|
|
|
item.Tagline = reader.ReadNormalizedString();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "country":
|
|
|
|
case "country":
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
@ -453,94 +379,45 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case "mpaa":
|
|
|
|
case "mpaa":
|
|
|
|
{
|
|
|
|
item.OfficialRating = reader.ReadNormalizedString();
|
|
|
|
var rating = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(rating))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
item.OfficialRating = rating;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "customrating":
|
|
|
|
case "customrating":
|
|
|
|
{
|
|
|
|
item.CustomRating = reader.ReadNormalizedString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
item.CustomRating = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "runtime":
|
|
|
|
case "runtime":
|
|
|
|
{
|
|
|
|
var runtimeText = reader.ReadElementContentAsString();
|
|
|
|
var text = reader.ReadElementContentAsString();
|
|
|
|
if (int.TryParse(runtimeText.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime))
|
|
|
|
|
|
|
|
|
|
|
|
if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime))
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
|
|
|
|
item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "aspectratio":
|
|
|
|
case "aspectratio":
|
|
|
|
|
|
|
|
var aspectRatio = reader.ReadNormalizedString();
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(aspectRatio) && item is IHasAspectRatio hasAspectRatio)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
hasAspectRatio.AspectRatio = aspectRatio;
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(val)
|
|
|
|
|
|
|
|
&& item is IHasAspectRatio hasAspectRatio)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
hasAspectRatio.AspectRatio = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "lockdata":
|
|
|
|
case "lockdata":
|
|
|
|
{
|
|
|
|
item.IsLocked = string.Equals(reader.ReadElementContentAsString(), "true", StringComparison.OrdinalIgnoreCase);
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
item.IsLocked = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "studio":
|
|
|
|
case "studio":
|
|
|
|
|
|
|
|
var studio = reader.ReadNormalizedString();
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(studio))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
item.AddStudio(studio);
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
item.AddStudio(val);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "director":
|
|
|
|
case "director":
|
|
|
|
|
|
|
|
foreach (var director in reader.GetPersonArray(PersonKind.Director))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
itemResult.AddPerson(director);
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "credits":
|
|
|
|
case "credits":
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
@ -565,141 +442,76 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case "writer":
|
|
|
|
case "writer":
|
|
|
|
|
|
|
|
foreach (var writer in reader.GetPersonArray(PersonKind.Writer))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
itemResult.AddPerson(writer);
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "actor":
|
|
|
|
case "actor":
|
|
|
|
{
|
|
|
|
var person = reader.GetPersonFromXmlNode();
|
|
|
|
if (!reader.IsEmptyElement)
|
|
|
|
if (person is not null)
|
|
|
|
{
|
|
|
|
|
|
|
|
using (var subtree = reader.ReadSubtree())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var person = GetPersonFromXmlNode(subtree);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(person.Name))
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
itemResult.AddPerson(person);
|
|
|
|
itemResult.AddPerson(person);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "trailer":
|
|
|
|
case "trailer":
|
|
|
|
|
|
|
|
var trailer = reader.ReadNormalizedString();
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(trailer))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
item.AddTrailerUrl(trailer.Replace(
|
|
|
|
|
|
|
|
"plugin://plugin.video.youtube/?action=play_video&videoid=",
|
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
|
BaseNfoSaver.YouTubeWatchUrl,
|
|
|
|
{
|
|
|
|
StringComparison.OrdinalIgnoreCase));
|
|
|
|
val = val.Replace("plugin://plugin.video.youtube/?action=play_video&videoid=", BaseNfoSaver.YouTubeWatchUrl, StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
item.AddTrailerUrl(val);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "displayorder":
|
|
|
|
case "displayorder":
|
|
|
|
|
|
|
|
var displayOrder = reader.ReadNormalizedString();
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(displayOrder) && item is IHasDisplayOrder hasDisplayOrder)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
hasDisplayOrder.DisplayOrder = displayOrder;
|
|
|
|
|
|
|
|
|
|
|
|
if (item is IHasDisplayOrder hasDisplayOrder && !string.IsNullOrWhiteSpace(val))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
hasDisplayOrder.DisplayOrder = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "year":
|
|
|
|
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;
|
|
|
|
item.ProductionYear = productionYear;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "rating":
|
|
|
|
case "rating":
|
|
|
|
{
|
|
|
|
var rating = reader.ReadElementContentAsString().Replace(',', '.');
|
|
|
|
var rating = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// All external meta is saving this as '.' for decimal I believe...but just to be sure
|
|
|
|
// 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))
|
|
|
|
if (float.TryParse(rating, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var communityRating))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
item.CommunityRating = val;
|
|
|
|
item.CommunityRating = communityRating;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "ratings":
|
|
|
|
case "ratings":
|
|
|
|
{
|
|
|
|
FetchFromRatingsNode(reader, item);
|
|
|
|
if (!reader.IsEmptyElement)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
using var subtree = reader.ReadSubtree();
|
|
|
|
|
|
|
|
FetchFromRatingsNode(subtree, item);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "aired":
|
|
|
|
case "aired":
|
|
|
|
case "formed":
|
|
|
|
case "formed":
|
|
|
|
case "premiered":
|
|
|
|
case "premiered":
|
|
|
|
case "releasedate":
|
|
|
|
case "releasedate":
|
|
|
|
|
|
|
|
if (reader.TryReadDateTimeExact(nfoConfiguration.ReleaseDateFormat, out var releaseDate))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var formatString = nfoConfiguration.ReleaseDateFormat;
|
|
|
|
item.PremiereDate = releaseDate;
|
|
|
|
|
|
|
|
item.ProductionYear = releaseDate.Year;
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "enddate":
|
|
|
|
case "enddate":
|
|
|
|
|
|
|
|
if (reader.TryReadDateTimeExact(nfoConfiguration.ReleaseDateFormat, out var endDate))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var formatString = nfoConfiguration.ReleaseDateFormat;
|
|
|
|
item.EndDate = endDate;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "genre":
|
|
|
|
case "genre":
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
@ -721,35 +533,17 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|
|
|
|
|
|
|
|
|
|
|
case "style":
|
|
|
|
case "style":
|
|
|
|
case "tag":
|
|
|
|
case "tag":
|
|
|
|
|
|
|
|
var tag = reader.ReadNormalizedString();
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(tag))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
item.AddTag(tag);
|
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
item.AddTag(val);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "fileinfo":
|
|
|
|
case "fileinfo":
|
|
|
|
{
|
|
|
|
FetchFromFileInfoNode(reader, item);
|
|
|
|
if (!reader.IsEmptyElement)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
using (var subtree = reader.ReadSubtree())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
FetchFromFileInfoNode(subtree, item);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "uniqueid":
|
|
|
|
case "uniqueid":
|
|
|
|
{
|
|
|
|
|
|
|
|
if (reader.IsEmptyElement)
|
|
|
|
if (reader.IsEmptyElement)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
reader.Read();
|
|
|
|
reader.Read();
|
|
|
@ -757,21 +551,16 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var provider = reader.GetAttribute("type");
|
|
|
|
var provider = reader.GetAttribute("type");
|
|
|
|
var id = reader.ReadElementContentAsString();
|
|
|
|
var providerId = reader.ReadElementContentAsString();
|
|
|
|
if (!string.IsNullOrWhiteSpace(provider) && !string.IsNullOrWhiteSpace(id))
|
|
|
|
if (!string.IsNullOrWhiteSpace(provider) && !string.IsNullOrWhiteSpace(providerId))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
item.SetProviderId(provider, id);
|
|
|
|
item.SetProviderId(provider, providerId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "thumb":
|
|
|
|
case "thumb":
|
|
|
|
{
|
|
|
|
|
|
|
|
FetchThumbNode(reader, itemResult, "thumb");
|
|
|
|
FetchThumbNode(reader, itemResult, "thumb");
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "fanart":
|
|
|
|
case "fanart":
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (reader.IsEmptyElement)
|
|
|
|
if (reader.IsEmptyElement)
|
|
|
@ -876,217 +665,162 @@ 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.MoveToContent();
|
|
|
|
reader.Read();
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
|
|
|
|
// Loop through each element
|
|
|
|
// Loop through each element
|
|
|
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
|
|
|
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();
|
|
|
|
reader.Read();
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
using (var subtree = reader.ReadSubtree())
|
|
|
|
switch (reader.Name)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
FetchFromStreamDetailsNode(subtree, item);
|
|
|
|
case "streamdetails":
|
|
|
|
}
|
|
|
|
FetchFromStreamDetailsNode(reader, item);
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
reader.Skip();
|
|
|
|
reader.Skip();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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.MoveToContent();
|
|
|
|
reader.Read();
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
|
|
|
|
// Loop through each element
|
|
|
|
// Loop through each element
|
|
|
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
|
|
|
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();
|
|
|
|
reader.Read();
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
using (var subtree = reader.ReadSubtree())
|
|
|
|
switch (reader.Name)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
FetchFromVideoNode(subtree, item);
|
|
|
|
case "video":
|
|
|
|
}
|
|
|
|
FetchFromVideoNode(reader, item);
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "subtitle":
|
|
|
|
case "subtitle":
|
|
|
|
{
|
|
|
|
FetchFromSubtitleNode(reader, item);
|
|
|
|
if (reader.IsEmptyElement)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using (var subtree = reader.ReadSubtree())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
FetchFromSubtitleNode(subtree, item);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
reader.Skip();
|
|
|
|
reader.Skip();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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.MoveToContent();
|
|
|
|
reader.Read();
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
|
|
|
|
// Loop through each element
|
|
|
|
// Loop through each element
|
|
|
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
|
|
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (reader.NodeType == XmlNodeType.Element)
|
|
|
|
if (reader.NodeType != XmlNodeType.Element || item is not Video video)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (reader.Name)
|
|
|
|
switch (reader.Name)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
case "format3d":
|
|
|
|
case "format3d":
|
|
|
|
{
|
|
|
|
var format = reader.ReadElementContentAsString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
if (string.Equals("HSBS", format, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
|
|
|
|
|
|
var video = item as Video;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (video is not null)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (string.Equals("HSBS", val, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
video.Video3DFormat = Video3DFormat.HalfSideBySide;
|
|
|
|
video.Video3DFormat = Video3DFormat.HalfSideBySide;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (string.Equals("HTAB", val, StringComparison.OrdinalIgnoreCase))
|
|
|
|
else if (string.Equals("HTAB", format, StringComparison.OrdinalIgnoreCase))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
|
|
|
|
video.Video3DFormat = Video3DFormat.HalfTopAndBottom;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (string.Equals("FTAB", val, StringComparison.OrdinalIgnoreCase))
|
|
|
|
else if (string.Equals("FTAB", format, StringComparison.OrdinalIgnoreCase))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
video.Video3DFormat = Video3DFormat.FullTopAndBottom;
|
|
|
|
video.Video3DFormat = Video3DFormat.FullTopAndBottom;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (string.Equals("FSBS", val, StringComparison.OrdinalIgnoreCase))
|
|
|
|
else if (string.Equals("FSBS", format, StringComparison.OrdinalIgnoreCase))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
video.Video3DFormat = Video3DFormat.FullSideBySide;
|
|
|
|
video.Video3DFormat = Video3DFormat.FullSideBySide;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (string.Equals("MVC", val, StringComparison.OrdinalIgnoreCase))
|
|
|
|
else if (string.Equals("MVC", format, StringComparison.OrdinalIgnoreCase))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
video.Video3DFormat = Video3DFormat.MVC;
|
|
|
|
video.Video3DFormat = Video3DFormat.MVC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "aspect":
|
|
|
|
case "aspect":
|
|
|
|
{
|
|
|
|
video.AspectRatio = reader.ReadNormalizedString();
|
|
|
|
var val = reader.ReadElementContentAsString();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (item is Video video)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
video.AspectRatio = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "width":
|
|
|
|
case "width":
|
|
|
|
{
|
|
|
|
video.Width = reader.ReadElementContentAsInt();
|
|
|
|
var val = reader.ReadElementContentAsInt();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (item is Video video)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
video.Width = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "height":
|
|
|
|
case "height":
|
|
|
|
{
|
|
|
|
video.Height = reader.ReadElementContentAsInt();
|
|
|
|
var val = reader.ReadElementContentAsInt();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (item is Video video)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
video.Height = val;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "durationinseconds":
|
|
|
|
case "durationinseconds":
|
|
|
|
{
|
|
|
|
video.RunTimeTicks = new TimeSpan(0, 0, reader.ReadElementContentAsInt()).Ticks;
|
|
|
|
var val = reader.ReadElementContentAsInt();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (item is Video video)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
video.RunTimeTicks = new TimeSpan(0, 0, val).Ticks;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
reader.Skip();
|
|
|
|
reader.Skip();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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.MoveToContent();
|
|
|
|
reader.Read();
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
|
|
|
|
// Loop through each element
|
|
|
|
// Loop through each element
|
|
|
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
|
|
|
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (reader.NodeType == XmlNodeType.Element)
|
|
|
|
if (reader.NodeType != XmlNodeType.Element)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (reader.Name)
|
|
|
|
switch (reader.Name)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
case "language":
|
|
|
|
case "language":
|
|
|
@ -1097,21 +831,22 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
reader.Skip();
|
|
|
|
reader.Skip();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
reader.Read();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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.MoveToContent();
|
|
|
|
reader.Read();
|
|
|
|
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()
|
|
|
|
internal XmlReaderSettings GetXmlReaderSettings()
|
|
|
|
=> new XmlReaderSettings()
|
|
|
|
=> new XmlReaderSettings()
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -1301,24 +940,6 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|
|
|
IgnoreComments = true
|
|
|
|
IgnoreComments = true
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// <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>
|
|
|
|
/// <summary>
|
|
|
|
/// Parses the <see cref="ImageType"/> from the NFO aspect property.
|
|
|
|
/// Parses the <see cref="ImageType"/> from the NFO aspect property.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|