diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 414488853f..8201ae318b 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 names) { - Studios = names.Distinct().ToArray(); + Studios = names.Trimmed().Distinct().ToArray(); } /// diff --git a/MediaBrowser.Controller/Entities/PeopleHelper.cs b/MediaBrowser.Controller/Entities/PeopleHelper.cs index 5292bd7727..d818604365 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 f9c0d39ddd..db934e0f47 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 Trimmed(this IEnumerable values) + { + return values.Select(i => (i ?? string.Empty).Trim()); + } } } diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index e4ac59b676..119effe791 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 334796f585..0dee77db81 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 pairs, MediaInfo info) { List peoples = new List(); + 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(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 80bb1a514c..d113cabc7f 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 246ba2733f..f486f150da 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(); - 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 a39bd16cea..daebe85d69 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 de0da7f7bd..ad9edb031c 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 8d68e2dcfe..582e05b793 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 e628abde55..4ee1645531 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 3f208b5993..b0a1e00df9 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 e4062740fe..9ace9c6743 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 2385e70485..4cb6f81b73 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 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 813d75f6c1..e13ba9385f 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 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 2afec3f6cd..7c94b25c4c 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 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 bc344d87e0..3ff8749e74 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); }