aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Collections/CollectionManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Collections/CollectionManager.cs')
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs266
1 files changed, 108 insertions, 158 deletions
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index 2b99e0ddf..79ef70fff 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -4,13 +4,12 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Collections;
-using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
@@ -20,20 +19,29 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Collections
{
+ /// <summary>
+ /// The collection manager.
+ /// </summary>
public class CollectionManager : ICollectionManager
{
private readonly ILibraryManager _libraryManager;
private readonly IFileSystem _fileSystem;
private readonly ILibraryMonitor _iLibraryMonitor;
- private readonly ILogger _logger;
+ private readonly ILogger<CollectionManager> _logger;
private readonly IProviderManager _providerManager;
private readonly ILocalizationManager _localizationManager;
- private IApplicationPaths _appPaths;
-
- public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
- public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
- public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
-
+ private readonly IApplicationPaths _appPaths;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CollectionManager"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="appPaths">The application paths.</param>
+ /// <param name="localizationManager">The localization manager.</param>
+ /// <param name="fileSystem">The filesystem.</param>
+ /// <param name="iLibraryMonitor">The library monitor.</param>
+ /// <param name="loggerFactory">The logger factory.</param>
+ /// <param name="providerManager">The provider manager.</param>
public CollectionManager(
ILibraryManager libraryManager,
IApplicationPaths appPaths,
@@ -46,12 +54,21 @@ namespace Emby.Server.Implementations.Collections
_libraryManager = libraryManager;
_fileSystem = fileSystem;
_iLibraryMonitor = iLibraryMonitor;
- _logger = loggerFactory.CreateLogger(nameof(CollectionManager));
+ _logger = loggerFactory.CreateLogger<CollectionManager>();
_providerManager = providerManager;
_localizationManager = localizationManager;
_appPaths = appPaths;
}
+ /// <inheritdoc />
+ public event EventHandler<CollectionCreatedEventArgs>? CollectionCreated;
+
+ /// <inheritdoc />
+ public event EventHandler<CollectionModifiedEventArgs>? ItemsAddedToCollection;
+
+ /// <inheritdoc />
+ public event EventHandler<CollectionModifiedEventArgs>? ItemsRemovedFromCollection;
+
private IEnumerable<Folder> FindFolders(string path)
{
return _libraryManager
@@ -61,14 +78,12 @@ namespace Emby.Server.Implementations.Collections
.Where(i => _fileSystem.AreEqual(path, i.Path) || _fileSystem.ContainsSubPath(i.Path, path));
}
- internal async Task<Folder> EnsureLibraryFolder(string path, bool createIfNeeded)
+ internal async Task<Folder?> EnsureLibraryFolder(string path, bool createIfNeeded)
{
- var existingFolders = FindFolders(path)
- .ToList();
-
- if (existingFolders.Count > 0)
+ var existingFolder = FindFolders(path).FirstOrDefault();
+ if (existingFolder != null)
{
- return existingFolders[0];
+ return existingFolder;
}
if (!createIfNeeded)
@@ -80,14 +95,14 @@ namespace Emby.Server.Implementations.Collections
var libraryOptions = new LibraryOptions
{
- PathInfos = new[] { new MediaPathInfo { Path = path } },
+ PathInfos = new[] { new MediaPathInfo(path) },
EnableRealtimeMonitor = false,
SaveLocalMetadata = true
};
var name = _localizationManager.GetLocalizedString("Collections");
- await _libraryManager.AddVirtualFolder(name, CollectionType.BoxSets, libraryOptions, true).ConfigureAwait(false);
+ await _libraryManager.AddVirtualFolder(name, CollectionTypeOptions.BoxSets, libraryOptions, true).ConfigureAwait(false);
return FindFolders(path).First();
}
@@ -97,21 +112,22 @@ namespace Emby.Server.Implementations.Collections
return Path.Combine(_appPaths.DataPath, "collections");
}
- private Task<Folder> GetCollectionsFolder(bool createIfNeeded)
+ private Task<Folder?> GetCollectionsFolder(bool createIfNeeded)
{
return EnsureLibraryFolder(GetCollectionsFolderPath(), createIfNeeded);
}
private IEnumerable<BoxSet> GetCollections(User user)
{
- var folder = GetCollectionsFolder(false).Result;
+ var folder = GetCollectionsFolder(false).GetAwaiter().GetResult();
- return folder == null ?
- new List<BoxSet>() :
- folder.GetChildren(user, true).OfType<BoxSet>();
+ return folder == null
+ ? Enumerable.Empty<BoxSet>()
+ : folder.GetChildren(user, true).OfType<BoxSet>();
}
- public BoxSet CreateCollection(CollectionCreationOptions options)
+ /// <inheritdoc />
+ public async Task<BoxSet> CreateCollectionAsync(CollectionCreationOptions options)
{
var name = options.Name;
@@ -120,7 +136,7 @@ namespace Emby.Server.Implementations.Collections
// This could cause it to get re-resolved as a plain folder
var folderName = _fileSystem.GetValidFilename(name) + " [boxset]";
- var parentFolder = GetCollectionsFolder(true).Result;
+ var parentFolder = await GetCollectionsFolder(true).ConfigureAwait(false);
if (parentFolder == null)
{
@@ -144,20 +160,24 @@ namespace Emby.Server.Implementations.Collections
DateCreated = DateTime.UtcNow
};
- parentFolder.AddChild(collection, CancellationToken.None);
+ parentFolder.AddChild(collection);
- if (options.ItemIdList.Length > 0)
+ if (options.ItemIdList.Count > 0)
{
- AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
- {
- // The initial adding of items is going to create a local metadata file
- // This will cause internet metadata to be skipped as a result
- MetadataRefreshMode = MetadataRefreshMode.FullRefresh
- });
+ await AddToCollectionAsync(
+ collection.Id,
+ options.ItemIdList.Select(x => new Guid(x)),
+ false,
+ new MetadataRefreshOptions(new DirectoryService(_fileSystem))
+ {
+ // The initial adding of items is going to create a local metadata file
+ // This will cause internet metadata to be skipped as a result
+ MetadataRefreshMode = MetadataRefreshMode.FullRefresh
+ }).ConfigureAwait(false);
}
else
{
- _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), RefreshPriority.High);
+ _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
}
CollectionCreated?.Invoke(this, new CollectionCreatedEventArgs
@@ -175,21 +195,13 @@ namespace Emby.Server.Implementations.Collections
}
}
- public void AddToCollection(Guid collectionId, IEnumerable<string> ids)
- {
- AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)));
- }
-
- public void AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
- {
- AddToCollection(collectionId, ids.Select(i => i.ToString("N")), true, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)));
- }
+ /// <inheritdoc />
+ public Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> itemIds)
+ => AddToCollectionAsync(collectionId, itemIds, true, new MetadataRefreshOptions(new DirectoryService(_fileSystem)));
- private void AddToCollection(Guid collectionId, IEnumerable<string> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
+ private async Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
{
- var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
-
- if (collection == null)
+ if (_libraryManager.GetItemById(collectionId) is not BoxSet collection)
{
throw new ArgumentException("No collection exists with the supplied Id");
}
@@ -202,15 +214,14 @@ namespace Emby.Server.Implementations.Collections
foreach (var id in ids)
{
- var guidId = new Guid(id);
- var item = _libraryManager.GetItemById(guidId);
+ var item = _libraryManager.GetItemById(id);
if (item == null)
{
throw new ArgumentException("No item exists with the supplied Id");
}
- if (!currentLinkedChildrenIds.Contains(guidId))
+ if (!currentLinkedChildrenIds.Contains(id))
{
itemList.Add(item);
@@ -227,32 +238,22 @@ namespace Emby.Server.Implementations.Collections
collection.UpdateRatingToItems(linkedChildrenList);
- collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
+ await collection.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
refreshOptions.ForceSave = true;
_providerManager.QueueRefresh(collection.Id, refreshOptions, RefreshPriority.High);
if (fireEvent)
{
- ItemsAddedToCollection?.Invoke(this, new CollectionModifiedEventArgs
- {
- Collection = collection,
- ItemsChanged = itemList
- });
+ ItemsAddedToCollection?.Invoke(this, new CollectionModifiedEventArgs(collection, itemList));
}
}
}
- public void RemoveFromCollection(Guid collectionId, IEnumerable<string> itemIds)
+ /// <inheritdoc />
+ public async Task RemoveFromCollectionAsync(Guid collectionId, IEnumerable<Guid> itemIds)
{
- RemoveFromCollection(collectionId, itemIds.Select(i => new Guid(i)));
- }
-
- public void RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds)
- {
- var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
-
- if (collection == null)
+ if (_libraryManager.GetItemById(collectionId) is not BoxSet collection)
{
throw new ArgumentException("No collection exists with the supplied Id");
}
@@ -285,128 +286,77 @@ namespace Emby.Server.Implementations.Collections
collection.LinkedChildren = collection.LinkedChildren.Except(list).ToArray();
}
- collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
- _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
- {
- ForceSave = true
- }, RefreshPriority.High);
+ await collection.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ _providerManager.QueueRefresh(
+ collection.Id,
+ new MetadataRefreshOptions(new DirectoryService(_fileSystem))
+ {
+ ForceSave = true
+ },
+ RefreshPriority.High);
- ItemsRemovedFromCollection?.Invoke(this, new CollectionModifiedEventArgs
- {
- Collection = collection,
- ItemsChanged = itemList
- });
+ ItemsRemovedFromCollection?.Invoke(this, new CollectionModifiedEventArgs(collection, itemList));
}
+ /// <inheritdoc />
public IEnumerable<BaseItem> CollapseItemsWithinBoxSets(IEnumerable<BaseItem> items, User user)
{
var results = new Dictionary<Guid, BaseItem>();
- var allBoxsets = GetCollections(user).ToList();
+ var allBoxSets = GetCollections(user).ToList();
foreach (var item in items)
{
- var grouping = item as ISupportsBoxSetGrouping;
-
- if (grouping == null)
- {
- results[item.Id] = item;
- }
- else
+ if (item is ISupportsBoxSetGrouping)
{
var itemId = item.Id;
- var currentBoxSets = allBoxsets
- .Where(i => i.ContainsLinkedChildByItemId(itemId))
- .ToList();
-
- if (currentBoxSets.Count > 0)
+ var itemIsInBoxSet = false;
+ foreach (var boxSet in allBoxSets)
{
- foreach (var boxset in currentBoxSets)
+ if (!boxSet.ContainsLinkedChildByItemId(itemId))
{
- results[boxset.Id] = boxset;
+ continue;
}
- }
- else
- {
- results[item.Id] = item;
- }
- }
- }
- return results.Values;
- }
- }
+ itemIsInBoxSet = true;
- public class CollectionManagerEntryPoint : IServerEntryPoint
- {
- private readonly CollectionManager _collectionManager;
- private readonly IServerConfigurationManager _config;
- private ILogger _logger;
+ results.TryAdd(boxSet.Id, boxSet);
+ }
- public CollectionManagerEntryPoint(ICollectionManager collectionManager, IServerConfigurationManager config, ILogger logger)
- {
- _collectionManager = (CollectionManager)collectionManager;
- _config = config;
- _logger = logger;
- }
+ // skip any item that is in a box set
+ if (itemIsInBoxSet)
+ {
+ continue;
+ }
- public async Task RunAsync()
- {
- if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted)
- {
- var path = _collectionManager.GetCollectionsFolderPath();
+ var alreadyInResults = false;
- if (Directory.Exists(path))
- {
- try
+ // this is kind of a performance hack because only Video has alternate versions that should be in a box set?
+ if (item is Video video)
{
- await _collectionManager.EnsureLibraryFolder(path, true).ConfigureAwait(false);
+ foreach (var childId in video.GetLocalAlternateVersionIds())
+ {
+ if (!results.ContainsKey(childId))
+ {
+ continue;
+ }
+
+ alreadyInResults = true;
+ break;
+ }
}
- catch (Exception ex)
+
+ if (alreadyInResults)
{
- _logger.LogError(ex, "Error creating camera uploads library");
+ continue;
}
-
- _config.Configuration.CollectionsUpgraded = true;
- _config.SaveConfiguration();
}
- }
- }
- #region IDisposable Support
- private bool disposedValue = false; // To detect redundant calls
-
- protected virtual void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- if (disposing)
- {
- // TODO: dispose managed state (managed objects).
- }
-
- // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
- // TODO: set large fields to null.
-
- disposedValue = true;
+ results[item.Id] = item;
}
- }
- // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
- // ~CollectionManagerEntryPoint() {
- // // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- // Dispose(false);
- // }
-
- // This code added to correctly implement the disposable pattern.
- public void Dispose()
- {
- // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
- Dispose(true);
- // TODO: uncomment the following line if the finalizer is overridden above.
- // GC.SuppressFinalize(this);
+ return results.Values;
}
- #endregion
}
}