From 2349c8099d04c6c0631cd33e6c74b404381946ab Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 6 Mar 2014 00:17:13 -0500 Subject: start on manual collection creation --- .../Library/Resolvers/Audio/MusicAlbumResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.Server.Implementations/Library') diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 871171541..ac1927931 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio var collectionType = args.GetCollectionType(); - // If there's a collection type and it's not music, it can't be a series + // If there's a collection type and it's not music, don't allow it. if (!string.IsNullOrEmpty(collectionType) && !string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) { -- cgit v1.2.3 From e00985d07ca3923f7f558b8592c0d092842bff5d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Mar 2014 10:53:23 -0500 Subject: #715 - Support creating/editing collections (boxsets) in web client --- MediaBrowser.Api/MediaBrowser.Api.csproj | 5 +- MediaBrowser.Api/Movies/CollectionService.cs | 80 +++++++++++++++++++ MediaBrowser.Api/Movies/MoviesService.cs | 82 +++++++++++++++++++ MediaBrowser.Api/Movies/TrailersService.cs | 75 ++++++++++++++++++ MediaBrowser.Api/MoviesService.cs | 82 ------------------- MediaBrowser.Api/SearchService.cs | 6 +- MediaBrowser.Api/TrailersService.cs | 75 ------------------ .../Collections/CollectionCreationOptions.cs | 2 +- .../Collections/ICollectionManager.cs | 9 ++- MediaBrowser.Controller/Entities/BaseItem.cs | 9 +++ .../Entities/BasePluginFolder.cs | 15 +--- MediaBrowser.Controller/Entities/Folder.cs | 66 ++++++++++++---- MediaBrowser.Controller/Entities/LinkedChild.cs | 4 + MediaBrowser.Model/Search/SearchQuery.cs | 4 + MediaBrowser.Providers/Savers/XmlSaverHelpers.cs | 39 ++++++++- .../Collections/CollectionManager.cs | 92 ++++++++++++++++++++-- .../Collections/CollectionsDynamicFolder.cs | 55 +++++++++++++ .../Library/SearchEngine.cs | 6 ++ .../LiveTv/LiveTvManager.cs | 1 + .../MediaBrowser.Server.Implementations.csproj | 14 ++-- .../packages.config | 2 +- MediaBrowser.ServerApplication/App.config | 16 +++- MediaBrowser.ServerApplication/ApplicationHost.cs | 5 ++ MediaBrowser.Tests/app.config | 2 +- MediaBrowser.WebDashboard/Api/DashboardService.cs | 1 + .../MediaBrowser.WebDashboard.csproj | 8 +- 26 files changed, 545 insertions(+), 210 deletions(-) create mode 100644 MediaBrowser.Api/Movies/CollectionService.cs create mode 100644 MediaBrowser.Api/Movies/MoviesService.cs create mode 100644 MediaBrowser.Api/Movies/TrailersService.cs delete mode 100644 MediaBrowser.Api/MoviesService.cs delete mode 100644 MediaBrowser.Api/TrailersService.cs create mode 100644 MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs (limited to 'MediaBrowser.Server.Implementations/Library') diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 85e40eda1..e19fbb967 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -66,6 +66,7 @@ Properties\SharedVersion.cs + @@ -91,7 +92,7 @@ - + @@ -118,7 +119,7 @@ - + diff --git a/MediaBrowser.Api/Movies/CollectionService.cs b/MediaBrowser.Api/Movies/CollectionService.cs new file mode 100644 index 000000000..456449b7b --- /dev/null +++ b/MediaBrowser.Api/Movies/CollectionService.cs @@ -0,0 +1,80 @@ +using MediaBrowser.Controller.Collections; +using ServiceStack; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace MediaBrowser.Api.Movies +{ + [Route("/Collections", "POST")] + [Api(Description = "Creates a new collection")] + public class CreateCollection : IReturnVoid + { + [ApiMember(Name = "IsLocked", Description = "Whether or not to lock the new collection.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")] + public bool IsLocked { get; set; } + + [ApiMember(Name = "Name", Description = "The name of the new collection.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public string Name { get; set; } + + [ApiMember(Name = "ParentId", Description = "Optional - create the collection within a specific folder", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public Guid? ParentId { get; set; } + } + + [Route("/Collections/{Id}/Items", "POST")] + [Api(Description = "Adds items to a collection")] + public class AddToCollection : IReturnVoid + { + [ApiMember(Name = "Ids", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string Ids { get; set; } + + [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public Guid Id { get; set; } + } + + [Route("/Collections/{Id}/Items", "DELETE")] + [Api(Description = "Removes items from a collection")] + public class RemoveFromCollection : IReturnVoid + { + [ApiMember(Name = "Ids", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string Ids { get; set; } + + [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] + public Guid Id { get; set; } + } + + public class CollectionService : BaseApiService + { + private readonly ICollectionManager _collectionManager; + + public CollectionService(ICollectionManager collectionManager) + { + _collectionManager = collectionManager; + } + + public void Post(CreateCollection request) + { + var task = _collectionManager.CreateCollection(new CollectionCreationOptions + { + IsLocked = request.IsLocked, + Name = request.Name, + ParentId = request.ParentId + }); + + Task.WaitAll(task); + } + + public void Post(AddToCollection request) + { + var task = _collectionManager.AddToCollection(request.Id, request.Ids.Split(',').Select(i => new Guid(i))); + + Task.WaitAll(task); + } + + public void Delete(RemoveFromCollection request) + { + var task = _collectionManager.RemoveFromCollection(request.Id, request.Ids.Split(',').Select(i => new Guid(i))); + + Task.WaitAll(task); + } + } +} diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs new file mode 100644 index 000000000..5d97d13e1 --- /dev/null +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -0,0 +1,82 @@ +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using ServiceStack; + +namespace MediaBrowser.Api.Movies +{ + /// + /// Class GetSimilarMovies + /// + [Route("/Movies/{Id}/Similar", "GET")] + [Api(Description = "Finds movies and trailers similar to a given movie.")] + public class GetSimilarMovies : BaseGetSimilarItemsFromItem + { + [ApiMember(Name = "IncludeTrailers", Description = "Whether or not to include trailers within the results. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool IncludeTrailers { get; set; } + + public GetSimilarMovies() + { + IncludeTrailers = true; + } + } + + /// + /// Class MoviesService + /// + public class MoviesService : BaseApiService + { + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + + /// + /// The _user data repository + /// + private readonly IUserDataManager _userDataRepository; + /// + /// The _library manager + /// + private readonly ILibraryManager _libraryManager; + + private readonly IItemRepository _itemRepo; + private readonly IDtoService _dtoService; + + /// + /// Initializes a new instance of the class. + /// + /// The user manager. + /// The user data repository. + /// The library manager. + public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService) + { + _userManager = userManager; + _userDataRepository = userDataRepository; + _libraryManager = libraryManager; + _itemRepo = itemRepo; + _dtoService = dtoService; + } + + /// + /// Gets the specified request. + /// + /// The request. + /// System.Object. + public object Get(GetSimilarMovies request) + { + var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager, + _itemRepo, + _libraryManager, + _userDataRepository, + _dtoService, + Logger, + request, item => item is Movie || (item is Trailer && request.IncludeTrailers), + SimilarItemsHelper.GetSimiliarityScore); + + return ToOptimizedSerializedResultUsingCache(result); + } + } +} diff --git a/MediaBrowser.Api/Movies/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs new file mode 100644 index 000000000..4e17bc7b5 --- /dev/null +++ b/MediaBrowser.Api/Movies/TrailersService.cs @@ -0,0 +1,75 @@ +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using ServiceStack; + +namespace MediaBrowser.Api.Movies +{ + /// + /// Class GetSimilarTrailers + /// + [Route("/Trailers/{Id}/Similar", "GET")] + [Api(Description = "Finds movies and trailers similar to a given trailer.")] + public class GetSimilarTrailers : BaseGetSimilarItemsFromItem + { + } + + /// + /// Class TrailersService + /// + public class TrailersService : BaseApiService + { + /// + /// The _user manager + /// + private readonly IUserManager _userManager; + + /// + /// The _user data repository + /// + private readonly IUserDataManager _userDataRepository; + /// + /// The _library manager + /// + private readonly ILibraryManager _libraryManager; + + private readonly IItemRepository _itemRepo; + private readonly IDtoService _dtoService; + + /// + /// Initializes a new instance of the class. + /// + /// The user manager. + /// The user data repository. + /// The library manager. + public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService) + { + _userManager = userManager; + _userDataRepository = userDataRepository; + _libraryManager = libraryManager; + _itemRepo = itemRepo; + _dtoService = dtoService; + } + + /// + /// Gets the specified request. + /// + /// The request. + /// System.Object. + public object Get(GetSimilarTrailers request) + { + var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager, + _itemRepo, + _libraryManager, + _userDataRepository, + _dtoService, + Logger, + request, item => item is Movie || item is Trailer, + SimilarItemsHelper.GetSimiliarityScore); + + return ToOptimizedSerializedResultUsingCache(result); + } + } +} diff --git a/MediaBrowser.Api/MoviesService.cs b/MediaBrowser.Api/MoviesService.cs deleted file mode 100644 index 2a99bca8b..000000000 --- a/MediaBrowser.Api/MoviesService.cs +++ /dev/null @@ -1,82 +0,0 @@ -using MediaBrowser.Controller.Dto; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using ServiceStack; - -namespace MediaBrowser.Api -{ - /// - /// Class GetSimilarMovies - /// - [Route("/Movies/{Id}/Similar", "GET")] - [Api(Description = "Finds movies and trailers similar to a given movie.")] - public class GetSimilarMovies : BaseGetSimilarItemsFromItem - { - [ApiMember(Name = "IncludeTrailers", Description = "Whether or not to include trailers within the results. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] - public bool IncludeTrailers { get; set; } - - public GetSimilarMovies() - { - IncludeTrailers = true; - } - } - - /// - /// Class MoviesService - /// - public class MoviesService : BaseApiService - { - /// - /// The _user manager - /// - private readonly IUserManager _userManager; - - /// - /// The _user data repository - /// - private readonly IUserDataManager _userDataRepository; - /// - /// The _library manager - /// - private readonly ILibraryManager _libraryManager; - - private readonly IItemRepository _itemRepo; - private readonly IDtoService _dtoService; - - /// - /// Initializes a new instance of the class. - /// - /// The user manager. - /// The user data repository. - /// The library manager. - public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService) - { - _userManager = userManager; - _userDataRepository = userDataRepository; - _libraryManager = libraryManager; - _itemRepo = itemRepo; - _dtoService = dtoService; - } - - /// - /// Gets the specified request. - /// - /// The request. - /// System.Object. - public object Get(GetSimilarMovies request) - { - var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager, - _itemRepo, - _libraryManager, - _userDataRepository, - _dtoService, - Logger, - request, item => item is Movie || (item is Trailer && request.IncludeTrailers), - SimilarItemsHelper.GetSimiliarityScore); - - return ToOptimizedSerializedResultUsingCache(result); - } - } -} diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 18bd8c695..c3da87d40 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -63,6 +63,9 @@ namespace MediaBrowser.Api [ApiMember(Name = "IncludeArtists", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool IncludeArtists { get; set; } + [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string IncludeItemTypes { get; set; } + public GetSearchHints() { IncludeArtists = true; @@ -130,7 +133,8 @@ namespace MediaBrowser.Api IncludePeople = request.IncludePeople, IncludeStudios = request.IncludeStudios, StartIndex = request.StartIndex, - UserId = request.UserId + UserId = request.UserId, + IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',') }).ConfigureAwait(false); diff --git a/MediaBrowser.Api/TrailersService.cs b/MediaBrowser.Api/TrailersService.cs deleted file mode 100644 index ca465b5e3..000000000 --- a/MediaBrowser.Api/TrailersService.cs +++ /dev/null @@ -1,75 +0,0 @@ -using MediaBrowser.Controller.Dto; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using ServiceStack; - -namespace MediaBrowser.Api -{ - /// - /// Class GetSimilarTrailers - /// - [Route("/Trailers/{Id}/Similar", "GET")] - [Api(Description = "Finds movies and trailers similar to a given trailer.")] - public class GetSimilarTrailers : BaseGetSimilarItemsFromItem - { - } - - /// - /// Class TrailersService - /// - public class TrailersService : BaseApiService - { - /// - /// The _user manager - /// - private readonly IUserManager _userManager; - - /// - /// The _user data repository - /// - private readonly IUserDataManager _userDataRepository; - /// - /// The _library manager - /// - private readonly ILibraryManager _libraryManager; - - private readonly IItemRepository _itemRepo; - private readonly IDtoService _dtoService; - - /// - /// Initializes a new instance of the class. - /// - /// The user manager. - /// The user data repository. - /// The library manager. - public TrailersService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService) - { - _userManager = userManager; - _userDataRepository = userDataRepository; - _libraryManager = libraryManager; - _itemRepo = itemRepo; - _dtoService = dtoService; - } - - /// - /// Gets the specified request. - /// - /// The request. - /// System.Object. - public object Get(GetSimilarTrailers request) - { - var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager, - _itemRepo, - _libraryManager, - _userDataRepository, - _dtoService, - Logger, - request, item => item is Movie || item is Trailer, - SimilarItemsHelper.GetSimiliarityScore); - - return ToOptimizedSerializedResultUsingCache(result); - } - } -} diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index d26bf5b35..089f9b6ad 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Collections { public string Name { get; set; } - public Guid ParentId { get; set; } + public Guid? ParentId { get; set; } public bool IsLocked { get; set; } } diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index a1e6b2c12..d7bc178ad 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace MediaBrowser.Controller.Collections @@ -16,16 +17,16 @@ namespace MediaBrowser.Controller.Collections /// Adds to collection. /// /// The collection identifier. - /// The item identifier. + /// The item ids. /// Task. - Task AddToCollection(Guid collectionId, Guid itemId); + Task AddToCollection(Guid collectionId, IEnumerable itemIds); /// /// Removes from collection. /// /// The collection identifier. - /// The item identifier. + /// The item ids. /// Task. - Task RemoveFromCollection(Guid collectionId, Guid itemId); + Task RemoveFromCollection(Guid collectionId, IEnumerable itemIds); } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 923673bd8..0deebeb32 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -124,6 +124,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public virtual bool IsHidden + { + get + { + return false; + } + } + [IgnoreDataMember] public virtual bool IsOwnedItem { diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index 8f7071000..29d66718c 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Model.Entities; - + namespace MediaBrowser.Controller.Entities { /// @@ -8,18 +7,6 @@ namespace MediaBrowser.Controller.Entities /// public abstract class BasePluginFolder : Folder, ICollectionFolder, IByReferenceItem { - /// - /// Gets or sets the type of the location. - /// - /// The type of the location. - public override LocationType LocationType - { - get - { - return LocationType.Virtual; - } - } - protected BasePluginFolder() { DisplayMediaType = "CollectionFolder"; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 627f657ab..7dfe7f22e 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -264,7 +264,7 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] public IEnumerable Children { - get { return ActualChildren; } + get { return ActualChildren.Where(i => !i.IsHidden); } } /// @@ -905,13 +905,6 @@ namespace MediaBrowser.Controller.Entities /// BaseItem. private BaseItem GetLinkedChild(LinkedChild info) { - if (string.IsNullOrEmpty(info.Path)) - { - throw new ArgumentException("Encountered linked child with empty path."); - } - - BaseItem item = null; - // First get using the cached Id if (info.ItemId.HasValue) { @@ -920,20 +913,19 @@ namespace MediaBrowser.Controller.Entities return null; } - item = LibraryManager.GetItemById(info.ItemId.Value); - } + var itemById = LibraryManager.GetItemById(info.ItemId.Value); - // If still null, search by path - if (item == null) - { - item = LibraryManager.RootFolder.FindByPath(info.Path); + if (itemById != null) + { + return itemById; + } } + var item = FindLinkedChild(info); + // If still null, log if (item == null) { - Logger.Warn("Unable to find linked item at {0}", info.Path); - // Don't keep searching over and over info.ItemId = Guid.Empty; } @@ -946,6 +938,43 @@ namespace MediaBrowser.Controller.Entities return item; } + private BaseItem FindLinkedChild(LinkedChild info) + { + if (!string.IsNullOrEmpty(info.Path)) + { + var itemByPath = LibraryManager.RootFolder.FindByPath(info.Path); + + if (itemByPath == null) + { + Logger.Warn("Unable to find linked item at path {0}", info.Path); + } + + return itemByPath; + } + + if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType)) + { + return LibraryManager.RootFolder.RecursiveChildren.FirstOrDefault(i => + { + if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)) + { + if (string.Equals(i.GetType().Name, info.ItemType, StringComparison.OrdinalIgnoreCase)) + { + if (info.ItemYear.HasValue) + { + return info.ItemYear.Value == (i.ProductionYear ?? -1); + } + return true; + } + } + + return false; + }); + } + + return null; + } + protected override async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { var changesFound = false; @@ -1106,5 +1135,10 @@ namespace MediaBrowser.Controller.Entities return GetRecursiveChildren(user).Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) .All(i => i.IsUnplayed(user)); } + + public IEnumerable GetHiddenChildren() + { + return ActualChildren.Where(i => i.IsHidden); + } } } diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index cc5f7bf38..84af0500d 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -9,6 +9,10 @@ namespace MediaBrowser.Controller.Entities public string Path { get; set; } public LinkedChildType Type { get; set; } + public string ItemName { get; set; } + public string ItemType { get; set; } + public int? ItemYear { get; set; } + /// /// Serves as a cache /// diff --git a/MediaBrowser.Model/Search/SearchQuery.cs b/MediaBrowser.Model/Search/SearchQuery.cs index 87ff7af66..678dfd39d 100644 --- a/MediaBrowser.Model/Search/SearchQuery.cs +++ b/MediaBrowser.Model/Search/SearchQuery.cs @@ -33,6 +33,8 @@ namespace MediaBrowser.Model.Search public bool IncludeStudios { get; set; } public bool IncludeArtists { get; set; } + public string[] IncludeItemTypes { get; set; } + public SearchQuery() { IncludeArtists = true; @@ -40,6 +42,8 @@ namespace MediaBrowser.Model.Search IncludeMedia = true; IncludePeople = true; IncludeStudios = true; + + IncludeItemTypes = new string[] { }; } } } diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index b8ab55db0..03fe5c802 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; @@ -82,7 +83,8 @@ namespace MediaBrowser.Providers.Savers "TVRageId", "VoteCount", "Website", - "Zap2ItId" + "Zap2ItId", + "CollectionItems" }.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); @@ -580,6 +582,12 @@ namespace MediaBrowser.Providers.Savers builder.Append(""); } + + var folder = item as BoxSet; + if (folder != null) + { + AddCollectionItems(folder, builder); + } } public static void AddChapters(Video item, StringBuilder builder, IItemRepository repository) @@ -631,5 +639,34 @@ namespace MediaBrowser.Providers.Savers } } } + + public static void AddCollectionItems(Folder item, StringBuilder builder) + { + var items = item.LinkedChildren + .Where(i => i.Type == LinkedChildType.Manual && !string.IsNullOrWhiteSpace(i.ItemName)) + .ToList(); + + if (items.Count == 0) + { + return; + } + + builder.Append(""); + foreach (var link in items) + { + builder.Append(""); + + builder.Append("" + SecurityElement.Escape(link.ItemName) + ""); + builder.Append("" + SecurityElement.Escape(link.ItemType) + ""); + + if (link.ItemYear.HasValue) + { + builder.Append("" + SecurityElement.Escape(link.ItemYear.Value.ToString(UsCulture)) + ""); + } + + builder.Append(""); + } + builder.Append(""); + } } } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index da444d100..679b629a8 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -5,7 +5,9 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -30,7 +32,7 @@ namespace MediaBrowser.Server.Implementations.Collections var folderName = _fileSystem.GetValidFilename(name); - var parentFolder = _libraryManager.GetItemById(options.ParentId) as Folder; + var parentFolder = GetParentFolder(options.ParentId); if (parentFolder == null) { @@ -66,14 +68,94 @@ namespace MediaBrowser.Server.Implementations.Collections } } - public Task AddToCollection(Guid collectionId, Guid itemId) + private Folder GetParentFolder(Guid? parentId) { - throw new NotImplementedException(); + if (parentId.HasValue) + { + if (parentId.Value == Guid.Empty) + { + throw new ArgumentNullException("parentId"); + } + + return _libraryManager.GetItemById(parentId.Value) as Folder; + } + + return _libraryManager.RootFolder.Children.OfType().FirstOrDefault() ?? + _libraryManager.RootFolder.GetHiddenChildren().OfType().FirstOrDefault(); } - public Task RemoveFromCollection(Guid collectionId, Guid itemId) + public async Task AddToCollection(Guid collectionId, IEnumerable ids) { - throw new NotImplementedException(); + var collection = _libraryManager.GetItemById(collectionId) as BoxSet; + + if (collection == null) + { + throw new ArgumentException("No collection exists with the supplied Id"); + } + + var list = new List(); + + foreach (var itemId in ids) + { + var item = _libraryManager.GetItemById(itemId); + + if (item == null) + { + throw new ArgumentException("No item exists with the supplied Id"); + } + + if (collection.LinkedChildren.Any(i => i.ItemId.HasValue && i.ItemId == itemId)) + { + throw new ArgumentException("Item already exists in collection"); + } + + list.Add(new LinkedChild + { + ItemName = item.Name, + ItemYear = item.ProductionYear, + ItemType = item.GetType().Name, + Type = LinkedChildType.Manual + }); + } + + collection.LinkedChildren.AddRange(list); + + await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + + await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false); + } + + public async Task RemoveFromCollection(Guid collectionId, IEnumerable 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(); + + 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); + } + + foreach (var child in list) + { + collection.LinkedChildren.Remove(child); + } + + await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + + await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs new file mode 100644 index 000000000..834fbcd31 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs @@ -0,0 +1,55 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.Collections +{ + public class CollectionsDynamicFolder : IVirtualFolderCreator + { + private readonly IApplicationPaths _appPaths; + + public CollectionsDynamicFolder(IApplicationPaths appPaths) + { + _appPaths = appPaths; + } + + public BasePluginFolder GetFolder() + { + var path = Path.Combine(_appPaths.DataPath, "collections"); + + Directory.CreateDirectory(path); + + return new ManualCollectionsFolder + { + Path = path + }; + } + } + + public class ManualCollectionsFolder : BasePluginFolder + { + public ManualCollectionsFolder() + { + Name = "Collections"; + } + + public override bool IsVisible(User user) + { + if (!GetChildren(user, true).Any()) + { + return false; + } + + return base.IsVisible(user); + } + + public override bool IsHidden + { + get + { + return !ActualChildren.Any() || base.IsHidden; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 12686f542..b22fd343b 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -37,6 +37,12 @@ namespace MediaBrowser.Server.Implementations.Library var results = await GetSearchHints(inputItems, query).ConfigureAwait(false); + // Include item types + if (query.IncludeItemTypes.Length > 0) + { + results = results.Where(f => query.IncludeItemTypes.Contains(f.Item.GetType().Name, StringComparer.OrdinalIgnoreCase)); + } + var searchResultArray = results.ToArray(); results = searchResultArray; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index bd315530e..104ebfab8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -583,6 +583,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase); programs = programList.OrderByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres)) + .ThenBy(i => i.HasImage(ImageType.Primary) ? 0 : 1) .ThenBy(i => i.StartDate); if (query.Limit.HasValue) diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 0165cefad..a0df2c23a 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -65,12 +65,9 @@ - + False - ..\packages\System.Data.SQLite.x86.1.0.90.0\lib\net45\System.Data.SQLite.dll - - - ..\packages\System.Data.SQLite.x86.1.0.90.0\lib\net45\System.Data.SQLite.Linq.dll + ..\packages\System.Data.SQLite.Core.1.0.91.3\lib\net45\System.Data.SQLite.dll @@ -110,6 +107,7 @@ + @@ -378,6 +376,12 @@ swagger-ui\swagger-ui.min.js PreserveNewest + + Always + + + Always + diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index 3c984e265..f04536190 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -4,5 +4,5 @@ - + \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/App.config b/MediaBrowser.ServerApplication/App.config index 53788e09a..978f31851 100644 --- a/MediaBrowser.ServerApplication/App.config +++ b/MediaBrowser.ServerApplication/App.config @@ -2,6 +2,8 @@
+ +
@@ -43,7 +45,7 @@ - + @@ -63,4 +65,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 479e07ee6..a3a878537 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -9,6 +9,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; +using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; @@ -36,6 +37,7 @@ using MediaBrowser.Model.Updates; using MediaBrowser.Providers.Manager; using MediaBrowser.Server.Implementations; using MediaBrowser.Server.Implementations.BdInfo; +using MediaBrowser.Server.Implementations.Collections; using MediaBrowser.Server.Implementations.Configuration; using MediaBrowser.Server.Implementations.Drawing; using MediaBrowser.Server.Implementations.Dto; @@ -488,6 +490,9 @@ namespace MediaBrowser.ServerApplication var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger); RegisterSingleInstance(appThemeManager); + var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor); + RegisterSingleInstance(collectionManager); + LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager); RegisterSingleInstance(LiveTvManager); diff --git a/MediaBrowser.Tests/app.config b/MediaBrowser.Tests/app.config index cbc4501c5..3359125c3 100644 --- a/MediaBrowser.Tests/app.config +++ b/MediaBrowser.Tests/app.config @@ -4,7 +4,7 @@ - + diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index c10b17d67..19f213b2f 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -480,6 +480,7 @@ namespace MediaBrowser.WebDashboard.Api "dashboardinfo.js", "dashboardpage.js", "directorybrowser.js", + "editcollectionitems.js", "edititemmetadata.js", "edititempeople.js", "edititemimages.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 4895d203f..424192e28 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -213,6 +213,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -261,7 +264,7 @@ PreserveNewest - + PreserveNewest @@ -480,6 +483,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest -- cgit v1.2.3 From 546acf0ebb7edce384822770ccc6fca43fb2cc1c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Mar 2014 13:48:55 -0500 Subject: fixes #715 - Support creating/editing collections (boxsets) in web client #715 --- MediaBrowser.Api/SearchService.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 4 +- MediaBrowser.Controller/Entities/LinkedChild.cs | 6 +- MediaBrowser.Controller/Library/IUserManager.cs | 3 +- .../BoxSets/BoxSetMetadataService.cs | 10 ++ MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs | 129 +++++++++++++++++++++ .../BoxSets/BoxSetXmlProvider.cs | 2 +- .../MediaBrowser.Providers.csproj | 1 + .../Collections/CollectionManager.cs | 34 +++++- .../Library/UserManager.cs | 9 +- .../LiveTv/LiveTvManager.cs | 4 +- 11 files changed, 184 insertions(+), 20 deletions(-) create mode 100644 MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs (limited to 'MediaBrowser.Server.Implementations/Library') diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index c3da87d40..455cf6a50 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -134,7 +134,7 @@ namespace MediaBrowser.Api IncludeStudios = request.IncludeStudios, StartIndex = request.StartIndex, UserId = request.UserId, - IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',') + IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray() }).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 7dfe7f22e..ee371680e 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -745,9 +745,9 @@ namespace MediaBrowser.Controller.Entities var list = new List(); - AddChildrenToList(user, includeLinkedChildren, list, false, null); + var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false, null); - return list; + return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; } /// diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index 84af0500d..1ae04e40f 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -22,8 +22,8 @@ namespace MediaBrowser.Controller.Entities public enum LinkedChildType { - Manual = 1, - Shortcut = 2 + Manual = 0, + Shortcut = 1 } public class LinkedChildComparer : IEqualityComparer @@ -39,7 +39,7 @@ namespace MediaBrowser.Controller.Entities public int GetHashCode(LinkedChild obj) { - return (obj.Path + obj.Type.ToString()).GetHashCode(); + return (obj.Path + obj.Type).GetHashCode(); } } } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 0502ec419..c3b0748cf 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -51,9 +51,8 @@ namespace MediaBrowser.Controller.Library /// Refreshes metadata for each user /// /// The cancellation token. - /// if set to true [force]. /// Task. - Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false); + Task RefreshUsersMetadata(CancellationToken cancellationToken); /// /// Renames the user. diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index 9547eedd9..49e616d1a 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -37,6 +38,15 @@ namespace MediaBrowser.Providers.BoxSets protected override void MergeData(BoxSet source, BoxSet target, List lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + + if (mergeMetadataSettings) + { + var list = source.LinkedChildren.ToList(); + + list.AddRange(target.LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut)); + + target.LinkedChildren = list; + } } protected override ItemUpdateType BeforeSave(BoxSet item) diff --git a/MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs b/MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs new file mode 100644 index 000000000..eb3c99cef --- /dev/null +++ b/MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs @@ -0,0 +1,129 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Logging; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; + +namespace MediaBrowser.Providers.BoxSets +{ + public class BoxSetXmlParser : BaseItemXmlParser + { + private readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + public BoxSetXmlParser(ILogger logger) + : base(logger) + { + } + + protected override void FetchDataFromXmlNode(XmlReader reader, BoxSet item) + { + switch (reader.Name) + { + case "CollectionItems": + + using (var subReader = reader.ReadSubtree()) + { + FetchFromCollectionItemsNode(subReader, item); + } + break; + + default: + base.FetchDataFromXmlNode(reader, item); + break; + } + } + + private void FetchFromCollectionItemsNode(XmlReader reader, BoxSet item) + { + reader.MoveToContent(); + + var list = new List(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "CollectionItem": + { + using (var subReader = reader.ReadSubtree()) + { + var child = GetLinkedChild(subReader); + + if (child != null) + { + list.Add(child); + } + } + + break; + } + + default: + reader.Skip(); + break; + } + } + } + + item.LinkedChildren = list; + } + + private LinkedChild GetLinkedChild(XmlReader reader) + { + reader.MoveToContent(); + + var linkedItem = new LinkedChild + { + Type = LinkedChildType.Manual + }; + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Name": + { + linkedItem.ItemName = reader.ReadElementContentAsString(); + break; + } + + case "Type": + { + linkedItem.ItemType = reader.ReadElementContentAsString(); + break; + } + + case "Year": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + int rval; + + if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval)) + { + linkedItem.ItemYear = rval; + } + } + + break; + } + + default: + reader.Skip(); + break; + } + } + } + + return string.IsNullOrWhiteSpace(linkedItem.ItemName) || string.IsNullOrWhiteSpace(linkedItem.ItemType) ? null : linkedItem; + } + } +} diff --git a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs index e9896c28e..77ea52fa9 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.BoxSets protected override void Fetch(LocalMetadataResult result, string path, CancellationToken cancellationToken) { - new BaseItemXmlParser(_logger).Fetch(result.Item, path, cancellationToken); + new BoxSetXmlParser(_logger).Fetch(result.Item, path, cancellationToken); } protected override FileInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index a5ea1b64b..79cbdfa68 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -75,6 +75,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index 679b629a8..5a5dfdd3e 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -148,9 +148,39 @@ namespace MediaBrowser.Server.Implementations.Collections list.Add(child); } - foreach (var child in list) + var shortcutFiles = Directory + .EnumerateFiles(collection.Path, "*", SearchOption.TopDirectoryOnly) + .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 { - collection.LinkedChildren.Remove(child); + foreach (var file in shortcutFilesToDelete) + { + File.Delete(file); + } + + foreach (var child in list) + { + collection.LinkedChildren.Remove(child); + } + } + finally + { + foreach (var file in shortcutFilesToDelete) + { + _iLibraryMonitor.ReportFileSystemChangeComplete(file, false); + } } await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 8654a26ce..06028d37e 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -189,15 +189,10 @@ namespace MediaBrowser.Server.Implementations.Library /// Refreshes metadata for each user /// /// The cancellation token. - /// if set to true [force]. /// Task. - public Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false) + public Task RefreshUsersMetadata(CancellationToken cancellationToken) { - var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions - { - ReplaceAllMetadata = force - - }, cancellationToken)).ToList(); + var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken)).ToList(); return Task.WhenAll(tasks); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 104ebfab8..7c0361a1f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -582,8 +582,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv .Select(i => _libraryManager.GetGenre(i)) .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase); - programs = programList.OrderByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres)) - .ThenBy(i => i.HasImage(ImageType.Primary) ? 0 : 1) + programs = programList.OrderBy(i => i.HasImage(ImageType.Primary) ? 0 : 1) + .ThenByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres)) .ThenBy(i => i.StartDate); if (query.Limit.HasValue) -- cgit v1.2.3 From d49494476770b3c0a091841bd3bbd44862fb8137 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 9 Mar 2014 18:14:44 -0400 Subject: calculate item by name counts on the fly --- MediaBrowser.Api/BaseApiService.cs | 5 +- .../DefaultTheme/DefaultThemeService.cs | 6 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 81 +++++++------- MediaBrowser.Api/SearchService.cs | 6 +- MediaBrowser.Api/UserLibrary/ArtistsService.cs | 14 ++- .../UserLibrary/BaseItemsByNameService.cs | 38 +++---- MediaBrowser.Api/UserLibrary/GameGenresService.cs | 9 +- MediaBrowser.Api/UserLibrary/GenresService.cs | 9 +- MediaBrowser.Api/UserLibrary/MusicGenresService.cs | 9 +- MediaBrowser.Api/UserLibrary/PersonsService.cs | 9 +- MediaBrowser.Api/UserLibrary/StudiosService.cs | 9 +- MediaBrowser.Api/UserLibrary/YearsService.cs | 19 +--- .../Channels/ChannelItemInfo.cs | 67 ++++++++++++ MediaBrowser.Controller/Channels/IChannel.cs | 57 ++++++++++ .../Channels/IChannelManager.cs | 12 +++ MediaBrowser.Controller/Dto/IDtoService.cs | 21 ++++ MediaBrowser.Controller/Entities/Audio/Audio.cs | 18 ++++ .../Entities/Audio/MusicArtist.cs | 11 +- .../Entities/Audio/MusicGenre.cs | 18 ++-- MediaBrowser.Controller/Entities/GameGenre.cs | 17 ++- MediaBrowser.Controller/Entities/Genre.cs | 18 ++-- MediaBrowser.Controller/Entities/IItemByName.cs | 38 ++----- MediaBrowser.Controller/Entities/Person.cs | 17 ++- MediaBrowser.Controller/Entities/Studio.cs | 18 ++-- MediaBrowser.Controller/Entities/Year.cs | 29 ++--- MediaBrowser.Controller/Library/ILibraryManager.cs | 13 --- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 7 -- MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 15 +-- .../MediaBrowser.Controller.csproj | 3 + MediaBrowser.Model/Querying/ItemSortBy.cs | 7 -- .../Dto/DtoService.cs | 62 ++++++----- .../Library/LibraryManager.cs | 9 +- .../Library/SearchEngine.cs | 4 +- .../Library/Validators/ArtistsValidator.cs | 45 +------- .../Library/Validators/GameGenresValidator.cs | 62 ++--------- .../Library/Validators/GenresValidator.cs | 62 ++--------- .../Library/Validators/MusicGenresValidator.cs | 73 +++---------- .../Library/Validators/PeoplePostScanTask.cs | 103 ++---------------- .../Library/Validators/PeopleValidator.cs | 6 +- .../Library/Validators/StudiosValidator.cs | 65 ++---------- .../LiveTv/LiveTvManager.cs | 118 ++++++++++++++------- .../MediaBrowser.Server.Implementations.csproj | 7 -- .../Sorting/AlbumCountComparer.cs | 71 ------------- .../Sorting/EpisodeCountComparer.cs | 71 ------------- .../Sorting/MovieCountComparer.cs | 71 ------------- .../Sorting/MusicVideoCountComparer.cs | 71 ------------- .../Sorting/SeriesCountComparer.cs | 71 ------------- .../Sorting/SongCountComparer.cs | 71 ------------- .../Sorting/TrailerCountComparer.cs | 71 ------------- 49 files changed, 517 insertions(+), 1196 deletions(-) create mode 100644 MediaBrowser.Controller/Channels/ChannelItemInfo.cs create mode 100644 MediaBrowser.Controller/Channels/IChannel.cs create mode 100644 MediaBrowser.Controller/Channels/IChannelManager.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/AlbumCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/EpisodeCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/MovieCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/MusicVideoCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/SeriesCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/SongCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/TrailerCountComparer.cs (limited to 'MediaBrowser.Server.Implementations/Library') diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 5fba539fe..08686b43a 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -164,7 +164,10 @@ namespace MediaBrowser.Api return name; } - return libraryManager.GetAllArtists() + return libraryManager.RootFolder.RecursiveChildren + .OfType