aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Brooks <IDisposable@gmail.com>2023-05-15 00:38:27 -0500
committerMarc Brooks <IDisposable@gmail.com>2024-09-18 20:33:18 -0500
commit6dc61a430ba3a8480399309f277e5debfd6403ba (patch)
tree074cd7244dc434d3853edc0209efd86b04568cdb
parent569a41fc2a518672684b28a106241ecd8c9ceb67 (diff)
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change. In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too. Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers) BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name) AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name) ArtistNfo: Albums (by Production Year>SortName>Name) MovieNfo: Artists Fix Debug build lint Fix CI debug build lint issue. Fix review issues Fixed debug-build lint issues. Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero. Removed the exception filtering I put in for testing. Don't emit actors for MusicAlbums or MusicArtists Swap from String.Trimmed() to ?.Trim() Addressing PR feedback Can't use ReadOnlySpan in an async method Removed now-unused namespace
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs6
-rw-r--r--MediaBrowser.Controller/Entities/PeopleHelper.cs2
-rw-r--r--MediaBrowser.Controller/Sorting/SortExtensions.cs5
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs27
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs34
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioFileProber.cs21
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs7
-rw-r--r--MediaBrowser.Providers/Music/AlbumMetadataService.cs4
-rw-r--r--MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs4
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs7
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs6
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs9
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs4
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs17
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs7
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs35
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs3
17 files changed, 123 insertions, 75 deletions
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 414488853..8201ae318 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -22,6 +22,7 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
@@ -915,7 +916,7 @@ namespace MediaBrowser.Controller.Entities
// Remove from middle if surrounded by spaces
sortable = sortable.Replace(" " + search + " ", " ", StringComparison.Ordinal);
- // Remove from end if followed by a space
+ // Remove from end if preceeded by a space
if (sortable.EndsWith(" " + search, StringComparison.Ordinal))
{
sortable = sortable.Remove(sortable.Length - (search.Length + 1));
@@ -1769,7 +1770,6 @@ namespace MediaBrowser.Controller.Entities
public void AddStudio(string name)
{
ArgumentException.ThrowIfNullOrEmpty(name);
-
var current = Studios;
if (!current.Contains(name, StringComparison.OrdinalIgnoreCase))
@@ -1788,7 +1788,7 @@ namespace MediaBrowser.Controller.Entities
public void SetStudios(IEnumerable<string> names)
{
- Studios = names.Distinct().ToArray();
+ Studios = names.Trimmed().Distinct().ToArray();
}
/// <summary>
diff --git a/MediaBrowser.Controller/Entities/PeopleHelper.cs b/MediaBrowser.Controller/Entities/PeopleHelper.cs
index 5292bd772..d81860436 100644
--- a/MediaBrowser.Controller/Entities/PeopleHelper.cs
+++ b/MediaBrowser.Controller/Entities/PeopleHelper.cs
@@ -15,6 +15,8 @@ namespace MediaBrowser.Controller.Entities
ArgumentNullException.ThrowIfNull(person);
ArgumentException.ThrowIfNullOrEmpty(person.Name);
+ person.Name = person.Name.Trim();
+
// Normalize
if (string.Equals(person.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
{
diff --git a/MediaBrowser.Controller/Sorting/SortExtensions.cs b/MediaBrowser.Controller/Sorting/SortExtensions.cs
index f9c0d39dd..db934e0f4 100644
--- a/MediaBrowser.Controller/Sorting/SortExtensions.cs
+++ b/MediaBrowser.Controller/Sorting/SortExtensions.cs
@@ -30,5 +30,10 @@ namespace MediaBrowser.Controller.Sorting
{
return list.ThenByDescending(getName, _comparer);
}
+
+ public static IEnumerable<string> Trimmed(this IEnumerable<string> values)
+ {
+ return values.Select(i => (i ?? string.Empty).Trim());
+ }
}
}
diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
index e4ac59b67..119effe79 100644
--- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
@@ -234,8 +234,8 @@ namespace MediaBrowser.LocalMetadata.Parsers
item.CustomRating = reader.ReadNormalizedString();
break;
case "RunningTime":
- var runtimeText = reader.ReadElementContentAsString();
- if (!string.IsNullOrWhiteSpace(runtimeText))
+ var runtimeText = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(runtimeText))
{
if (int.TryParse(runtimeText.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime))
{
@@ -253,7 +253,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
break;
case "LockData":
- item.IsLocked = string.Equals(reader.ReadElementContentAsString(), "true", StringComparison.OrdinalIgnoreCase);
+ item.IsLocked = string.Equals(reader.ReadNormalizedString(), "true", StringComparison.OrdinalIgnoreCase);
break;
case "Network":
foreach (var name in reader.GetStringArray())
@@ -331,9 +331,9 @@ namespace MediaBrowser.LocalMetadata.Parsers
case "Rating":
case "IMDBrating":
{
- var rating = reader.ReadElementContentAsString();
+ var rating = reader.ReadNormalizedString();
- if (!string.IsNullOrWhiteSpace(rating))
+ if (!string.IsNullOrEmpty(rating))
{
// 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))
@@ -449,7 +449,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
case "OwnerUserId":
{
- var val = reader.ReadElementContentAsString();
+ var val = reader.ReadNormalizedString();
if (Guid.TryParse(val, out var guid) && !guid.Equals(Guid.Empty))
{
@@ -464,7 +464,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
case "Format3D":
{
- var val = reader.ReadElementContentAsString();
+ var val = reader.ReadNormalizedString();
if (item is Video video)
{
@@ -498,7 +498,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
string readerName = reader.Name;
if (_validProviderIds!.TryGetValue(readerName, out string? providerIdValue))
{
- var id = reader.ReadElementContentAsString();
+ var id = reader.ReadNormalizedString();
item.TrySetProviderId(providerIdValue, id);
}
else
@@ -580,7 +580,12 @@ namespace MediaBrowser.LocalMetadata.Parsers
switch (reader.Name)
{
case "Tagline":
- item.Tagline = reader.ReadNormalizedString();
+ var val = reader.ReadNormalizedString();
+ if (!string.IsNullOrEmpty(val))
+ {
+ item.Tagline = val;
+ }
+
break;
default:
reader.Skip();
@@ -842,7 +847,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
userId = reader.ReadNormalizedString();
break;
case "CanEdit":
- canEdit = string.Equals(reader.ReadElementContentAsString(), "true", StringComparison.OrdinalIgnoreCase);
+ canEdit = string.Equals(reader.ReadNormalizedString(), "true", StringComparison.OrdinalIgnoreCase);
break;
default:
reader.Skip();
@@ -856,7 +861,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
}
// This is valid
- if (!string.IsNullOrWhiteSpace(userId) && Guid.TryParse(userId, out var guid))
+ if (!string.IsNullOrEmpty(userId) && Guid.TryParse(userId, out var guid))
{
return new PlaylistUserPermissions(guid, canEdit);
}
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 334796f58..0dee77db8 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -10,7 +10,9 @@ using System.Text.RegularExpressions;
using System.Xml;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
+using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
@@ -531,42 +533,44 @@ namespace MediaBrowser.MediaEncoding.Probing
private void ProcessPairs(string key, List<NameValuePair> pairs, MediaInfo info)
{
List<BaseItemPerson> peoples = new List<BaseItemPerson>();
+ var distinctPairs = pairs.Select(p => p.Value)
+ .Where(i => !string.IsNullOrWhiteSpace(i))
+ .Trimmed()
+ .Distinct(StringComparer.OrdinalIgnoreCase);
+
if (string.Equals(key, "studio", StringComparison.OrdinalIgnoreCase))
{
- info.Studios = pairs.Select(p => p.Value)
- .Where(i => !string.IsNullOrWhiteSpace(i))
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToArray();
+ info.Studios = distinctPairs.ToArray();
}
else if (string.Equals(key, "screenwriters", StringComparison.OrdinalIgnoreCase))
{
- foreach (var pair in pairs)
+ foreach (var pair in distinctPairs)
{
peoples.Add(new BaseItemPerson
{
- Name = pair.Value,
+ Name = pair,
Type = PersonKind.Writer
});
}
}
else if (string.Equals(key, "producers", StringComparison.OrdinalIgnoreCase))
{
- foreach (var pair in pairs)
+ foreach (var pair in distinctPairs)
{
peoples.Add(new BaseItemPerson
{
- Name = pair.Value,
+ Name = pair,
Type = PersonKind.Producer
});
}
}
else if (string.Equals(key, "directors", StringComparison.OrdinalIgnoreCase))
{
- foreach (var pair in pairs)
+ foreach (var pair in distinctPairs)
{
peoples.Add(new BaseItemPerson
{
- Name = pair.Value,
+ Name = pair,
Type = PersonKind.Director
});
}
@@ -591,10 +595,10 @@ namespace MediaBrowser.MediaEncoding.Probing
switch (reader.Name)
{
case "key":
- name = reader.ReadElementContentAsString();
+ name = reader.ReadNormalizedString();
break;
case "string":
- value = reader.ReadElementContentAsString();
+ value = reader.ReadNormalizedString();
break;
default:
reader.Skip();
@@ -607,8 +611,8 @@ namespace MediaBrowser.MediaEncoding.Probing
}
}
- if (string.IsNullOrWhiteSpace(name)
- || string.IsNullOrWhiteSpace(value))
+ if (string.IsNullOrEmpty(name)
+ || string.IsNullOrEmpty(value))
{
return null;
}
@@ -1453,7 +1457,7 @@ namespace MediaBrowser.MediaEncoding.Probing
var genres = new List<string>(info.Genres);
foreach (var genre in Split(genreVal, true))
{
- if (string.IsNullOrWhiteSpace(genre))
+ if (string.IsNullOrEmpty(genre))
{
continue;
}
diff --git a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs
index 80bb1a514..d113cabc7 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioFileProber.cs
@@ -13,6 +13,7 @@ using MediaBrowser.Controller.Lyrics;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -183,11 +184,11 @@ namespace MediaBrowser.Providers.MediaInfo
foreach (var albumArtist in albumArtists)
{
- if (!string.IsNullOrEmpty(albumArtist))
+ if (!string.IsNullOrWhiteSpace(albumArtist))
{
PeopleHelper.AddPerson(people, new PersonInfo
{
- Name = albumArtist,
+ Name = albumArtist.Trim(),
Type = PersonKind.AlbumArtist
});
}
@@ -215,11 +216,11 @@ namespace MediaBrowser.Providers.MediaInfo
foreach (var performer in performers)
{
- if (!string.IsNullOrEmpty(performer))
+ if (!string.IsNullOrWhiteSpace(performer))
{
PeopleHelper.AddPerson(people, new PersonInfo
{
- Name = performer,
+ Name = performer.Trim(),
Type = PersonKind.Artist
});
}
@@ -227,11 +228,11 @@ namespace MediaBrowser.Providers.MediaInfo
foreach (var composer in track.Composer.Split(InternalValueSeparator))
{
- if (!string.IsNullOrEmpty(composer))
+ if (!string.IsNullOrWhiteSpace(composer))
{
PeopleHelper.AddPerson(people, new PersonInfo
{
- Name = composer,
+ Name = composer.Trim(),
Type = PersonKind.Composer
});
}
@@ -273,13 +274,13 @@ namespace MediaBrowser.Providers.MediaInfo
if (options.ReplaceAllMetadata)
{
- audio.Album = track.Album;
+ audio.Album = track.Album.Trim();
audio.IndexNumber = track.TrackNumber;
audio.ParentIndexNumber = track.DiscNumber;
}
else
{
- audio.Album ??= track.Album;
+ audio.Album ??= track.Album.Trim();
audio.IndexNumber ??= track.TrackNumber;
audio.ParentIndexNumber ??= track.DiscNumber;
}
@@ -309,13 +310,15 @@ namespace MediaBrowser.Providers.MediaInfo
if (!audio.LockedFields.Contains(MetadataField.Genres))
{
- var genres = string.IsNullOrEmpty(track.Genre) ? mediaInfo.Genres : track.Genre.Split(InternalValueSeparator).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
+ var genres = string.IsNullOrEmpty(track.Genre) ? mediaInfo.Genres : track.Genre.Split(InternalValueSeparator);
if (libraryOptions.UseCustomTagDelimiters)
{
genres = genres.SelectMany(g => SplitWithCustomDelimiter(g, libraryOptions.CustomTagDelimiters, libraryOptions.DelimiterWhitelist)).ToArray();
}
+ genres = genres.Trimmed().Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
+
audio.Genres = options.ReplaceAllMetadata || audio.Genres is null || audio.Genres.Length == 0
? genres
: audio.Genres;
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 246ba2733..f486f150d 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -16,6 +16,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
@@ -400,7 +401,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
video.Genres = Array.Empty<string>();
- foreach (var genre in data.Genres)
+ foreach (var genre in data.Genres.Trimmed())
{
video.AddGenre(genre);
}
@@ -509,9 +510,9 @@ namespace MediaBrowser.Providers.MediaInfo
{
PeopleHelper.AddPerson(people, new PersonInfo
{
- Name = person.Name,
+ Name = person.Name.Trim(),
Type = person.Type,
- Role = person.Role
+ Role = person.Role.Trim()
});
}
diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
index a39bd16ce..daebe85d6 100644
--- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
@@ -187,7 +187,7 @@ namespace MediaBrowser.Providers.Music
{
PeopleHelper.AddPerson(people, new PersonInfo
{
- Name = albumArtist,
+ Name = albumArtist.Trim(),
Type = PersonKind.AlbumArtist
});
}
@@ -196,7 +196,7 @@ namespace MediaBrowser.Providers.Music
{
PeopleHelper.AddPerson(people, new PersonInfo
{
- Name = artist,
+ Name = artist.Trim(),
Type = PersonKind.Artist
});
}
diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
index de0da7f7b..ad9edb031 100644
--- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs
@@ -421,7 +421,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{
var person = new PersonInfo
{
- Name = result.Director,
+ Name = result.Director.Trim(),
Type = PersonKind.Director
};
@@ -432,7 +432,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb
{
var person = new PersonInfo
{
- Name = result.Writer,
+ Name = result.Writer.Trim(),
Type = PersonKind.Writer
};
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
index 8d68e2dcf..582e05b79 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
@@ -12,6 +12,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using TMDbLib.Objects.Find;
@@ -234,7 +235,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
var genres = movieResult.Genres;
- foreach (var genre in genres.Select(g => g.Name))
+ foreach (var genre in genres.Select(g => g.Name).Trimmed())
{
movie.AddGenre(genre);
}
@@ -254,7 +255,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character.Trim(),
Type = PersonKind.Actor,
SortOrder = actor.Order
};
@@ -289,7 +290,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
var personInfo = new PersonInfo
{
Name = person.Name.Trim(),
- Role = person.Job,
+ Role = person.Job?.Trim(),
Type = type
};
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
index e628abde5..4ee164553 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
@@ -211,7 +211,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
metadataResult.AddPerson(new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character.Trim(),
Type = PersonKind.Actor,
SortOrder = actor.Order
});
@@ -225,7 +225,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
metadataResult.AddPerson(new PersonInfo
{
Name = guest.Name.Trim(),
- Role = guest.Character,
+ Role = guest.Character.Trim(),
Type = PersonKind.GuestStar,
SortOrder = guest.Order
});
@@ -249,7 +249,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
metadataResult.AddPerson(new PersonInfo
{
Name = person.Name.Trim(),
- Role = person.Job,
+ Role = person.Job?.Trim(),
Type = type
});
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
index 3f208b599..b0a1e00df 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
@@ -82,12 +82,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
var cast = credits.Cast.OrderBy(c => c.Order).Take(Plugin.Instance.Configuration.MaxCastMembers).ToList();
for (var i = 0; i < cast.Count; i++)
{
+ var member = cast[i];
result.AddPerson(new PersonInfo
{
- Name = cast[i].Name.Trim(),
- Role = cast[i].Character,
+ Name = member.Name.Trim(),
+ Role = member.Character.Trim(),
Type = PersonKind.Actor,
- SortOrder = cast[i].Order
+ SortOrder = member.Order
});
}
}
@@ -108,7 +109,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
result.AddPerson(new PersonInfo
{
Name = person.Name.Trim(),
- Role = person.Job,
+ Role = person.Job?.Trim(),
Type = type
});
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
index e4062740f..9ace9c674 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
@@ -330,7 +330,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character.Trim(),
Type = PersonKind.Actor,
SortOrder = actor.Order,
ImageUrl = _tmdbClientManager.GetPosterUrl(actor.ProfilePath)
@@ -368,7 +368,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
yield return new PersonInfo
{
Name = person.Name.Trim(),
- Role = person.Job,
+ Role = person.Job?.Trim(),
Type = type
};
}
diff --git a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
index 2385e7048..4cb6f81b7 100644
--- a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -55,12 +56,12 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
var album = (MusicAlbum)item;
- foreach (var artist in album.Artists)
+ foreach (var artist in album.Artists.Trimmed().OrderBy(artist => artist))
{
writer.WriteElementString("artist", artist);
}
- foreach (var artist in album.AlbumArtists)
+ foreach (var artist in album.AlbumArtists.Trimmed().OrderBy(artist => artist))
{
writer.WriteElementString("albumartist", artist);
}
@@ -70,11 +71,19 @@ namespace MediaBrowser.XbmcMetadata.Savers
private void AddTracks(IEnumerable<BaseItem> tracks, XmlWriter writer)
{
- foreach (var track in tracks.OrderBy(i => i.ParentIndexNumber ?? 0).ThenBy(i => i.IndexNumber ?? 0))
+ foreach (var track in tracks
+ .OrderBy(i => i.ParentIndexNumber ?? 0)
+ .ThenBy(i => i.IndexNumber ?? 0)
+ .ThenBy(i => i.Name?.Trim()))
{
writer.WriteStartElement("track");
- if (track.IndexNumber.HasValue)
+ if (track.ParentIndexNumber.HasValue && track.ParentIndexNumber.Value != 0)
+ {
+ writer.WriteElementString("disc", track.ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ if (track.IndexNumber.HasValue && track.IndexNumber.Value != 0)
{
writer.WriteElementString("position", track.IndexNumber.Value.ToString(CultureInfo.InvariantCulture));
}
diff --git a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
index 813d75f6c..e13ba9385 100644
--- a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs
@@ -1,11 +1,13 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Xml;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.IO;
using MediaBrowser.XbmcMetadata.Configuration;
using Microsoft.Extensions.Logging;
@@ -69,7 +71,10 @@ namespace MediaBrowser.XbmcMetadata.Savers
private void AddAlbums(IList<BaseItem> albums, XmlWriter writer)
{
- foreach (var album in albums)
+ foreach (var album in albums
+ .OrderBy(album => album.ProductionYear ?? 0)
+ .ThenBy(album => album.SortName?.Trim())
+ .ThenBy(album => album.Name?.Trim()))
{
writer.WriteStartElement("album");
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 2afec3f6c..7c94b25c4 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -19,6 +19,7 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@@ -488,7 +489,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
var directors = people
.Where(i => i.IsType(PersonKind.Director))
- .Select(i => i.Name)
+ .Select(i => i.Name?.Trim())
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .OrderBy(i => i)
.ToList();
foreach (var person in directors)
@@ -498,8 +501,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
var writers = people
.Where(i => i.IsType(PersonKind.Writer))
- .Select(i => i.Name)
+ .Select(i => i.Name?.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
+ .OrderBy(i => i)
.ToList();
foreach (var person in writers)
@@ -512,7 +516,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("credits", person);
}
- foreach (var trailer in item.RemoteTrailers)
+ foreach (var trailer in item.RemoteTrailers.OrderBy(t => t.Url?.Trim()))
{
writer.WriteElementString("trailer", GetOutputTrailerUrl(trailer.Url));
}
@@ -660,22 +664,22 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("tagline", item.Tagline);
}
- foreach (var country in item.ProductionLocations)
+ foreach (var country in item.ProductionLocations.Trimmed().OrderBy(country => country))
{
writer.WriteElementString("country", country);
}
- foreach (var genre in item.Genres)
+ foreach (var genre in item.Genres.Trimmed().OrderBy(genre => genre))
{
writer.WriteElementString("genre", genre);
}
- foreach (var studio in item.Studios)
+ foreach (var studio in item.Studios.Trimmed().OrderBy(studio => studio))
{
writer.WriteElementString("studio", studio);
}
- foreach (var tag in item.Tags)
+ foreach (var tag in item.Tags.Trimmed().OrderBy(tag => tag))
{
if (item is MusicAlbum || item is MusicArtist)
{
@@ -752,7 +756,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (item.ProviderIds is not null)
{
- foreach (var providerKey in item.ProviderIds.Keys)
+ foreach (var providerKey in item.ProviderIds.Keys.OrderBy(providerKey => providerKey))
{
var providerId = item.ProviderIds[providerKey];
if (!string.IsNullOrEmpty(providerId) && !writtenProviderIds.Contains(providerKey))
@@ -764,7 +768,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
XmlConvert.VerifyName(tagName);
Logger.LogDebug("Saving custom provider tagname {0}", tagName);
- writer.WriteElementString(GetTagForProviderKey(providerKey), providerId);
+ writer.WriteElementString(tagName, providerId);
}
catch (ArgumentException)
{
@@ -785,7 +789,10 @@ namespace MediaBrowser.XbmcMetadata.Savers
AddUserData(item, writer, userManager, userDataRepo, options);
- AddActors(people, writer, libraryManager, options.SaveImagePathsInNfo);
+ if (item is not MusicAlbum && item is not MusicArtist)
+ {
+ AddActors(people, writer, libraryManager, options.SaveImagePathsInNfo);
+ }
if (item is BoxSet folder)
{
@@ -797,6 +804,8 @@ namespace MediaBrowser.XbmcMetadata.Savers
{
var items = item.LinkedChildren
.Where(i => i.Type == LinkedChildType.Manual)
+ .OrderBy(i => i.Path?.Trim())
+ .ThenBy(i => i.LibraryItemId?.Trim())
.ToList();
foreach (var link in items)
@@ -839,7 +848,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("poster", GetImagePathToSave(image, libraryManager));
}
- foreach (var backdrop in item.GetImages(ImageType.Backdrop))
+ foreach (var backdrop in item.GetImages(ImageType.Backdrop).OrderBy(b => b.Path?.Trim()))
{
writer.WriteElementString("fanart", GetImagePathToSave(backdrop, libraryManager));
}
@@ -913,7 +922,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
private void AddActors(List<PersonInfo> people, XmlWriter writer, ILibraryManager libraryManager, bool saveImagePath)
{
- foreach (var person in people)
+ foreach (var person in people
+ .OrderBy(person => person.SortOrder ?? 0)
+ .ThenBy(person => person.Name?.Trim()))
{
if (person.IsType(PersonKind.Director) || person.IsType(PersonKind.Writer))
{
diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
index bc344d87e..3ff8749e7 100644
--- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs
@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -100,7 +101,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (item is MusicVideo musicVideo)
{
- foreach (var artist in musicVideo.Artists)
+ foreach (var artist in musicVideo.Artists.Trimmed().OrderBy(artist => artist))
{
writer.WriteElementString("artist", artist);
}