From 6fb6b5f1766a1f37a61b9faaa40209bab995bf30 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sun, 14 Apr 2024 08:18:36 -0600 Subject: Validate item access (#11171) --- Jellyfin.Api/Controllers/ItemUpdateController.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Api/Controllers/ItemUpdateController.cs') diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 9800248c6..83f308bb1 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; +using Jellyfin.Api.Extensions; +using Jellyfin.Api.Helpers; using Jellyfin.Data.Enums; using MediaBrowser.Common.Api; using MediaBrowser.Controller.Configuration; @@ -72,7 +74,7 @@ public class ItemUpdateController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task UpdateItem([FromRoute, Required] Guid itemId, [FromBody, Required] BaseItemDto request) { - var item = _libraryManager.GetItemById(itemId); + var item = _libraryManager.GetItemById(itemId, User.GetUserId()); if (item is null) { return NotFound(); @@ -145,7 +147,11 @@ public class ItemUpdateController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult GetMetadataEditorInfo([FromRoute, Required] Guid itemId) { - var item = _libraryManager.GetItemById(itemId); + var item = _libraryManager.GetItemById(itemId, User.GetUserId()); + if (item is null) + { + return NotFound(); + } var info = new MetadataEditorInfo { @@ -197,7 +203,7 @@ public class ItemUpdateController : BaseJellyfinApiController [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult UpdateItemContentType([FromRoute, Required] Guid itemId, [FromQuery] string? contentType) { - var item = _libraryManager.GetItemById(itemId); + var item = _libraryManager.GetItemById(itemId, User.GetUserId()); if (item is null) { return NotFound(); -- cgit v1.2.3 From a80968478a2620dd0c76c9069101231f086ddca5 Mon Sep 17 00:00:00 2001 From: Niels van Velzen Date: Mon, 22 Apr 2024 05:53:27 +0200 Subject: Fix InvalidCastException in ItemUpdateController (#11398) --- Jellyfin.Api/Controllers/ItemUpdateController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Api/Controllers/ItemUpdateController.cs') diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 83f308bb1..56ef5f8f1 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -288,7 +288,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (item is Series rseries) { - foreach (Season season in rseries.Children) + foreach (var season in rseries.Children.OfType()) { season.OfficialRating = request.OfficialRating; season.CustomRating = request.CustomRating; @@ -296,7 +296,7 @@ public class ItemUpdateController : BaseJellyfinApiController season.OnMetadataChanged(); await season.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); - foreach (Episode ep in season.Children) + foreach (var ep in season.Children.OfType()) { ep.OfficialRating = request.OfficialRating; ep.CustomRating = request.CustomRating; @@ -308,7 +308,7 @@ public class ItemUpdateController : BaseJellyfinApiController } else if (item is Season season) { - foreach (Episode ep in season.Children) + foreach (var ep in season.Children.OfType()) { ep.OfficialRating = request.OfficialRating; ep.CustomRating = request.CustomRating; -- cgit v1.2.3 From 3feb3f81bfe848aa829e7c129bee3cd060c23c05 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 30 Apr 2024 21:32:59 +0200 Subject: More efficient array creation (#11468) --- .../AppBase/BaseConfigurationManager.cs | 8 ++------ .../Data/SqliteItemRepository.cs | 14 ++------------ Emby.Server.Implementations/Library/IgnorePatterns.cs | 2 +- Emby.Server.Implementations/Library/LibraryManager.cs | 9 ++------- Emby.Server.Implementations/Library/UserViewManager.cs | 4 ++-- .../Playlists/PlaylistManager.cs | 11 +++-------- .../ScheduledTasks/ScheduledTaskWorker.cs | 7 +++---- Emby.Server.Implementations/Session/SessionManager.cs | 11 ++++------- Jellyfin.Api/Controllers/ItemUpdateController.cs | 12 +++--------- Jellyfin.Api/Controllers/LibraryController.cs | 4 ++-- Jellyfin.Api/Controllers/LibraryStructureController.cs | 2 +- Jellyfin.Api/Controllers/UserViewsController.cs | 9 ++------- Jellyfin.Api/Extensions/DtoExtensions.cs | 12 ++---------- MediaBrowser.Controller/Entities/BaseItem.cs | 18 ++++-------------- MediaBrowser.Controller/Entities/Extensions.cs | 8 ++------ MediaBrowser.Controller/Entities/TagExtensions.cs | 4 ++-- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 4 ++-- .../Net/BasePeriodicWebSocketListener.cs | 2 +- MediaBrowser.Controller/Session/SessionInfo.cs | 4 +--- MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs | 4 +--- src/Jellyfin.LiveTv/Channels/ChannelManager.cs | 2 +- src/Jellyfin.LiveTv/Listings/ListingsManager.cs | 14 ++++++-------- src/Jellyfin.LiveTv/LiveTvManager.cs | 2 +- src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs | 12 ++---------- src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs | 7 +++---- 25 files changed, 55 insertions(+), 131 deletions(-) (limited to 'Jellyfin.Api/Controllers/ItemUpdateController.cs') diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index a2f38c8c2..9e98d5ce0 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -127,15 +127,11 @@ namespace Emby.Server.Implementations.AppBase if (_configurationFactories is null) { - _configurationFactories = new[] { factory }; + _configurationFactories = [factory]; } else { - var oldLen = _configurationFactories.Length; - var arr = new IConfigurationFactory[oldLen + 1]; - _configurationFactories.CopyTo(arr, 0); - arr[oldLen] = factory; - _configurationFactories = arr; + _configurationFactories = [.._configurationFactories, factory]; } _configurationStores = _configurationFactories diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index e3015095c..9ef1bd66d 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -2323,14 +2323,7 @@ namespace Emby.Server.Implementations.Data columns.Add(builder.ToString()); - var oldLen = query.ExcludeItemIds.Length; - var newLen = oldLen + item.ExtraIds.Length + 1; - var excludeIds = new Guid[newLen]; - query.ExcludeItemIds.CopyTo(excludeIds, 0); - excludeIds[oldLen] = item.Id; - item.ExtraIds.CopyTo(excludeIds, oldLen + 1); - - query.ExcludeItemIds = excludeIds; + query.ExcludeItemIds = [..query.ExcludeItemIds, item.Id, ..item.ExtraIds]; query.ExcludeProviderIds = item.ProviderIds; } @@ -2838,10 +2831,7 @@ namespace Emby.Server.Implementations.Data prepend.Add((ItemSortBy.Random, SortOrder.Ascending)); } - var arr = new (ItemSortBy, SortOrder)[prepend.Count + orderBy.Count]; - prepend.CopyTo(arr, 0); - orderBy.CopyTo(arr, prepend.Count); - orderBy = query.OrderBy = arr; + orderBy = query.OrderBy = [..prepend, ..orderBy]; } else if (orderBy.Count == 0) { diff --git a/Emby.Server.Implementations/Library/IgnorePatterns.cs b/Emby.Server.Implementations/Library/IgnorePatterns.cs index cf6fc1845..a2301c8ae 100644 --- a/Emby.Server.Implementations/Library/IgnorePatterns.cs +++ b/Emby.Server.Implementations/Library/IgnorePatterns.cs @@ -103,7 +103,7 @@ namespace Emby.Server.Implementations.Library } }; - private static readonly Glob[] _globs = _patterns.Select(p => Glob.Parse(p, _globOptions)).ToArray(); + private static readonly Glob[] _globs = Array.ConvertAll(_patterns, p => Glob.Parse(p, _globOptions)); /// /// Returns true if the supplied path should be ignored. diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 3e41a5048..3b5714f8e 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -3038,9 +3038,7 @@ namespace Emby.Server.Implementations.Library { var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath); - var list = libraryOptions.PathInfos.ToList(); - list.Add(pathInfo); - libraryOptions.PathInfos = list.ToArray(); + libraryOptions.PathInfos = [..libraryOptions.PathInfos, pathInfo]; SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions); @@ -3059,8 +3057,7 @@ namespace Emby.Server.Implementations.Library SyncLibraryOptionsToLocations(virtualFolderPath, libraryOptions); - var list = libraryOptions.PathInfos.ToList(); - foreach (var originalPathInfo in list) + foreach (var originalPathInfo in libraryOptions.PathInfos) { if (string.Equals(mediaPath.Path, originalPathInfo.Path, StringComparison.Ordinal)) { @@ -3069,8 +3066,6 @@ namespace Emby.Server.Implementations.Library } } - libraryOptions.PathInfos = list.ToArray(); - CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions); } diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 83a66c8e4..d9a559014 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -303,8 +303,8 @@ namespace Emby.Server.Implementations.Library { // Handle situations with the grouping setting, e.g. movies showing up in tv, etc. // Thanks to mixed content libraries included in the UserView - var hasCollectionType = parents.OfType().ToArray(); - if (hasCollectionType.Length > 0) + var hasCollectionType = parents.OfType().ToList(); + if (hasCollectionType.Count > 0) { if (hasCollectionType.All(i => i.CollectionType == CollectionType.movies)) { diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 7a6cf9eff..6007591b2 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -226,13 +226,8 @@ namespace Emby.Server.Implementations.Playlists return; } - // Create a new array with the updated playlist items - var newLinkedChildren = new LinkedChild[playlist.LinkedChildren.Length + childrenToAdd.Count]; - playlist.LinkedChildren.CopyTo(newLinkedChildren, 0); - childrenToAdd.CopyTo(newLinkedChildren, playlist.LinkedChildren.Length); - // Update the playlist in the repository - playlist.LinkedChildren = newLinkedChildren; + playlist.LinkedChildren = [..playlist.LinkedChildren, ..childrenToAdd]; await UpdatePlaylistInternal(playlist).ConfigureAwait(false); @@ -526,8 +521,8 @@ namespace Emby.Server.Implementations.Playlists foreach (var playlist in playlists) { // Update owner if shared - var rankedShares = playlist.Shares.OrderByDescending(x => x.CanEdit).ToArray(); - if (rankedShares.Length > 0) + var rankedShares = playlist.Shares.OrderByDescending(x => x.CanEdit).ToList(); + if (rankedShares.Count > 0) { playlist.OwnerUserId = rankedShares[0].UserId; playlist.Shares = rankedShares.Skip(1).ToArray(); diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index efb6436ae..40e1bbf15 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -256,8 +256,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { get { - var triggers = InternalTriggers; - return triggers.Select(i => i.Item1).ToArray(); + return Array.ConvertAll(InternalTriggers, i => i.Item1); } set @@ -269,7 +268,7 @@ namespace Emby.Server.Implementations.ScheduledTasks SaveTriggers(triggerList); - InternalTriggers = triggerList.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); + InternalTriggers = Array.ConvertAll(triggerList, i => new Tuple(i, GetTrigger(i))); } } @@ -503,7 +502,7 @@ namespace Emby.Server.Implementations.ScheduledTasks private Tuple[] LoadTriggers() { // This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly - var settings = LoadTriggerSettings().Where(i => i is not null).ToArray(); + var settings = LoadTriggerSettings().Where(i => i is not null); return settings.Select(i => new Tuple(i, GetTrigger(i))).ToArray(); } diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 06798628f..10d5b4f97 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -400,7 +400,7 @@ namespace Emby.Server.Implementations.Session { session.NowPlayingQueue = nowPlayingQueue; - var itemIds = nowPlayingQueue.Select(queue => queue.Id).ToArray(); + var itemIds = Array.ConvertAll(nowPlayingQueue, queue => queue.Id); session.NowPlayingQueueFullItems = _dtoService.GetBaseItemDtos( _libraryManager.GetItemList(new InternalItemsQuery { ItemIds = itemIds }), new DtoOptions(true)); @@ -1386,16 +1386,13 @@ namespace Emby.Server.Implementations.Session if (session.AdditionalUsers.All(i => !i.UserId.Equals(userId))) { var user = _userManager.GetUserById(userId); - - var list = session.AdditionalUsers.ToList(); - - list.Add(new SessionUserInfo + var newUser = new SessionUserInfo { UserId = userId, UserName = user.Username - }); + }; - session.AdditionalUsers = list.ToArray(); + session.AdditionalUsers = [..session.AdditionalUsers, newUser]; } } diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index 56ef5f8f1..b4ce343be 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -264,7 +264,7 @@ public class ItemUpdateController : BaseJellyfinApiController if (request.Studios is not null) { - item.Studios = request.Studios.Select(x => x.Name).ToArray(); + item.Studios = Array.ConvertAll(request.Studios, x => x.Name); } if (request.DateCreated.HasValue) @@ -379,10 +379,7 @@ public class ItemUpdateController : BaseJellyfinApiController { if (item is IHasAlbumArtist hasAlbumArtists) { - hasAlbumArtists.AlbumArtists = request - .AlbumArtists - .Select(i => i.Name) - .ToArray(); + hasAlbumArtists.AlbumArtists = Array.ConvertAll(request.AlbumArtists, i => i.Name); } } @@ -390,10 +387,7 @@ public class ItemUpdateController : BaseJellyfinApiController { if (item is IHasArtist hasArtists) { - hasArtists.Artists = request - .ArtistItems - .Select(i => i.Name) - .ToArray(); + hasArtists.Artists = Array.ConvertAll(request.ArtistItems, i => i.Name); } } diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 3b4e80ff3..64df4c4f0 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -158,13 +158,13 @@ public class LibraryController : BaseJellyfinApiController return NotFound(); } - IEnumerable themeItems; + IReadOnlyList themeItems; while (true) { themeItems = item.GetThemeSongs(); - if (themeItems.Any() || !inheritFromParent) + if (themeItems.Count > 0 || !inheritFromParent) { break; } diff --git a/Jellyfin.Api/Controllers/LibraryStructureController.cs b/Jellyfin.Api/Controllers/LibraryStructureController.cs index f685eeaa0..fb9f44d46 100644 --- a/Jellyfin.Api/Controllers/LibraryStructureController.cs +++ b/Jellyfin.Api/Controllers/LibraryStructureController.cs @@ -85,7 +85,7 @@ public class LibraryStructureController : BaseJellyfinApiController if (paths is not null && paths.Length > 0) { - libraryOptions.PathInfos = paths.Select(i => new MediaPathInfo(i)).ToArray(); + libraryOptions.PathInfos = Array.ConvertAll(paths, i => new MediaPathInfo(i)); } await _libraryManager.AddVirtualFolder(name, collectionType, libraryOptions, refreshLibrary).ConfigureAwait(false); diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index bf3ce1d39..01da50d02 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -85,16 +85,11 @@ public class UserViewsController : BaseJellyfinApiController var folders = _userViewManager.GetUserViews(query); var dtoOptions = new DtoOptions().AddClientFields(User); - var fields = dtoOptions.Fields.ToList(); - - fields.Add(ItemFields.PrimaryImageAspectRatio); - fields.Add(ItemFields.DisplayPreferencesId); - dtoOptions.Fields = fields.ToArray(); + dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.PrimaryImageAspectRatio, ItemFields.DisplayPreferencesId]; var user = _userManager.GetUserById(userId.Value); - var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)) - .ToArray(); + var dtos = Array.ConvertAll(folders, i => _dtoService.GetBaseItemDto(i, dtoOptions, user)); return new QueryResult(dtos); } diff --git a/Jellyfin.Api/Extensions/DtoExtensions.cs b/Jellyfin.Api/Extensions/DtoExtensions.cs index 7d9823c25..3d17dbda1 100644 --- a/Jellyfin.Api/Extensions/DtoExtensions.cs +++ b/Jellyfin.Api/Extensions/DtoExtensions.cs @@ -43,11 +43,7 @@ public static class DtoExtensions client.Contains("media center", StringComparison.OrdinalIgnoreCase) || client.Contains("classic", StringComparison.OrdinalIgnoreCase)) { - int oldLen = dtoOptions.Fields.Count; - var arr = new ItemFields[oldLen + 1]; - dtoOptions.Fields.CopyTo(arr, 0); - arr[oldLen] = ItemFields.RecursiveItemCount; - dtoOptions.Fields = arr; + dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.RecursiveItemCount]; } } @@ -61,11 +57,7 @@ public static class DtoExtensions client.Contains("samsung", StringComparison.OrdinalIgnoreCase) || client.Contains("androidtv", StringComparison.OrdinalIgnoreCase)) { - int oldLen = dtoOptions.Fields.Count; - var arr = new ItemFields[oldLen + 1]; - dtoOptions.Fields.CopyTo(arr, 0); - arr[oldLen] = ItemFields.ChildCount; - dtoOptions.Fields = arr; + dtoOptions.Fields = [..dtoOptions.Fields, ItemFields.ChildCount]; } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 6c9097689..22793206e 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1779,14 +1779,11 @@ namespace MediaBrowser.Controller.Entities int curLen = current.Length; if (curLen == 0) { - Studios = new[] { name }; + Studios = [name]; } else { - var newArr = new string[curLen + 1]; - current.CopyTo(newArr, 0); - newArr[curLen] = name; - Studios = newArr; + Studios = [..current, name]; } } } @@ -1808,9 +1805,7 @@ namespace MediaBrowser.Controller.Entities var genres = Genres; if (!genres.Contains(name, StringComparison.OrdinalIgnoreCase)) { - var list = genres.ToList(); - list.Add(name); - Genres = list.ToArray(); + Genres = [..genres, name]; } } @@ -1980,12 +1975,7 @@ namespace MediaBrowser.Controller.Entities public void AddImage(ItemImageInfo image) { - var current = ImageInfos; - var currentCount = current.Length; - var newArr = new ItemImageInfo[currentCount + 1]; - current.CopyTo(newArr, 0); - newArr[currentCount] = image; - ImageInfos = newArr; + ImageInfos = [..ImageInfos, image]; } public virtual Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs index 3005bee0a..c56603a3e 100644 --- a/MediaBrowser.Controller/Entities/Extensions.cs +++ b/MediaBrowser.Controller/Entities/Extensions.cs @@ -30,15 +30,11 @@ namespace MediaBrowser.Controller.Entities if (item.RemoteTrailers.Count == 0) { - item.RemoteTrailers = new[] { mediaUrl }; + item.RemoteTrailers = [mediaUrl]; } else { - var oldIds = item.RemoteTrailers; - var newIds = new MediaUrl[oldIds.Count + 1]; - oldIds.CopyTo(newIds); - newIds[oldIds.Count] = mediaUrl; - item.RemoteTrailers = newIds; + item.RemoteTrailers = [..item.RemoteTrailers, mediaUrl]; } } } diff --git a/MediaBrowser.Controller/Entities/TagExtensions.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs index ec3eb0f70..c1e4d1db2 100644 --- a/MediaBrowser.Controller/Entities/TagExtensions.cs +++ b/MediaBrowser.Controller/Entities/TagExtensions.cs @@ -21,11 +21,11 @@ namespace MediaBrowser.Controller.Entities { if (current.Length == 0) { - item.Tags = new[] { name }; + item.Tags = [name]; } else { - item.Tags = current.Concat(new[] { name }).ToArray(); + item.Tags = [..current, name]; } } } diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 6202f92f5..b558ef73d 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -116,8 +116,8 @@ namespace MediaBrowser.Controller.Library { get { - var paths = string.IsNullOrEmpty(Path) ? Array.Empty() : new[] { Path }; - return AdditionalLocations is null ? paths : paths.Concat(AdditionalLocations).ToArray(); + var paths = string.IsNullOrEmpty(Path) ? Array.Empty() : [Path]; + return AdditionalLocations is null ? paths : [..paths, ..AdditionalLocations]; } } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 06386f2b8..a47d2fa45 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -288,7 +288,7 @@ namespace MediaBrowser.Controller.Net lock (_activeConnectionsLock) { - foreach (var connection in _activeConnections.ToArray()) + foreach (var connection in _activeConnections.ToList()) { DisposeConnection(connection); } diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 76d5d3a3f..9e3358818 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -270,9 +270,7 @@ namespace MediaBrowser.Controller.Session public void AddController(ISessionController controller) { - var controllers = SessionControllers.ToList(); - controllers.Add(controller); - SessionControllers = controllers.ToArray(); + SessionControllers = [..SessionControllers, controller]; } public bool ContainsUser(Guid userId) diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs index 16ea5e3ea..af867cd59 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs @@ -117,9 +117,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers var artist = reader.ReadNormalizedString(); if (!string.IsNullOrEmpty(artist) && item is MusicVideo artistVideo) { - var list = artistVideo.Artists.ToList(); - list.Add(artist); - artistVideo.Artists = list.ToArray(); + artistVideo.Artists = [..artistVideo.Artists, artist]; } break; diff --git a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs index cce2911dc..83f68ab50 100644 --- a/src/Jellyfin.LiveTv/Channels/ChannelManager.cs +++ b/src/Jellyfin.LiveTv/Channels/ChannelManager.cs @@ -1130,7 +1130,7 @@ namespace Jellyfin.LiveTv.Channels { if (!item.Tags.Contains("livestream", StringComparison.OrdinalIgnoreCase)) { - item.Tags = item.Tags.Concat(new[] { "livestream" }).ToArray(); + item.Tags = [..item.Tags, "livestream"]; _logger.LogDebug("Forcing update due to Tags {0}", item.Name); forceUpdate = true; } diff --git a/src/Jellyfin.LiveTv/Listings/ListingsManager.cs b/src/Jellyfin.LiveTv/Listings/ListingsManager.cs index 87f47611e..dfd376092 100644 --- a/src/Jellyfin.LiveTv/Listings/ListingsManager.cs +++ b/src/Jellyfin.LiveTv/Listings/ListingsManager.cs @@ -60,14 +60,13 @@ public class ListingsManager : IListingsManager var config = _config.GetLiveTvConfiguration(); - var list = config.ListingProviders.ToList(); - int index = list.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + var list = config.ListingProviders; + int index = Array.FindIndex(list, i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) { info.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - list.Add(info); - config.ListingProviders = list.ToArray(); + config.ListingProviders = [..list, info]; } else { @@ -236,13 +235,12 @@ public class ListingsManager : IListingsManager if (!string.Equals(tunerChannelNumber, providerChannelNumber, StringComparison.OrdinalIgnoreCase)) { - var list = listingsProviderInfo.ChannelMappings.ToList(); - list.Add(new NameValuePair + var newItem = new NameValuePair { Name = tunerChannelNumber, Value = providerChannelNumber - }); - listingsProviderInfo.ChannelMappings = list.ToArray(); + }; + listingsProviderInfo.ChannelMappings = [..listingsProviderInfo.ChannelMappings, newItem]; } _config.SaveConfiguration("livetv", config); diff --git a/src/Jellyfin.LiveTv/LiveTvManager.cs b/src/Jellyfin.LiveTv/LiveTvManager.cs index c19d8195c..0c85dc434 100644 --- a/src/Jellyfin.LiveTv/LiveTvManager.cs +++ b/src/Jellyfin.LiveTv/LiveTvManager.cs @@ -939,7 +939,7 @@ namespace Jellyfin.LiveTv { var internalChannelId = _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId); var channel = _libraryManager.GetItemById(internalChannelId); - channelName = channel is null ? null : channel.Name; + channelName = channel?.Name; } return _tvDtoService.GetSeriesTimerInfoDto(i.Item1, i.Item2, channelName); diff --git a/src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs b/src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs index 18e4810a2..9e7323f5b 100644 --- a/src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs +++ b/src/Jellyfin.LiveTv/Timers/ItemDataProvider.cs @@ -115,11 +115,7 @@ namespace Jellyfin.LiveTv.Timers throw new ArgumentException("item already exists", nameof(item)); } - int oldLen = _items.Length; - var newList = new T[oldLen + 1]; - _items.CopyTo(newList, 0); - newList[oldLen] = item; - _items = newList; + _items = [.._items, item]; SaveList(); } @@ -134,11 +130,7 @@ namespace Jellyfin.LiveTv.Timers int index = Array.FindIndex(_items, i => EqualityComparer(i, item)); if (index == -1) { - int oldLen = _items.Length; - var newList = new T[oldLen + 1]; - _items.CopyTo(newList, 0); - newList[oldLen] = item; - _items = newList; + _items = [.._items, item]; } else { diff --git a/src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs b/src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs index 60be19c68..473f00153 100644 --- a/src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs +++ b/src/Jellyfin.LiveTv/TunerHosts/TunerHostManager.cs @@ -76,14 +76,13 @@ public class TunerHostManager : ITunerHostManager var config = _config.GetLiveTvConfiguration(); - var list = config.TunerHosts.ToList(); - var index = list.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); + var list = config.TunerHosts; + var index = Array.FindIndex(list, i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) { info.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - list.Add(info); - config.TunerHosts = list.ToArray(); + config.TunerHosts = [..list, info]; } else { -- cgit v1.2.3 From 5d4880c4974a8399d178147fcc4e78e1aed191e9 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 1 Jun 2024 18:40:56 -0400 Subject: Backport pull request #11743 from jellyfin/release-10.9.z Fix replace logic Original-merge: 2ddb15c7845a944d980364209c2304f03cebf025 Merged-by: joshuaboniface Backported-by: Joshua M. Boniface --- .../Data/SqliteItemRepository.cs | 9 +- .../Library/LibraryManager.cs | 6 +- Jellyfin.Api/Controllers/ItemUpdateController.cs | 52 ++++++- MediaBrowser.Controller/Entities/BaseItem.cs | 3 - MediaBrowser.Controller/Entities/Movies/Movie.cs | 3 - MediaBrowser.Controller/Entities/TV/Series.cs | 6 +- MediaBrowser.Controller/Entities/Trailer.cs | 3 - MediaBrowser.Providers/Manager/MetadataService.cs | 165 +++++++++++---------- .../Movies/MovieMetadataService.cs | 16 -- .../Movies/TrailerMetadataService.cs | 21 +-- .../Music/AlbumMetadataService.cs | 4 + .../Music/AudioMetadataService.cs | 5 + .../Music/MusicVideoMetadataService.cs | 5 + .../Playlists/PlaylistMetadataService.cs | 21 ++- MediaBrowser.Providers/TV/SeriesMetadataService.cs | 16 -- .../Manager/MetadataServiceTests.cs | 5 +- 16 files changed, 181 insertions(+), 159 deletions(-) (limited to 'Jellyfin.Api/Controllers/ItemUpdateController.cs') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 34d753093..d27b7185a 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -5222,19 +5222,20 @@ AND Type = @InternalPersonType)"); throw new ArgumentNullException(nameof(itemId)); } - ArgumentNullException.ThrowIfNull(people); - CheckDisposed(); using var connection = GetConnection(); using var transaction = connection.BeginTransaction(); - // First delete chapters + // Delete all existing people first using var command = connection.CreateCommand(); command.CommandText = "delete from People where ItemId=@ItemId"; command.TryBind("@ItemId", itemId); command.ExecuteNonQuery(); - InsertPeople(itemId, people, connection); + if (people is not null) + { + InsertPeople(itemId, people, connection); + } transaction.Commit(); } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index cca835e4f..e66f2496a 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2812,8 +2812,10 @@ namespace Emby.Server.Implementations.Library } _itemRepository.UpdatePeople(item.Id, people); - - await SavePeopleMetadataAsync(people, cancellationToken).ConfigureAwait(false); + if (people is not null) + { + await SavePeopleMetadataAsync(people, cancellationToken).ConfigureAwait(false); + } } public async Task ConvertImageToLocal(BaseItem item, ItemImageInfo image, int imageIndex, bool removeOnFailure) diff --git a/Jellyfin.Api/Controllers/ItemUpdateController.cs b/Jellyfin.Api/Controllers/ItemUpdateController.cs index b4ce343be..4001a6add 100644 --- a/Jellyfin.Api/Controllers/ItemUpdateController.cs +++ b/Jellyfin.Api/Controllers/ItemUpdateController.cs @@ -290,17 +290,35 @@ public class ItemUpdateController : BaseJellyfinApiController { foreach (var season in rseries.Children.OfType()) { - season.OfficialRating = request.OfficialRating; + if (!season.LockedFields.Contains(MetadataField.OfficialRating)) + { + season.OfficialRating = request.OfficialRating; + } + season.CustomRating = request.CustomRating; - season.Tags = season.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + + if (!season.LockedFields.Contains(MetadataField.Tags)) + { + season.Tags = season.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + } + season.OnMetadataChanged(); await season.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); foreach (var ep in season.Children.OfType()) { - ep.OfficialRating = request.OfficialRating; + if (!ep.LockedFields.Contains(MetadataField.OfficialRating)) + { + ep.OfficialRating = request.OfficialRating; + } + ep.CustomRating = request.CustomRating; - ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + + if (!ep.LockedFields.Contains(MetadataField.Tags)) + { + ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + } + ep.OnMetadataChanged(); await ep.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); } @@ -310,9 +328,18 @@ public class ItemUpdateController : BaseJellyfinApiController { foreach (var ep in season.Children.OfType()) { - ep.OfficialRating = request.OfficialRating; + if (!ep.LockedFields.Contains(MetadataField.OfficialRating)) + { + ep.OfficialRating = request.OfficialRating; + } + ep.CustomRating = request.CustomRating; - ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + + if (!ep.LockedFields.Contains(MetadataField.Tags)) + { + ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + } + ep.OnMetadataChanged(); await ep.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); } @@ -321,9 +348,18 @@ public class ItemUpdateController : BaseJellyfinApiController { foreach (BaseItem track in album.Children) { - track.OfficialRating = request.OfficialRating; + if (!track.LockedFields.Contains(MetadataField.OfficialRating)) + { + track.OfficialRating = request.OfficialRating; + } + track.CustomRating = request.CustomRating; - track.Tags = track.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + + if (!track.LockedFields.Contains(MetadataField.Tags)) + { + track.Tags = track.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray(); + } + track.OnMetadataChanged(); await track.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 22793206e..184bb4d68 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -751,9 +751,6 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public virtual bool SupportsAncestors => true; - [JsonIgnore] - public virtual bool StopRefreshIfLocalMetadataFound => true; - [JsonIgnore] protected virtual bool SupportsOwnedItems => !ParentId.IsEmpty() && IsFileProtocol; diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 81f6248fa..ede544eec 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -45,9 +45,6 @@ namespace MediaBrowser.Controller.Entities.Movies set => TmdbCollectionName = value; } - [JsonIgnore] - public override bool StopRefreshIfLocalMetadataFound => false; - public override double GetDefaultPrimaryImageAspectRatio() { // hack for tv plugins diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index e7a8a773e..8b4108b69 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -69,9 +69,6 @@ namespace MediaBrowser.Controller.Entities.TV /// The status. public SeriesStatus? Status { get; set; } - [JsonIgnore] - public override bool StopRefreshIfLocalMetadataFound => false; - public override double GetDefaultPrimaryImageAspectRatio() { double value = 2; @@ -288,8 +285,7 @@ namespace MediaBrowser.Controller.Entities.TV public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress progress, CancellationToken cancellationToken) { - // Refresh bottom up, children first, then the boxset - // By then hopefully the movies within will have Tmdb collection values + // Refresh bottom up, seasons and episodes first, then the series var items = GetRecursiveChildren(); var totalItems = items.Count; diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 1c558d419..81d50bbc1 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -23,9 +23,6 @@ namespace MediaBrowser.Controller.Entities TrailerTypes = Array.Empty(); } - [JsonIgnore] - public override bool StopRefreshIfLocalMetadataFound => false; - public TrailerType[] TrailerTypes { get; set; } public override double GetDefaultPrimaryImageAspectRatio() diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 234c5869a..0a98967da 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -121,7 +121,8 @@ namespace MediaBrowser.Providers.Manager var metadataResult = new MetadataResult { - Item = itemOfType + Item = itemOfType, + People = LibraryManager.GetPeople(item) }; bool hasRefreshedMetadata = true; @@ -164,7 +165,7 @@ namespace MediaBrowser.Providers.Manager } // Next run remote image providers, but only if local image providers didn't throw an exception - if (!localImagesFailed && refreshOptions.ImageRefreshMode != MetadataRefreshMode.ValidationOnly) + if (!localImagesFailed && refreshOptions.ImageRefreshMode > MetadataRefreshMode.ValidationOnly) { var providers = GetNonLocalImageProviders(item, allImageProviders, refreshOptions).ToList(); @@ -242,7 +243,7 @@ namespace MediaBrowser.Providers.Manager protected async Task SaveItemAsync(MetadataResult result, ItemUpdateType reason, CancellationToken cancellationToken) { - if (result.Item.SupportsPeople && result.People is not null) + if (result.Item.SupportsPeople) { var baseItem = result.Item; @@ -655,26 +656,19 @@ namespace MediaBrowser.Providers.Manager await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); } + if (item.IsLocked) + { + return refreshResult; + } + var temp = new MetadataResult { Item = CreateNew() }; temp.Item.Path = item.Path; + temp.Item.Id = item.Id; - // If replacing all metadata, run internet providers first - if (options.ReplaceAllMetadata) - { - var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType>(), cancellationToken) - .ConfigureAwait(false); - - refreshResult.UpdateType |= remoteResult.UpdateType; - refreshResult.ErrorMessage = remoteResult.ErrorMessage; - refreshResult.Failures += remoteResult.Failures; - } - - var hasLocalMetadata = false; var foundImageTypes = new List(); - foreach (var provider in providers.OfType>()) { var providerName = provider.GetType().Name; @@ -720,15 +714,9 @@ namespace MediaBrowser.Providers.Manager refreshResult.UpdateType |= ItemUpdateType.ImageUpdate; } - MergeData(localItem, temp, Array.Empty(), options.ReplaceAllMetadata, true); + MergeData(localItem, temp, Array.Empty(), false, true); refreshResult.UpdateType |= ItemUpdateType.MetadataImport; - // Only one local provider allowed per item - if (item.IsLocked || localItem.Item.IsLocked || IsFullLocalMetadata(localItem.Item)) - { - hasLocalMetadata = true; - } - break; } @@ -747,10 +735,10 @@ namespace MediaBrowser.Providers.Manager } } - // Local metadata is king - if any is found don't run remote providers - if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || !item.StopRefreshIfLocalMetadataFound)) + var isLocalLocked = temp.Item.IsLocked; + if (!isLocalLocked && (options.ReplaceAllMetadata || options.MetadataRefreshMode > MetadataRefreshMode.ValidationOnly)) { - var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType>(), cancellationToken) + var remoteResult = await ExecuteRemoteProviders(temp, logName, false, id, providers.OfType>(), cancellationToken) .ConfigureAwait(false); refreshResult.UpdateType |= remoteResult.UpdateType; @@ -762,19 +750,20 @@ namespace MediaBrowser.Providers.Manager { if (refreshResult.UpdateType > ItemUpdateType.None) { - if (hasLocalMetadata) + if (!options.RemoveOldMetadata) + { + // Add existing metadata to provider result if it does not exist there + MergeData(metadata, temp, Array.Empty(), false, false); + } + + if (isLocalLocked) { MergeData(temp, metadata, item.LockedFields, true, true); } else { - if (!options.RemoveOldMetadata) - { - MergeData(metadata, temp, Array.Empty(), false, false); - } - - // Will always replace all metadata when Scan for new and updated files is used. Else, follow the options. - MergeData(temp, metadata, item.LockedFields, options.MetadataRefreshMode == MetadataRefreshMode.Default || options.ReplaceAllMetadata, false); + var shouldReplace = options.MetadataRefreshMode > MetadataRefreshMode.ValidationOnly || options.ReplaceAllMetadata; + MergeData(temp, metadata, item.LockedFields, shouldReplace, false); } } } @@ -787,16 +776,6 @@ namespace MediaBrowser.Providers.Manager return refreshResult; } - protected virtual bool IsFullLocalMetadata(TItemType item) - { - if (string.IsNullOrWhiteSpace(item.Name)) - { - return false; - } - - return true; - } - private async Task RunCustomProvider(ICustomMetadataProvider provider, TItemType item, string logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) { Logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, logName); @@ -821,7 +800,7 @@ namespace MediaBrowser.Providers.Manager return new TItemType(); } - private async Task ExecuteRemoteProviders(MetadataResult temp, string logName, TIdType id, IEnumerable> providers, CancellationToken cancellationToken) + private async Task ExecuteRemoteProviders(MetadataResult temp, string logName, bool replaceData, TIdType id, IEnumerable> providers, CancellationToken cancellationToken) { var refreshResult = new RefreshResult(); @@ -846,7 +825,7 @@ namespace MediaBrowser.Providers.Manager { result.Provider = provider.Name; - MergeData(result, temp, Array.Empty(), false, false); + MergeData(result, temp, Array.Empty(), replaceData, false); MergeNewData(temp.Item, id); refreshResult.UpdateType |= ItemUpdateType.MetadataDownload; @@ -949,11 +928,7 @@ namespace MediaBrowser.Providers.Manager if (replaceData || string.IsNullOrEmpty(target.OriginalTitle)) { - // Safeguard against incoming data having an empty name - if (!string.IsNullOrWhiteSpace(source.OriginalTitle)) - { - target.OriginalTitle = source.OriginalTitle; - } + target.OriginalTitle = source.OriginalTitle; } if (replaceData || !target.CommunityRating.HasValue) @@ -1016,7 +991,7 @@ namespace MediaBrowser.Providers.Manager { targetResult.People = sourceResult.People; } - else if (targetResult.People is not null && sourceResult.People is not null) + else if (sourceResult.People is not null && sourceResult.People.Count >= 0) { MergePeople(sourceResult.People, targetResult.People); } @@ -1049,6 +1024,10 @@ namespace MediaBrowser.Providers.Manager { target.Studios = source.Studios; } + else + { + target.Studios = target.Studios.Concat(source.Studios).Distinct().ToArray(); + } } if (!lockedFields.Contains(MetadataField.Tags)) @@ -1057,6 +1036,10 @@ namespace MediaBrowser.Providers.Manager { target.Tags = source.Tags; } + else + { + target.Tags = target.Tags.Concat(source.Tags).Distinct().ToArray(); + } } if (!lockedFields.Contains(MetadataField.ProductionLocations)) @@ -1065,6 +1048,10 @@ namespace MediaBrowser.Providers.Manager { target.ProductionLocations = source.ProductionLocations; } + else + { + target.Tags = target.ProductionLocations.Concat(source.ProductionLocations).Distinct().ToArray(); + } } foreach (var id in source.ProviderIds) @@ -1082,17 +1069,28 @@ namespace MediaBrowser.Providers.Manager } } + if (replaceData || !target.CriticRating.HasValue) + { + target.CriticRating = source.CriticRating; + } + + if (replaceData || target.RemoteTrailers.Count == 0) + { + target.RemoteTrailers = source.RemoteTrailers; + } + else + { + target.RemoteTrailers = target.RemoteTrailers.Concat(source.RemoteTrailers).Distinct().ToArray(); + } + MergeAlbumArtist(source, target, replaceData); - MergeCriticRating(source, target, replaceData); - MergeTrailers(source, target, replaceData); MergeVideoInfo(source, target, replaceData); MergeDisplayOrder(source, target, replaceData); if (replaceData || string.IsNullOrEmpty(target.ForcedSortName)) { var forcedSortName = source.ForcedSortName; - - if (!string.IsNullOrWhiteSpace(forcedSortName)) + if (!string.IsNullOrEmpty(forcedSortName)) { target.ForcedSortName = forcedSortName; } @@ -1100,22 +1098,44 @@ namespace MediaBrowser.Providers.Manager if (mergeMetadataSettings) { - target.LockedFields = source.LockedFields; - target.IsLocked = source.IsLocked; + if (replaceData || !target.IsLocked) + { + target.IsLocked = target.IsLocked || source.IsLocked; + } + + if (target.LockedFields.Length == 0) + { + target.LockedFields = source.LockedFields; + } + else + { + target.LockedFields = target.LockedFields.Concat(source.LockedFields).Distinct().ToArray(); + } - // Grab the value if it's there, but if not then don't overwrite with the default if (source.DateCreated != default) { target.DateCreated = source.DateCreated; } - target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode; - target.PreferredMetadataLanguage = source.PreferredMetadataLanguage; + if (replaceData || string.IsNullOrEmpty(target.PreferredMetadataCountryCode)) + { + target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode; + } + + if (replaceData || string.IsNullOrEmpty(target.PreferredMetadataLanguage)) + { + target.PreferredMetadataLanguage = source.PreferredMetadataLanguage; + } } } private static void MergePeople(List source, List target) { + if (target is null) + { + target = new List(); + } + foreach (var person in target) { var normalizedName = person.Name.RemoveDiacritics(); @@ -1144,7 +1164,6 @@ namespace MediaBrowser.Providers.Manager if (replaceData || string.IsNullOrEmpty(targetHasDisplayOrder.DisplayOrder)) { var displayOrder = sourceHasDisplayOrder.DisplayOrder; - if (!string.IsNullOrWhiteSpace(displayOrder)) { targetHasDisplayOrder.DisplayOrder = displayOrder; @@ -1162,22 +1181,10 @@ namespace MediaBrowser.Providers.Manager { targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists; } - } - } - - private static void MergeCriticRating(BaseItem source, BaseItem target, bool replaceData) - { - if (replaceData || !target.CriticRating.HasValue) - { - target.CriticRating = source.CriticRating; - } - } - - private static void MergeTrailers(BaseItem source, BaseItem target, bool replaceData) - { - if (replaceData || target.RemoteTrailers.Count == 0) - { - target.RemoteTrailers = source.RemoteTrailers; + else if (sourceHasAlbumArtist.AlbumArtists.Count >= 0) + { + targetHasAlbumArtist.AlbumArtists = targetHasAlbumArtist.AlbumArtists.Concat(sourceHasAlbumArtist.AlbumArtists).Distinct().ToArray(); + } } } @@ -1185,7 +1192,7 @@ namespace MediaBrowser.Providers.Manager { if (source is Video sourceCast && target is Video targetCast) { - if (replaceData || targetCast.Video3DFormat is null) + if (replaceData || !targetCast.Video3DFormat.HasValue) { targetCast.Video3DFormat = sourceCast.Video3DFormat; } diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index 984a3c122..8997ddc64 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -23,22 +23,6 @@ namespace MediaBrowser.Providers.Movies { } - /// - protected override bool IsFullLocalMetadata(Movie item) - { - if (string.IsNullOrWhiteSpace(item.Overview)) - { - return false; - } - - if (!item.ProductionYear.HasValue) - { - return false; - } - - return base.IsFullLocalMetadata(item); - } - /// protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { diff --git a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs index ad0c5aaa7..e77d2fa8a 100644 --- a/MediaBrowser.Providers/Movies/TrailerMetadataService.cs +++ b/MediaBrowser.Providers/Movies/TrailerMetadataService.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System.Linq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -23,22 +24,6 @@ namespace MediaBrowser.Providers.Movies { } - /// - protected override bool IsFullLocalMetadata(Trailer item) - { - if (string.IsNullOrWhiteSpace(item.Overview)) - { - return false; - } - - if (!item.ProductionYear.HasValue) - { - return false; - } - - return base.IsFullLocalMetadata(item); - } - /// protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { @@ -48,6 +33,10 @@ namespace MediaBrowser.Providers.Movies { target.Item.TrailerTypes = source.Item.TrailerTypes; } + else + { + target.Item.TrailerTypes = target.Item.TrailerTypes.Concat(source.Item.TrailerTypes).Distinct().ToArray(); + } } } } diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index e4f34776b..a39bd16ce 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -225,6 +225,10 @@ namespace MediaBrowser.Providers.Music { targetItem.Artists = sourceItem.Artists; } + else + { + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + } if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist))) { diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs index a5b7cb895..7b25bc0e4 100644 --- a/MediaBrowser.Providers/Music/AudioMetadataService.cs +++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; @@ -60,6 +61,10 @@ namespace MediaBrowser.Providers.Music { targetItem.Artists = sourceItem.Artists; } + else + { + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + } if (replaceData || string.IsNullOrEmpty(targetItem.Album)) { diff --git a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs index b97b76630..24c4b5501 100644 --- a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs +++ b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs @@ -1,5 +1,6 @@ #pragma warning disable CS1591 +using System.Linq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -45,6 +46,10 @@ namespace MediaBrowser.Providers.Music { targetItem.Artists = sourceItem.Artists; } + else + { + targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray(); + } } } } diff --git a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs index 1bd000a48..43889bfbf 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System.Collections.Generic; +using System.Linq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -49,8 +50,24 @@ namespace MediaBrowser.Providers.Playlists if (mergeMetadataSettings) { targetItem.PlaylistMediaType = sourceItem.PlaylistMediaType; - targetItem.LinkedChildren = sourceItem.LinkedChildren; - targetItem.Shares = sourceItem.Shares; + + if (replaceData || targetItem.LinkedChildren.Length == 0) + { + targetItem.LinkedChildren = sourceItem.LinkedChildren; + } + else + { + targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren).Distinct().ToArray(); + } + + if (replaceData || targetItem.Shares.Count == 0) + { + targetItem.Shares = sourceItem.Shares; + } + else + { + targetItem.Shares = sourceItem.Shares.Concat(targetItem.Shares).DistinctBy(s => s.UserId).ToArray(); + } } } } diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index 9747c983a..99c4e0f1b 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -65,22 +65,6 @@ namespace MediaBrowser.Providers.TV await CreateSeasonsAsync(item, cancellationToken).ConfigureAwait(false); } - /// - protected override bool IsFullLocalMetadata(Series item) - { - if (string.IsNullOrWhiteSpace(item.Overview)) - { - return false; - } - - if (!item.ProductionYear.HasValue) - { - return false; - } - - return base.IsFullLocalMetadata(item); - } - /// protected override void MergeData(MetadataResult source, MetadataResult target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) { diff --git a/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs b/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs index ec4df9981..cedcaf9c0 100644 --- a/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs +++ b/tests/Jellyfin.Providers.Tests/Manager/MetadataServiceTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; @@ -19,7 +20,7 @@ namespace Jellyfin.Providers.Tests.Manager [InlineData(true, true)] public void MergeBaseItemData_MergeMetadataSettings_MergesWhenSet(bool mergeMetadataSettings, bool defaultDate) { - var newLocked = new[] { MetadataField.Cast }; + var newLocked = new[] { MetadataField.Genres, MetadataField.Cast }; var newString = "new"; var newDate = DateTime.Now; @@ -77,7 +78,7 @@ namespace Jellyfin.Providers.Tests.Manager [Theory] [InlineData("Name", MetadataField.Name, false)] - [InlineData("OriginalTitle", null, false)] + [InlineData("OriginalTitle", null)] [InlineData("OfficialRating", MetadataField.OfficialRating)] [InlineData("CustomRating")] [InlineData("Tagline")] -- cgit v1.2.3