mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-10-27 00:32:43 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			327 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			327 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using MediaBrowser.Common.Events;
 | |
| using MediaBrowser.Controller.Collections;
 | |
| using MediaBrowser.Controller.Entities;
 | |
| using MediaBrowser.Controller.Entities.Movies;
 | |
| using MediaBrowser.Controller.Library;
 | |
| using MediaBrowser.Controller.Providers;
 | |
| using MediaBrowser.Model.Logging;
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.IO;
 | |
| using System.Linq;
 | |
| using System.Threading;
 | |
| using System.Threading.Tasks;
 | |
| using CommonIO;
 | |
| 
 | |
| namespace MediaBrowser.Server.Implementations.Collections
 | |
| {
 | |
|     public class CollectionManager : ICollectionManager
 | |
|     {
 | |
|         private readonly ILibraryManager _libraryManager;
 | |
|         private readonly IFileSystem _fileSystem;
 | |
|         private readonly ILibraryMonitor _iLibraryMonitor;
 | |
|         private readonly ILogger _logger;
 | |
|         private readonly IProviderManager _providerManager;
 | |
| 
 | |
|         public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
 | |
|         public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
 | |
|         public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
 | |
| 
 | |
|         public CollectionManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor, ILogger logger, IProviderManager providerManager)
 | |
|         {
 | |
|             _libraryManager = libraryManager;
 | |
|             _fileSystem = fileSystem;
 | |
|             _iLibraryMonitor = iLibraryMonitor;
 | |
|             _logger = logger;
 | |
|             _providerManager = providerManager;
 | |
|         }
 | |
| 
 | |
|         public Folder GetCollectionsFolder(string userId)
 | |
|         {
 | |
|             return _libraryManager.RootFolder.Children.OfType<ManualCollectionsFolder>()
 | |
|                 .FirstOrDefault() ?? _libraryManager.GetUserRootFolder().Children.OfType<ManualCollectionsFolder>()
 | |
|                 .FirstOrDefault();
 | |
|         }
 | |
| 
 | |
|         public IEnumerable<BoxSet> GetCollections(User user)
 | |
|         {
 | |
|             var folder = GetCollectionsFolder(user.Id.ToString("N"));
 | |
|             return folder == null ?
 | |
|                 new List<BoxSet>() :
 | |
|                 folder.GetChildren(user, true).OfType<BoxSet>();
 | |
|         }
 | |
| 
 | |
|         public async Task<BoxSet> CreateCollection(CollectionCreationOptions options)
 | |
|         {
 | |
|             var name = options.Name;
 | |
| 
 | |
|             // Need to use the [boxset] suffix
 | |
|             // If internet metadata is not found, or if xml saving is off there will be no collection.xml
 | |
|             // This could cause it to get re-resolved as a plain folder
 | |
|             var folderName = _fileSystem.GetValidFilename(name) + " [boxset]";
 | |
| 
 | |
|             var parentFolder = GetParentFolder(options.ParentId);
 | |
| 
 | |
|             if (parentFolder == null)
 | |
|             {
 | |
|                 throw new ArgumentException();
 | |
|             }
 | |
| 
 | |
|             var path = Path.Combine(parentFolder.Path, folderName);
 | |
| 
 | |
|             _iLibraryMonitor.ReportFileSystemChangeBeginning(path);
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 _fileSystem.CreateDirectory(path);
 | |
| 
 | |
|                 var collection = new BoxSet
 | |
|                 {
 | |
|                     Name = name,
 | |
|                     Path = path,
 | |
|                     IsLocked = options.IsLocked,
 | |
|                     ProviderIds = options.ProviderIds,
 | |
|                     Shares = options.UserIds.Select(i => new Share
 | |
|                     {
 | |
|                         UserId = i.ToString("N"),
 | |
|                         CanEdit = true
 | |
| 
 | |
|                     }).ToList()
 | |
|                 };
 | |
| 
 | |
|                 await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false);
 | |
| 
 | |
|                 if (options.ItemIdList.Count > 0)
 | |
|                 {
 | |
|                     await AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(_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
 | |
|                     });
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem));
 | |
|                 }
 | |
| 
 | |
|                 EventHelper.FireEventIfNotNull(CollectionCreated, this, new CollectionCreatedEventArgs
 | |
|                 {
 | |
|                     Collection = collection,
 | |
|                     Options = options
 | |
| 
 | |
|                 }, _logger);
 | |
| 
 | |
|                 return collection;
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 // Refresh handled internally
 | |
|                 _iLibraryMonitor.ReportFileSystemChangeComplete(path, false);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private Folder GetParentFolder(Guid? parentId)
 | |
|         {
 | |
|             if (parentId.HasValue)
 | |
|             {
 | |
|                 if (parentId.Value == Guid.Empty)
 | |
|                 {
 | |
|                     throw new ArgumentNullException("parentId");
 | |
|                 }
 | |
| 
 | |
|                 var folder = _libraryManager.GetItemById(parentId.Value) as Folder;
 | |
| 
 | |
|                 // Find an actual physical folder
 | |
|                 if (folder is CollectionFolder)
 | |
|                 {
 | |
|                     var child = _libraryManager.RootFolder.Children.OfType<Folder>()
 | |
|                         .FirstOrDefault(i => folder.PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase));
 | |
| 
 | |
|                     if (child != null)
 | |
|                     {
 | |
|                         return child;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return GetCollectionsFolder(string.Empty);
 | |
|         }
 | |
| 
 | |
|         public Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
 | |
|         {
 | |
|             return AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(_fileSystem));
 | |
|         }
 | |
| 
 | |
|         private async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
 | |
|         {
 | |
|             var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
 | |
| 
 | |
|             if (collection == null)
 | |
|             {
 | |
|                 throw new ArgumentException("No collection exists with the supplied Id");
 | |
|             }
 | |
| 
 | |
|             var list = new List<LinkedChild>();
 | |
|             var itemList = new List<BaseItem>();
 | |
|             var currentLinkedChildren = collection.GetLinkedChildren().ToList();
 | |
| 
 | |
|             foreach (var itemId in ids)
 | |
|             {
 | |
|                 var item = _libraryManager.GetItemById(itemId);
 | |
| 
 | |
|                 if (item == null)
 | |
|                 {
 | |
|                     throw new ArgumentException("No item exists with the supplied Id");
 | |
|                 }
 | |
| 
 | |
|                 itemList.Add(item);
 | |
| 
 | |
|                 if (currentLinkedChildren.All(i => i.Id != itemId))
 | |
|                 {
 | |
|                     list.Add(LinkedChild.Create(item));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (list.Count > 0)
 | |
|             {
 | |
|                 collection.LinkedChildren.AddRange(list);
 | |
| 
 | |
|                 collection.UpdateRatingToContent();
 | |
| 
 | |
|                 await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
 | |
| 
 | |
|                 _providerManager.QueueRefresh(collection.Id, refreshOptions);
 | |
| 
 | |
|                 if (fireEvent)
 | |
|                 {
 | |
|                     EventHelper.FireEventIfNotNull(ItemsAddedToCollection, this, new CollectionModifiedEventArgs
 | |
|                     {
 | |
|                         Collection = collection,
 | |
|                         ItemsChanged = itemList
 | |
| 
 | |
|                     }, _logger);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public async Task RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds)
 | |
|         {
 | |
|             var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
 | |
| 
 | |
|             if (collection == null)
 | |
|             {
 | |
|                 throw new ArgumentException("No collection exists with the supplied Id");
 | |
|             }
 | |
| 
 | |
|             var list = new List<LinkedChild>();
 | |
|             var itemList = new List<BaseItem>();
 | |
| 
 | |
|             foreach (var itemId in itemIds)
 | |
|             {
 | |
|                 var child = collection.LinkedChildren.FirstOrDefault(i => i.ItemId.HasValue && i.ItemId.Value == itemId);
 | |
| 
 | |
|                 if (child == null)
 | |
|                 {
 | |
|                     throw new ArgumentException("No collection title exists with the supplied Id");
 | |
|                 }
 | |
| 
 | |
|                 list.Add(child);
 | |
| 
 | |
|                 var childItem = _libraryManager.GetItemById(itemId);
 | |
| 
 | |
|                 if (childItem != null)
 | |
|                 {
 | |
|                     itemList.Add(childItem);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             var shortcutFiles = _fileSystem
 | |
|                 .GetFilePaths(collection.Path)
 | |
|                 .Where(i => _fileSystem.IsShortcut(i))
 | |
|                 .ToList();
 | |
| 
 | |
|             var shortcutFilesToDelete = list.Where(child => !string.IsNullOrWhiteSpace(child.Path) && child.Type == LinkedChildType.Shortcut)
 | |
|                 .Select(child => shortcutFiles.FirstOrDefault(i => string.Equals(child.Path, _fileSystem.ResolveShortcut(i), StringComparison.OrdinalIgnoreCase)))
 | |
|                 .Where(i => !string.IsNullOrWhiteSpace(i))
 | |
|                 .ToList();
 | |
| 
 | |
|             foreach (var file in shortcutFilesToDelete)
 | |
|             {
 | |
|                 _iLibraryMonitor.ReportFileSystemChangeBeginning(file);
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 foreach (var file in shortcutFilesToDelete)
 | |
|                 {
 | |
|                     _fileSystem.DeleteFile(file);
 | |
|                 }
 | |
| 
 | |
|                 foreach (var child in list)
 | |
|                 {
 | |
|                     collection.LinkedChildren.Remove(child);
 | |
|                 }
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 foreach (var file in shortcutFilesToDelete)
 | |
|                 {
 | |
|                     _iLibraryMonitor.ReportFileSystemChangeComplete(file, false);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             collection.UpdateRatingToContent();
 | |
| 
 | |
|             await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
 | |
|             _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem));
 | |
| 
 | |
|             EventHelper.FireEventIfNotNull(ItemsRemovedFromCollection, this, new CollectionModifiedEventArgs
 | |
|             {
 | |
|                 Collection = collection,
 | |
|                 ItemsChanged = itemList
 | |
| 
 | |
|             }, _logger);
 | |
|         }
 | |
| 
 | |
|         public IEnumerable<BaseItem> CollapseItemsWithinBoxSets(IEnumerable<BaseItem> items, User user)
 | |
|         {
 | |
|             var results = new Dictionary<Guid, BaseItem>();
 | |
| 
 | |
|             var allBoxsets = GetCollections(user).ToList();
 | |
| 
 | |
|             foreach (var item in items)
 | |
|             {
 | |
|                 var grouping = item as ISupportsBoxSetGrouping;
 | |
| 
 | |
|                 if (grouping == null)
 | |
|                 {
 | |
|                     results[item.Id] = item;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     var itemId = item.Id;
 | |
| 
 | |
|                     var currentBoxSets = allBoxsets
 | |
|                         .Where(i => i.GetLinkedChildren().Any(j => j.Id == itemId))
 | |
|                         .ToList();
 | |
| 
 | |
|                     if (currentBoxSets.Count > 0)
 | |
|                     {
 | |
|                         foreach (var boxset in currentBoxSets)
 | |
|                         {
 | |
|                             results[boxset.Id] = boxset;
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         results[item.Id] = item;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return results.Values;
 | |
|         }
 | |
|     }
 | |
| }
 |