diff options
| author | Luke <luke.pulverenti@gmail.com> | 2016-12-18 00:44:33 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-12-18 00:44:33 -0500 |
| commit | e7cebb91a73354dc3e0d0b6340c9fbd6511f4406 (patch) | |
| tree | 6f1c368c766c17b7514fe749c0e92e69cd89194a /Emby.Server.Implementations/Collections | |
| parent | 025905a3e4d50b9a2e07fbf4ff0a203af6604ced (diff) | |
| parent | aaa027f3229073e9a40756c3157d41af2a442922 (diff) | |
Merge pull request #2350 from MediaBrowser/beta
Beta
Diffstat (limited to 'Emby.Server.Implementations/Collections')
3 files changed, 414 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs new file mode 100644 index 000000000..b82d4e44e --- /dev/null +++ b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs @@ -0,0 +1,84 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Emby.Server.Implementations.Images; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Extensions; + +namespace Emby.Server.Implementations.Collections +{ + public class CollectionImageProvider : BaseDynamicImageProvider<BoxSet> + { + public CollectionImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor) : base(fileSystem, providerManager, applicationPaths, imageProcessor) + { + } + + protected override bool Supports(IHasImages item) + { + // Right now this is the only way to prevent this image from getting created ahead of internet image providers + if (!item.IsLocked) + { + return false; + } + + return base.Supports(item); + } + + protected override Task<List<BaseItem>> GetItemsWithImages(IHasImages item) + { + var playlist = (BoxSet)item; + + var items = playlist.Children.Concat(playlist.GetLinkedChildren()) + .Select(i => + { + var subItem = i; + + var episode = subItem as Episode; + + if (episode != null) + { + var series = episode.Series; + if (series != null && series.HasImage(ImageType.Primary)) + { + return series; + } + } + + if (subItem.HasImage(ImageType.Primary)) + { + return subItem; + } + + var parent = subItem.GetParent(); + + if (parent != null && parent.HasImage(ImageType.Primary)) + { + if (parent is MusicAlbum) + { + return parent; + } + } + + return null; + }) + .Where(i => i != null) + .DistinctBy(i => i.Id) + .ToList(); + + return Task.FromResult(GetFinalItems(items, 2)); + } + + protected override Task<string> CreateImage(IHasImages item, List<BaseItem> itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) + { + return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary); + } + } +} diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs new file mode 100644 index 000000000..d0bd76c35 --- /dev/null +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -0,0 +1,296 @@ +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 MediaBrowser.Model.IO; + +namespace Emby.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 childItem = _libraryManager.GetItemById(itemId); + + var child = collection.LinkedChildren.FirstOrDefault(i => (i.ItemId.HasValue && i.ItemId.Value == itemId) || (childItem != null && string.Equals(childItem.Path, i.Path, StringComparison.OrdinalIgnoreCase))); + + if (child == null) + { + throw new ArgumentException("No collection title exists with the supplied Id"); + } + + list.Add(child); + + if (childItem != null) + { + itemList.Add(childItem); + } + } + + foreach (var child in list) + { + collection.LinkedChildren.Remove(child); + } + + 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; + } + } +} diff --git a/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs b/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs new file mode 100644 index 000000000..4ff33e645 --- /dev/null +++ b/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs @@ -0,0 +1,34 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities; +using System.IO; +using MediaBrowser.Common.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Controller.Collections; +using MediaBrowser.Controller.IO; + +namespace Emby.Server.Implementations.Collections +{ + public class CollectionsDynamicFolder : IVirtualFolderCreator + { + private readonly IApplicationPaths _appPaths; + private readonly IFileSystem _fileSystem; + + public CollectionsDynamicFolder(IApplicationPaths appPaths, IFileSystem fileSystem) + { + _appPaths = appPaths; + _fileSystem = fileSystem; + } + + public BasePluginFolder GetFolder() + { + var path = Path.Combine(_appPaths.DataPath, "collections"); + + _fileSystem.CreateDirectory(path); + + return new ManualCollectionsFolder + { + Path = path + }; + } + } +} |
