diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 85e40eda15..e19fbb967f 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 0000000000..456449b7b6
--- /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/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
similarity index 98%
rename from MediaBrowser.Api/MoviesService.cs
rename to MediaBrowser.Api/Movies/MoviesService.cs
index 2a99bca8b0..5d97d13e15 100644
--- a/MediaBrowser.Api/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack;
-namespace MediaBrowser.Api
+namespace MediaBrowser.Api.Movies
{
///
/// Class GetSimilarMovies
diff --git a/MediaBrowser.Api/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs
similarity index 98%
rename from MediaBrowser.Api/TrailersService.cs
rename to MediaBrowser.Api/Movies/TrailersService.cs
index ca465b5e32..4e17bc7b50 100644
--- a/MediaBrowser.Api/TrailersService.cs
+++ b/MediaBrowser.Api/Movies/TrailersService.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack;
-namespace MediaBrowser.Api
+namespace MediaBrowser.Api.Movies
{
///
/// Class GetSimilarTrailers
diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs
index 18bd8c6956..c3da87d401 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.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs
index d26bf5b352..089f9b6ad2 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 a1e6b2c120..d7bc178ad3 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 923673bd83..0deebeb323 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 8f70710003..29d66718c4 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 627f657ab3..7dfe7f22e1 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 cc5f7bf38c..84af0500dd 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 87ff7af669..678dfd39d7 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 b8ab55db08..03fe5c8029 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 da444d100a..679b629a86 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 0000000000..834fbcd315
--- /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 12686f5426..b22fd343b3 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 bd315530e1..104ebfab84 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 0165cefad8..a0df2c23ac 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 3c984e2656..f04536190b 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 53788e09af..978f318515 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 479e07ee6c..a3a8785371 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 cbc4501c5c..3359125c3b 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 c10b17d678..19f213b2ff 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 4895d203f5..424192e283 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