From 5eb1fde88cb32e05ea51f26e1577b20bb4c60bd6 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Mon, 15 Nov 2021 22:26:42 +0800 Subject: [PATCH 01/13] Add Collection Validator, create collection based on nfo Based on nfo's set element, automatically add movie to collection. Signed-off-by: Petrus.Z --- .../Validators/CollectionPostScanTask.cs | 50 ++++++ .../Library/Validators/CollectionValidator.cs | 166 ++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs create mode 100644 Emby.Server.Implementations/Library/Validators/CollectionValidator.cs diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs new file mode 100644 index 0000000000..bc204b788b --- /dev/null +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -0,0 +1,50 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Collections; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.Library.Validators +{ + /// + /// Class CollectionPostScanTask. + /// + public class CollectionPostScanTask : ILibraryPostScanTask + { + /// + /// The _library manager. + /// + private readonly ILibraryManager _libraryManager; + private readonly ICollectionManager _collectionManager; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The collection manager. + /// The logger. + public CollectionPostScanTask( + ILibraryManager libraryManager, + ILogger logger, + ICollectionManager collectionManager) + { + _libraryManager = libraryManager; + _collectionManager = collectionManager; + _logger = logger; + } + + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public Task Run(IProgress progress, CancellationToken cancellationToken) + { + return new CollectionValidator(_libraryManager, _collectionManager, _logger).Run(progress, cancellationToken); + } + } +} diff --git a/Emby.Server.Implementations/Library/Validators/CollectionValidator.cs b/Emby.Server.Implementations/Library/Validators/CollectionValidator.cs new file mode 100644 index 0000000000..439fc1da10 --- /dev/null +++ b/Emby.Server.Implementations/Library/Validators/CollectionValidator.cs @@ -0,0 +1,166 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; +using MediaBrowser.Controller.Collections; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Querying; +using Microsoft.Extensions.Logging; +using Jellyfin.Data.Enums; + +namespace Emby.Server.Implementations.Library.Validators +{ + /// + /// Class CollectionValidator. + /// + public class CollectionValidator + { + /// + /// The library manager. + /// + private readonly ILibraryManager _libraryManager; + + /// + /// The collection manager. + /// + private readonly ICollectionManager _collectionManager; + + /// + /// The logger. + /// + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The library manager. + /// The collection manager. + /// The logger. + public CollectionValidator(ILibraryManager libraryManager, ICollectionManager collectionManager, ILogger logger) + { + _libraryManager = libraryManager; + _collectionManager = collectionManager; + _logger = logger; + } + + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + var movies = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { nameof(Movie) }, + IsVirtualItem = false, + OrderBy = new List> + { + new ValueTuple(ItemSortBy.SortName, SortOrder.Ascending) + }, + Recursive = true + }).Select(m => m as Movie).ToList(); + + var boxSets = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { nameof(BoxSet) }, + CollapseBoxSetItems = false, + Recursive = true + }).Select(b => b as BoxSet).ToList(); + + var numComplete = 0; + var count = movies.Count; + + var map = new Dictionary>(); + foreach (var movie in movies) + { + if (movie != null && movie.CollectionName != null) + { + var movieList = new List(); + if (map.TryGetValue(movie.CollectionName, out movieList)) + { + if (!movieList.Where(m => m.Id == movie.Id).Any()) + { + movieList.Add(movie); + map[movie.CollectionName] = movieList; + } + } + else + { + map[movie.CollectionName] = new List { movie }; + } + + } + + numComplete++; + double percent = numComplete; + percent /= count * 2; + percent *= 100; + + progress.Report(percent); + } + + foreach (var pair in map) + { + try + { + var collectionName = pair.Key; + var movieList = pair.Value; + + var boxSet = boxSets.FirstOrDefault(b => b != null ? b.Name == collectionName : false); + if (boxSet == null) + { + // won't automatically create collection if only one movie in it + if (movieList.Count >= 2) + { + boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions + { + Name = collectionName, + IsLocked = true + }); + + AddMovieToCollection(boxSet.Id, boxSet, movieList); + } + } + else + { + AddMovieToCollection(boxSet.Id, boxSet, movieList); + } + + numComplete++; + double percent = numComplete; + percent /= count * 2; + percent *= 100; + + progress.Report(percent); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error refreshing {0}, {1}", pair.Key, pair.Value.ToString()); + } + } + + progress.Report(100); + } + + private async void AddMovieToCollection(Guid boxSetId, BoxSet boxSet, List movieList) + { + + var movieIds = new List(); + foreach (var movie in movieList) + { + if (!boxSet.ContainsLinkedChildByItemId(movie.Id)) + { + movieIds.Add(movie.Id); + } + } + if (movieIds.Any()) { + await _collectionManager.AddToCollectionAsync(boxSetId, movieIds); + } + } + } +} From 74459ec403eda3912f12122da18c15c96244d351 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Tue, 16 Nov 2021 11:38:36 +0800 Subject: [PATCH 02/13] Fix issues mentioned in review Signed-off-by: Petrus.Z --- .../Validators/CollectionPostScanTask.cs | 115 +++++++++++- .../Library/Validators/CollectionValidator.cs | 166 ------------------ 2 files changed, 110 insertions(+), 171 deletions(-) delete mode 100644 Emby.Server.Implementations/Library/Validators/CollectionValidator.cs diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index bc204b788b..64967350ef 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -1,9 +1,14 @@ using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using System.Collections.Generic; using MediaBrowser.Controller.Collections; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Querying; +using Jellyfin.Data.Enums; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library.Validators @@ -17,8 +22,16 @@ namespace Emby.Server.Implementations.Library.Validators /// The _library manager. /// private readonly ILibraryManager _libraryManager; + + /// + /// The collection manager. + /// private readonly ICollectionManager _collectionManager; - private readonly ILogger _logger; + + /// + /// The logger. + /// + private readonly ILogger _logger; /// /// Initializes a new instance of the class. @@ -28,7 +41,7 @@ namespace Emby.Server.Implementations.Library.Validators /// The logger. public CollectionPostScanTask( ILibraryManager libraryManager, - ILogger logger, + ILogger logger, ICollectionManager collectionManager) { _libraryManager = libraryManager; @@ -42,9 +55,101 @@ namespace Emby.Server.Implementations.Library.Validators /// The progress. /// The cancellation token. /// Task. - public Task Run(IProgress progress, CancellationToken cancellationToken) + public async Task Run(IProgress progress, CancellationToken cancellationToken) { - return new CollectionValidator(_libraryManager, _collectionManager, _logger).Run(progress, cancellationToken); + + var movies = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { nameof(Movie) }, + IsVirtualItem = false, + OrderBy = new List> + { + new ValueTuple(ItemSortBy.SortName, SortOrder.Ascending) + }, + Recursive = true + }); + + var boxSets = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { nameof(BoxSet) }, + CollapseBoxSetItems = false, + Recursive = true + }); + + var numComplete = 0; + var count = movies.Count; + + var collectionNameMoviesMap = new Dictionary>(); + foreach (var m in movies) + { + var movie = m as Movie; + if (movie != null && movie.CollectionName != null) + { + var movieList = new List(); + if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out movieList)) + { + if (!movieList.Any(m => m.Id == movie.Id)) + { + movieList.Add(movie); + collectionNameMoviesMap[movie.CollectionName] = movieList; + } + } + else + { + collectionNameMoviesMap[movie.CollectionName] = new List { movie }; + } + + } + + numComplete++; + double percent = numComplete; + percent /= count * 2; + percent *= 100; + + progress.Report(percent); + } + + foreach (var pair in collectionNameMoviesMap) + { + try + { + var collectionName = pair.Key; + var movieList = pair.Value; + + var boxSet = boxSets.FirstOrDefault(b => b != null ? b.Name == collectionName : false) as BoxSet; + if (boxSet == null) + { + // won't automatically create collection if only one movie in it + if (movieList.Count >= 2) + { + boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions + { + Name = collectionName, + IsLocked = true + }); + + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieList.Select(m => m.Id)); + } + } + else + { + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieList.Select(m => m.Id)); + } + + numComplete++; + double percent = numComplete; + percent /= count * 2; + percent *= 100; + + progress.Report(percent); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error refreshing {0}, {1}", pair.Key, pair.Value.ToString()); + } + } + + progress.Report(100); } } } diff --git a/Emby.Server.Implementations/Library/Validators/CollectionValidator.cs b/Emby.Server.Implementations/Library/Validators/CollectionValidator.cs deleted file mode 100644 index 439fc1da10..0000000000 --- a/Emby.Server.Implementations/Library/Validators/CollectionValidator.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Collections.Generic; -using MediaBrowser.Controller.Collections; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Querying; -using Microsoft.Extensions.Logging; -using Jellyfin.Data.Enums; - -namespace Emby.Server.Implementations.Library.Validators -{ - /// - /// Class CollectionValidator. - /// - public class CollectionValidator - { - /// - /// The library manager. - /// - private readonly ILibraryManager _libraryManager; - - /// - /// The collection manager. - /// - private readonly ICollectionManager _collectionManager; - - /// - /// The logger. - /// - private readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The library manager. - /// The collection manager. - /// The logger. - public CollectionValidator(ILibraryManager libraryManager, ICollectionManager collectionManager, ILogger logger) - { - _libraryManager = libraryManager; - _collectionManager = collectionManager; - _logger = logger; - } - - /// - /// Runs the specified progress. - /// - /// The progress. - /// The cancellation token. - /// Task. - public async Task Run(IProgress progress, CancellationToken cancellationToken) - { - var movies = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { nameof(Movie) }, - IsVirtualItem = false, - OrderBy = new List> - { - new ValueTuple(ItemSortBy.SortName, SortOrder.Ascending) - }, - Recursive = true - }).Select(m => m as Movie).ToList(); - - var boxSets = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { nameof(BoxSet) }, - CollapseBoxSetItems = false, - Recursive = true - }).Select(b => b as BoxSet).ToList(); - - var numComplete = 0; - var count = movies.Count; - - var map = new Dictionary>(); - foreach (var movie in movies) - { - if (movie != null && movie.CollectionName != null) - { - var movieList = new List(); - if (map.TryGetValue(movie.CollectionName, out movieList)) - { - if (!movieList.Where(m => m.Id == movie.Id).Any()) - { - movieList.Add(movie); - map[movie.CollectionName] = movieList; - } - } - else - { - map[movie.CollectionName] = new List { movie }; - } - - } - - numComplete++; - double percent = numComplete; - percent /= count * 2; - percent *= 100; - - progress.Report(percent); - } - - foreach (var pair in map) - { - try - { - var collectionName = pair.Key; - var movieList = pair.Value; - - var boxSet = boxSets.FirstOrDefault(b => b != null ? b.Name == collectionName : false); - if (boxSet == null) - { - // won't automatically create collection if only one movie in it - if (movieList.Count >= 2) - { - boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions - { - Name = collectionName, - IsLocked = true - }); - - AddMovieToCollection(boxSet.Id, boxSet, movieList); - } - } - else - { - AddMovieToCollection(boxSet.Id, boxSet, movieList); - } - - numComplete++; - double percent = numComplete; - percent /= count * 2; - percent *= 100; - - progress.Report(percent); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error refreshing {0}, {1}", pair.Key, pair.Value.ToString()); - } - } - - progress.Report(100); - } - - private async void AddMovieToCollection(Guid boxSetId, BoxSet boxSet, List movieList) - { - - var movieIds = new List(); - foreach (var movie in movieList) - { - if (!boxSet.ContainsLinkedChildByItemId(movie.Id)) - { - movieIds.Add(movie.Id); - } - } - if (movieIds.Any()) { - await _collectionManager.AddToCollectionAsync(boxSetId, movieIds); - } - } - } -} From 1924d0740d2846aae401686e45d55e8c8358e23b Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Tue, 16 Nov 2021 19:03:18 +0800 Subject: [PATCH 03/13] Fix style and performance issues mentioned in review Signed-off-by: Petrus.Z --- .../Validators/CollectionPostScanTask.cs | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index 64967350ef..e692455db1 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -18,19 +18,8 @@ namespace Emby.Server.Implementations.Library.Validators /// public class CollectionPostScanTask : ILibraryPostScanTask { - /// - /// The _library manager. - /// private readonly ILibraryManager _libraryManager; - - /// - /// The collection manager. - /// private readonly ICollectionManager _collectionManager; - - /// - /// The logger. - /// private readonly ILogger _logger; /// @@ -41,8 +30,8 @@ namespace Emby.Server.Implementations.Library.Validators /// The logger. public CollectionPostScanTask( ILibraryManager libraryManager, - ILogger logger, - ICollectionManager collectionManager) + ICollectionManager collectionManager, + ILogger logger) { _libraryManager = libraryManager; _collectionManager = collectionManager; @@ -57,15 +46,11 @@ namespace Emby.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var movies = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = new[] { nameof(Movie) }, IsVirtualItem = false, - OrderBy = new List> - { - new ValueTuple(ItemSortBy.SortName, SortOrder.Ascending) - }, + OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, Recursive = true }); @@ -82,16 +67,13 @@ namespace Emby.Server.Implementations.Library.Validators var collectionNameMoviesMap = new Dictionary>(); foreach (var m in movies) { - var movie = m as Movie; - if (movie != null && movie.CollectionName != null) + if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName)) { - var movieList = new List(); - if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out movieList)) + if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) { if (!movieList.Any(m => m.Id == movie.Id)) { movieList.Add(movie); - collectionNameMoviesMap[movie.CollectionName] = movieList; } } else @@ -109,14 +91,11 @@ namespace Emby.Server.Implementations.Library.Validators progress.Report(percent); } - foreach (var pair in collectionNameMoviesMap) + foreach (var (collectionName, movieList) in collectionNameMoviesMap) { try { - var collectionName = pair.Key; - var movieList = pair.Value; - - var boxSet = boxSets.FirstOrDefault(b => b != null ? b.Name == collectionName : false) as BoxSet; + var boxSet = boxSets.FirstOrDefault(b => b?.Name == collectionName) as BoxSet; if (boxSet == null) { // won't automatically create collection if only one movie in it @@ -145,7 +124,7 @@ namespace Emby.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.LogError(ex, "Error refreshing {0}, {1}", pair.Key, pair.Value.ToString()); + _logger.LogError(ex, "Error refreshing {CollectionName} with {@MovieIds}", collectionName, movieList); } } From 0a0ddb0eafa669256f0493d1bc2abdf32290302a Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Wed, 17 Nov 2021 14:02:07 +0800 Subject: [PATCH 04/13] Add AutoCollection option it can determine whether auto create/add movies to collection Signed-off-by: Petrus.Z --- .../Validators/CollectionPostScanTask.cs | 34 ++++++++++++++----- .../Configuration/LibraryOptions.cs | 2 ++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index e692455db1..3deaf7fe78 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -10,6 +10,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Querying; using Jellyfin.Data.Enums; using Microsoft.Extensions.Logging; +using System.Diagnostics; namespace Emby.Server.Implementations.Library.Validators { @@ -101,18 +102,23 @@ namespace Emby.Server.Implementations.Library.Validators // won't automatically create collection if only one movie in it if (movieList.Count >= 2) { - boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions - { - Name = collectionName, - IsLocked = true - }); + var movieIds = FliterMoviesByOption(movieList); + if (movieIds.Count >= 2) { + // at least 2 movies have AutoCollection option enable + boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions + { + Name = collectionName, + IsLocked = true + }); - await _collectionManager.AddToCollectionAsync(boxSet.Id, movieList.Select(m => m.Id)); + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds); + } } } else { - await _collectionManager.AddToCollectionAsync(boxSet.Id, movieList.Select(m => m.Id)); + var movieIds = FliterMoviesByOption(movieList); + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds); } numComplete++; @@ -130,5 +136,17 @@ namespace Emby.Server.Implementations.Library.Validators progress.Report(100); } + + private List FliterMoviesByOption(List movieList) { + List movieIds = new List(); + foreach (var movie in movieList) + { + if (_libraryManager.GetLibraryOptions(movie).AutoCollection) + { + movieIds.Add(movie.Id); + } + } + return movieIds; + } } -} +} \ No newline at end of file diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index aae5359b1d..0a676de9a2 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -16,6 +16,7 @@ namespace MediaBrowser.Model.Configuration SkipSubtitlesIfAudioTrackMatches = true; RequirePerfectSubtitleMatch = true; + AutoCollection = true; EnablePhotos = true; SaveSubtitlesWithMedia = true; EnableRealtimeMonitor = true; @@ -80,6 +81,7 @@ namespace MediaBrowser.Model.Configuration public bool RequirePerfectSubtitleMatch { get; set; } public bool SaveSubtitlesWithMedia { get; set; } + public bool AutoCollection { get; set; } public TypeOptions[] TypeOptions { get; set; } From 3c8f7d380f6f2b719dd4ededebcc2505ef24baad Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Wed, 17 Nov 2021 20:56:14 +0800 Subject: [PATCH 05/13] Improve performance Signed-off-by: Petrus.Z --- .../Validators/CollectionPostScanTask.cs | 100 ++++++++---------- 1 file changed, 43 insertions(+), 57 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index 3deaf7fe78..37b0c439c0 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -10,7 +10,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Querying; using Jellyfin.Data.Enums; using Microsoft.Extensions.Logging; -using System.Diagnostics; +using MediaBrowser.Model.Entities; namespace Emby.Server.Implementations.Library.Validators { @@ -47,14 +47,6 @@ namespace Emby.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var movies = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { nameof(Movie) }, - IsVirtualItem = false, - OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, - Recursive = true - }); - var boxSets = _libraryManager.GetItemList(new InternalItemsQuery { IncludeItemTypes = new[] { nameof(BoxSet) }, @@ -62,36 +54,47 @@ namespace Emby.Server.Implementations.Library.Validators Recursive = true }); - var numComplete = 0; - var count = movies.Count; - var collectionNameMoviesMap = new Dictionary>(); - foreach (var m in movies) - { - if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName)) - { - if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) - { - if (!movieList.Any(m => m.Id == movie.Id)) - { - movieList.Add(movie); - } - } - else - { - collectionNameMoviesMap[movie.CollectionName] = new List { movie }; - } + foreach (var library in _libraryManager.RootFolder.Children.ToList()) { + if (!_libraryManager.GetLibraryOptions(library).AutoCollection) { + continue; } - numComplete++; - double percent = numComplete; - percent /= count * 2; - percent *= 100; + var movies = _libraryManager.GetItemList(new InternalItemsQuery + { + MediaTypes = new string[] { MediaType.Video }, + IncludeItemTypes = new[] { nameof(Movie) }, + IsVirtualItem = false, + OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, + SourceTypes = new[] { SourceType.Library }, + Parent = library, + Recursive = true + }); - progress.Report(percent); + foreach (var m in movies) + { + if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName)) + { + if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) + { + if (!movieList.Any(m => m.Id == movie.Id)) + { + movieList.Add(movie); + } + } + else + { + collectionNameMoviesMap[movie.CollectionName] = new List { movie }; + } + + } + } } + var numComplete = 0; + var count = collectionNameMoviesMap.Count; + foreach (var (collectionName, movieList) in collectionNameMoviesMap) { try @@ -102,28 +105,23 @@ namespace Emby.Server.Implementations.Library.Validators // won't automatically create collection if only one movie in it if (movieList.Count >= 2) { - var movieIds = FliterMoviesByOption(movieList); - if (movieIds.Count >= 2) { - // at least 2 movies have AutoCollection option enable - boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions - { - Name = collectionName, - IsLocked = true - }); + boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions + { + Name = collectionName, + IsLocked = true + }); - await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds); - } + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieList.Select(m => m.Id)); } } else { - var movieIds = FliterMoviesByOption(movieList); - await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds); + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieList.Select(m => m.Id)); } numComplete++; double percent = numComplete; - percent /= count * 2; + percent /= count; percent *= 100; progress.Report(percent); @@ -136,17 +134,5 @@ namespace Emby.Server.Implementations.Library.Validators progress.Report(100); } - - private List FliterMoviesByOption(List movieList) { - List movieIds = new List(); - foreach (var movie in movieList) - { - if (_libraryManager.GetLibraryOptions(movie).AutoCollection) - { - movieIds.Add(movie.Id); - } - } - return movieIds; - } } } \ No newline at end of file From 52e9dc66f5c2051a5e4b7f62ff7f2469cfa4da61 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Wed, 17 Nov 2021 21:07:02 +0800 Subject: [PATCH 06/13] Remove extra blank line Signed-off-by: Petrus.Z --- .../Library/Validators/CollectionPostScanTask.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index 37b0c439c0..b659caa142 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -87,7 +87,6 @@ namespace Emby.Server.Implementations.Library.Validators { collectionNameMoviesMap[movie.CollectionName] = new List { movie }; } - } } } From c09e9999163f6a6aa2f816a6f56197126c115c85 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Wed, 17 Nov 2021 22:18:59 +0800 Subject: [PATCH 07/13] Use List instead of List Signed-off-by: Petrus.Z --- .../Validators/CollectionPostScanTask.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index b659caa142..c87d6718ab 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.Library.Validators Recursive = true }); - var collectionNameMoviesMap = new Dictionary>(); + var collectionNameMoviesMap = new Dictionary>(); foreach (var library in _libraryManager.RootFolder.Children.ToList()) { if (!_libraryManager.GetLibraryOptions(library).AutoCollection) { @@ -78,14 +78,14 @@ namespace Emby.Server.Implementations.Library.Validators { if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) { - if (!movieList.Any(m => m.Id == movie.Id)) + if (!movieList.Any(m => m == movie.Id)) { - movieList.Add(movie); + movieList.Add(movie.Id); } } else { - collectionNameMoviesMap[movie.CollectionName] = new List { movie }; + collectionNameMoviesMap[movie.CollectionName] = new List { movie.Id }; } } } @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.Library.Validators var numComplete = 0; var count = collectionNameMoviesMap.Count; - foreach (var (collectionName, movieList) in collectionNameMoviesMap) + foreach (var (collectionName, movieIds) in collectionNameMoviesMap) { try { @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Library.Validators if (boxSet == null) { // won't automatically create collection if only one movie in it - if (movieList.Count >= 2) + if (movieIds.Count >= 2) { boxSet = await _collectionManager.CreateCollectionAsync(new CollectionCreationOptions { @@ -110,12 +110,12 @@ namespace Emby.Server.Implementations.Library.Validators IsLocked = true }); - await _collectionManager.AddToCollectionAsync(boxSet.Id, movieList.Select(m => m.Id)); + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds); } } else { - await _collectionManager.AddToCollectionAsync(boxSet.Id, movieList.Select(m => m.Id)); + await _collectionManager.AddToCollectionAsync(boxSet.Id, movieIds); } numComplete++; @@ -127,7 +127,7 @@ namespace Emby.Server.Implementations.Library.Validators } catch (Exception ex) { - _logger.LogError(ex, "Error refreshing {CollectionName} with {@MovieIds}", collectionName, movieList); + _logger.LogError(ex, "Error refreshing {CollectionName} with {@MovieIds}", collectionName, movieIds); } } From 989013c974a4a2292f946e05a9ee7fd6d53f7c60 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Wed, 17 Nov 2021 22:22:52 +0800 Subject: [PATCH 08/13] Add new line at end of file Signed-off-by: Petrus.Z --- .../Library/Validators/CollectionPostScanTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index c87d6718ab..fece37b036 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -134,4 +134,4 @@ namespace Emby.Server.Implementations.Library.Validators progress.Report(100); } } -} \ No newline at end of file +} From 6d74c83ddb983c30ae5ab2ffe0a403d0e07b5198 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Thu, 18 Nov 2021 12:07:27 +0800 Subject: [PATCH 09/13] Fix issues mentioned in review, except for option name Signed-off-by: Petrus.Z --- .../Library/Validators/CollectionPostScanTask.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index fece37b036..cd9e109ffe 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -54,9 +54,10 @@ namespace Emby.Server.Implementations.Library.Validators Recursive = true }); - var collectionNameMoviesMap = new Dictionary>(); + var collectionNameMoviesMap = new Dictionary>(); - foreach (var library in _libraryManager.RootFolder.Children.ToList()) { + foreach (var library in _libraryManager.RootFolder.Children) + { if (!_libraryManager.GetLibraryOptions(library).AutoCollection) { continue; } @@ -67,7 +68,6 @@ namespace Emby.Server.Implementations.Library.Validators IncludeItemTypes = new[] { nameof(Movie) }, IsVirtualItem = false, OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, - SourceTypes = new[] { SourceType.Library }, Parent = library, Recursive = true }); @@ -78,14 +78,14 @@ namespace Emby.Server.Implementations.Library.Validators { if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) { - if (!movieList.Any(m => m == movie.Id)) + if (!movieList.Contains(movie.Id)) { movieList.Add(movie.Id); } } else { - collectionNameMoviesMap[movie.CollectionName] = new List { movie.Id }; + collectionNameMoviesMap[movie.CollectionName] = new HashSet { movie.Id }; } } } From b635b5a7e3b72c91922d36bce6b29265123f88f8 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Thu, 18 Nov 2021 12:49:56 +0800 Subject: [PATCH 10/13] Paginate movies query Signed-off-by: Petrus.Z --- .../Validators/CollectionPostScanTask.cs | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index cd9e109ffe..123183c077 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -62,30 +62,40 @@ namespace Emby.Server.Implementations.Library.Validators continue; } - var movies = _libraryManager.GetItemList(new InternalItemsQuery - { - MediaTypes = new string[] { MediaType.Video }, - IncludeItemTypes = new[] { nameof(Movie) }, - IsVirtualItem = false, - OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, - Parent = library, - Recursive = true - }); + var startIndex = 0; + var pagesize = 1000; - foreach (var m in movies) + while (true) { - if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName)) + var movies = _libraryManager.GetItemList(new InternalItemsQuery { - if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) + MediaTypes = new string[] { MediaType.Video }, + IncludeItemTypes = new[] { nameof(Movie) }, + IsVirtualItem = false, + OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, + Parent = library, + StartIndex = startIndex, + Limit = pagesize, + Recursive = true + }); + startIndex += pagesize; + + if (!movies.Any()) { + break; + } + + foreach (var m in movies) + { + if (m is Movie movie && !string.IsNullOrEmpty(movie.CollectionName)) { - if (!movieList.Contains(movie.Id)) + if (collectionNameMoviesMap.TryGetValue(movie.CollectionName, out var movieList)) { movieList.Add(movie.Id); } - } - else - { - collectionNameMoviesMap[movie.CollectionName] = new HashSet { movie.Id }; + else + { + collectionNameMoviesMap[movie.CollectionName] = new HashSet { movie.Id }; + } } } } From 6565b0cfbe519a6203e3104fc472214a1927f215 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Thu, 18 Nov 2021 13:33:44 +0800 Subject: [PATCH 11/13] Fix style issues Signed-off-by: Petrus.Z --- .../Library/Validators/CollectionPostScanTask.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index 123183c077..c5ce4f1a87 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -58,7 +58,8 @@ namespace Emby.Server.Implementations.Library.Validators foreach (var library in _libraryManager.RootFolder.Children) { - if (!_libraryManager.GetLibraryOptions(library).AutoCollection) { + if (!_libraryManager.GetLibraryOptions(library).AutoCollection) + { continue; } @@ -80,7 +81,8 @@ namespace Emby.Server.Implementations.Library.Validators }); startIndex += pagesize; - if (!movies.Any()) { + if (!movies.Any()) + { break; } From 263bbf897ac9699b9bd27e9c7aba812111d08d42 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Thu, 18 Nov 2021 15:34:35 +0800 Subject: [PATCH 12/13] Reduce one query Signed-off-by: Petrus.Z --- .../Library/Validators/CollectionPostScanTask.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index c5ce4f1a87..1ca76ad952 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -79,12 +79,6 @@ namespace Emby.Server.Implementations.Library.Validators Limit = pagesize, Recursive = true }); - startIndex += pagesize; - - if (!movies.Any()) - { - break; - } foreach (var m in movies) { @@ -100,6 +94,13 @@ namespace Emby.Server.Implementations.Library.Validators } } } + + if (movies.Count < pagesize) + { + break; + } + + startIndex += pagesize; } } From acb86066fffa14e95d6d5ed52a50409bc1b326a5 Mon Sep 17 00:00:00 2001 From: "Petrus.Z" Date: Thu, 18 Nov 2021 16:00:14 +0800 Subject: [PATCH 13/13] Replace library option to AutomaticallyAddToCollection Signed-off-by: Petrus.Z --- .../Validators/CollectionPostScanTask.cs | 22 ++++++++++++------- .../Configuration/LibraryOptions.cs | 4 ++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs index 1ca76ad952..945b559ad3 100644 --- a/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs +++ b/Emby.Server.Implementations/Library/Validators/CollectionPostScanTask.cs @@ -47,18 +47,11 @@ namespace Emby.Server.Implementations.Library.Validators /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { - var boxSets = _libraryManager.GetItemList(new InternalItemsQuery - { - IncludeItemTypes = new[] { nameof(BoxSet) }, - CollapseBoxSetItems = false, - Recursive = true - }); - var collectionNameMoviesMap = new Dictionary>(); foreach (var library in _libraryManager.RootFolder.Children) { - if (!_libraryManager.GetLibraryOptions(library).AutoCollection) + if (!_libraryManager.GetLibraryOptions(library).AutomaticallyAddToCollection) { continue; } @@ -107,6 +100,19 @@ namespace Emby.Server.Implementations.Library.Validators var numComplete = 0; var count = collectionNameMoviesMap.Count; + if (count == 0) + { + progress.Report(100); + return; + } + + var boxSets = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new[] { nameof(BoxSet) }, + CollapseBoxSetItems = false, + Recursive = true + }); + foreach (var (collectionName, movieIds) in collectionNameMoviesMap) { try diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs index 0a676de9a2..90cf8f43bd 100644 --- a/MediaBrowser.Model/Configuration/LibraryOptions.cs +++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Model.Configuration SkipSubtitlesIfAudioTrackMatches = true; RequirePerfectSubtitleMatch = true; - AutoCollection = true; + AutomaticallyAddToCollection = true; EnablePhotos = true; SaveSubtitlesWithMedia = true; EnableRealtimeMonitor = true; @@ -81,7 +81,7 @@ namespace MediaBrowser.Model.Configuration public bool RequirePerfectSubtitleMatch { get; set; } public bool SaveSubtitlesWithMedia { get; set; } - public bool AutoCollection { get; set; } + public bool AutomaticallyAddToCollection { get; set; } public TypeOptions[] TypeOptions { get; set; }