瀏覽代碼

improve poster sizing

Luke Pulverenti 11 年之前
父節點
當前提交
f0464dfa17

+ 1 - 0
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -70,6 +70,7 @@
     <Compile Include="Dlna\DlnaServerService.cs" />
     <Compile Include="Dlna\DlnaService.cs" />
     <Compile Include="Library\ChapterService.cs" />
+    <Compile Include="PlaylistService.cs" />
     <Compile Include="Subtitles\SubtitleService.cs" />
     <Compile Include="Movies\CollectionService.cs" />
     <Compile Include="Music\AlbumsService.cs" />

+ 1 - 5
MediaBrowser.Api/Movies/CollectionService.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Controller.Collections;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Collections;
 using MediaBrowser.Model.Querying;
 using ServiceStack;
 using System;
@@ -92,9 +93,4 @@ namespace MediaBrowser.Api.Movies
             Task.WaitAll(task);
         }
     }
-
-    public class CollectionCreationResult
-    {
-        public string Id { get; set; }
-    }
 }

+ 84 - 0
MediaBrowser.Api/PlaylistService.cs

@@ -0,0 +1,84 @@
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Playlists;
+using MediaBrowser.Model.Playlists;
+using MediaBrowser.Model.Querying;
+using ServiceStack;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api
+{
+    [Route("/Playlists", "POST", Summary = "Creates a new playlist")]
+    public class CreatePlaylist : IReturn<PlaylistCreationResult>
+    {
+        [ApiMember(Name = "Name", Description = "The name of the new playlist.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+        public string Name { get; set; }
+
+        [ApiMember(Name = "Ids", Description = "Item Ids to add to the playlist", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)]
+        public string Ids { get; set; }
+    }
+
+    [Route("/Playlists/{Id}/Items", "POST", Summary = "Adds items to a playlist")]
+    public class AddToPlaylist : 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 string Id { get; set; }
+    }
+
+    [Route("/Playlists/{Id}/Items", "DELETE", Summary = "Removes items from a playlist")]
+    public class RemoveFromPlaylist : IReturnVoid
+    {
+        [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+        public string Id { get; set; }
+    }
+
+    [Authenticated]
+    public class PlaylistService : BaseApiService
+    {
+        private readonly IPlaylistManager _playlistManager;
+        private readonly IDtoService _dtoService;
+
+        public PlaylistService(IDtoService dtoService, IPlaylistManager playlistManager)
+        {
+            _dtoService = dtoService;
+            _playlistManager = playlistManager;
+        }
+
+        public object Post(CreatePlaylist request)
+        {
+            var task = _playlistManager.CreatePlaylist(new PlaylistCreationOptions
+            {
+                Name = request.Name,
+                ItemIdList = (request.Ids ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList()
+            });
+
+            var item = task.Result;
+
+            var dto = _dtoService.GetBaseItemDto(item, new List<ItemFields>());
+
+            return ToOptimizedResult(new PlaylistCreationResult
+            {
+                Id = dto.Id
+            });
+        }
+
+        public void Post(AddToPlaylist request)
+        {
+            var task = _playlistManager.AddToPlaylist(request.Id, request.Ids.Split(','));
+
+            Task.WaitAll(task);
+        }
+
+        public void Delete(RemoveFromPlaylist request)
+        {
+            //var task = _playlistManager.RemoveFromPlaylist(request.Id, request.Ids.Split(',').Select(i => new Guid(i)));
+
+            //Task.WaitAll(task);
+        }
+    }
+}

+ 3 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -217,6 +217,9 @@
     <Compile Include="Notifications\UserNotification.cs" />
     <Compile Include="Persistence\IFileOrganizationRepository.cs" />
     <Compile Include="Persistence\MediaStreamQuery.cs" />
+    <Compile Include="Playlists\IPlaylistManager.cs" />
+    <Compile Include="Playlists\Playlist.cs" />
+    <Compile Include="Playlists\PlaylistCreationOptions.cs" />
     <Compile Include="Providers\DirectoryService.cs" />
     <Compile Include="Providers\ICustomMetadataProvider.cs" />
     <Compile Include="Providers\IExternalId.cs" />

+ 47 - 0
MediaBrowser.Controller/Playlists/IPlaylistManager.cs

@@ -0,0 +1,47 @@
+using MediaBrowser.Controller.Entities;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Playlists
+{
+    public interface IPlaylistManager
+    {
+        /// <summary>
+        /// Gets the playlists.
+        /// </summary>
+        /// <param name="userId">The user identifier.</param>
+        /// <returns>IEnumerable&lt;Playlist&gt;.</returns>
+        IEnumerable<Playlist> GetPlaylists(string userId);
+
+        /// <summary>
+        /// Creates the playlist.
+        /// </summary>
+        /// <param name="options">The options.</param>
+        /// <returns>Task&lt;Playlist&gt;.</returns>
+        Task<Playlist> CreatePlaylist(PlaylistCreationOptions options);
+
+        /// <summary>
+        /// Adds to playlist.
+        /// </summary>
+        /// <param name="playlistId">The playlist identifier.</param>
+        /// <param name="itemIds">The item ids.</param>
+        /// <returns>Task.</returns>
+        Task AddToPlaylist(string playlistId, IEnumerable<string> itemIds);
+
+        /// <summary>
+        /// Removes from playlist.
+        /// </summary>
+        /// <param name="playlistId">The playlist identifier.</param>
+        /// <param name="indeces">The indeces.</param>
+        /// <returns>Task.</returns>
+        Task RemoveFromPlaylist(string playlistId, IEnumerable<int> indeces);
+
+        /// <summary>
+        /// Gets the playlists folder.
+        /// </summary>
+        /// <param name="userId">The user identifier.</param>
+        /// <returns>Folder.</returns>
+        Folder GetPlaylistsFolder(string userId);
+
+    }
+}

+ 20 - 0
MediaBrowser.Controller/Playlists/Playlist.cs

@@ -0,0 +1,20 @@
+using MediaBrowser.Controller.Entities;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Playlists
+{
+    public class Playlist : Folder
+    {
+        public List<string> ItemIds { get; set; }
+
+        public Playlist()
+        {
+            ItemIds = new List<string>();
+        }
+
+        public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
+        {
+            return base.GetChildren(user, includeLinkedChildren);
+        }
+    }
+}

+ 16 - 0
MediaBrowser.Controller/Playlists/PlaylistCreationOptions.cs

@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Playlists
+{
+    public class PlaylistCreationOptions
+    {
+        public string Name { get; set; }
+
+        public List<string> ItemIdList { get; set; }
+
+        public PlaylistCreationOptions()
+        {
+            ItemIdList = new List<string>();
+        }
+    }
+}

+ 6 - 0
MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj

@@ -131,6 +131,9 @@
     <Compile Include="..\MediaBrowser.Model\Chapters\RemoteChapterResult.cs">
       <Link>Chapters\RemoteChapterResult.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Collections\CollectionCreationResult.cs">
+      <Link>Collections\CollectionCreationResult.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Configuration\BaseApplicationConfiguration.cs">
       <Link>Configuration\BaseApplicationConfiguration.cs</Link>
     </Compile>
@@ -692,6 +695,9 @@
     <Compile Include="..\MediaBrowser.Model\Notifications\SendToUserType.cs">
       <Link>Notifications\SendToUserType.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Playlists\PlaylistCreationResult.cs">
+      <Link>Playlists\PlaylistCreationResult.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Plugins\BasePluginConfiguration.cs">
       <Link>Plugins\BasePluginConfiguration.cs</Link>
     </Compile>

+ 6 - 0
MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj

@@ -94,6 +94,9 @@
     <Compile Include="..\MediaBrowser.Model\Chapters\RemoteChapterResult.cs">
       <Link>Chapters\RemoteChapterResult.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Collections\CollectionCreationResult.cs">
+      <Link>Collections\CollectionCreationResult.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Configuration\BaseApplicationConfiguration.cs">
       <Link>Configuration\BaseApplicationConfiguration.cs</Link>
     </Compile>
@@ -649,6 +652,9 @@
     <Compile Include="..\MediaBrowser.Model\Notifications\SendToUserType.cs">
       <Link>Notifications\SendToUserType.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Playlists\PlaylistCreationResult.cs">
+      <Link>Playlists\PlaylistCreationResult.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Plugins\BasePluginConfiguration.cs">
       <Link>Plugins\BasePluginConfiguration.cs</Link>
     </Compile>

+ 8 - 0
MediaBrowser.Model/Collections/CollectionCreationResult.cs

@@ -0,0 +1,8 @@
+
+namespace MediaBrowser.Model.Collections
+{
+    public class CollectionCreationResult
+    {
+        public string Id { get; set; }
+    }
+}

+ 1 - 0
MediaBrowser.Model/Entities/CollectionType.cs

@@ -23,5 +23,6 @@
         public const string Games = "games";
         public const string Channels = "channels";
         public const string LiveTv = "livetv";
+        public const string Playlists = "playlists";
     }
 }

+ 2 - 0
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -75,6 +75,7 @@
     <Compile Include="Channels\ChannelQuery.cs" />
     <Compile Include="Chapters\RemoteChapterInfo.cs" />
     <Compile Include="Chapters\RemoteChapterResult.cs" />
+    <Compile Include="Collections\CollectionCreationResult.cs" />
     <Compile Include="Configuration\ChannelOptions.cs" />
     <Compile Include="Configuration\ChapterOptions.cs" />
     <Compile Include="Configuration\XbmcMetadataOptions.cs" />
@@ -204,6 +205,7 @@
     <Compile Include="Notifications\NotificationRequest.cs" />
     <Compile Include="Notifications\NotificationServiceInfo.cs" />
     <Compile Include="Notifications\NotificationTypeInfo.cs" />
+    <Compile Include="Playlists\PlaylistCreationResult.cs" />
     <Compile Include="Providers\ExternalIdInfo.cs" />
     <Compile Include="Providers\ExternalUrl.cs" />
     <Compile Include="Providers\ImageProviderInfo.cs" />

+ 8 - 0
MediaBrowser.Model/Playlists/PlaylistCreationResult.cs

@@ -0,0 +1,8 @@
+
+namespace MediaBrowser.Model.Playlists
+{
+    public class PlaylistCreationResult
+    {
+        public string Id { get; set; }
+    }
+}

+ 0 - 1
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -140,7 +140,6 @@
     <Compile Include="Music\FanArtAlbumProvider.cs" />
     <Compile Include="Music\FanArtArtistProvider.cs" />
     <Compile Include="Music\MusicBrainzAlbumProvider.cs" />
-    <Compile Include="Music\SoundtrackPostScanTask.cs" />
     <Compile Include="People\PersonMetadataService.cs" />
     <Compile Include="People\MovieDbPersonProvider.cs" />
     <Compile Include="Photos\ExifReader.cs" />

+ 0 - 32
MediaBrowser.Providers/Music/SoundtrackPostScanTask.cs

@@ -1,32 +0,0 @@
-using MediaBrowser.Controller.Library;
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Providers.Music
-{
-    public class SoundtrackPostScanTask : ILibraryPostScanTask
-    {
-        private readonly ILibraryManager _libraryManager;
-
-        public SoundtrackPostScanTask(ILibraryManager libraryManager)
-        {
-            _libraryManager = libraryManager;
-        }
-
-        private readonly Task _cachedTask = Task.FromResult(true);
-        public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
-        {
-            RunInternal(progress, cancellationToken);
-
-            return _cachedTask;
-        }
-
-        private void RunInternal(IProgress<double> progress, CancellationToken cancellationToken)
-        {
-            // Reimplement this when more kinds of associations are supported.
-
-            progress.Report(100);
-        }
-    }
-}

+ 1 - 1
MediaBrowser.Server.Implementations/Collections/CollectionManager.cs

@@ -37,7 +37,7 @@ namespace MediaBrowser.Server.Implementations.Collections
 
         public Folder GetCollectionsFolder(string userId)
         {
-            return _libraryManager.RootFolder.Children.Concat(_libraryManager.RootFolder).OfType<ManualCollectionsFolder>()
+            return _libraryManager.RootFolder.Children.OfType<ManualCollectionsFolder>()
                 .FirstOrDefault();
         }
 

+ 11 - 4
MediaBrowser.Server.Implementations/Library/UserViewManager.cs

@@ -1,5 +1,4 @@
-using System.IO;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Channels;
@@ -10,16 +9,17 @@ using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.Localization;
+using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Library;
 using MediaBrowser.Model.Querying;
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Server.Implementations.Configuration;
 
 namespace MediaBrowser.Server.Implementations.Library
 {
@@ -33,8 +33,9 @@ namespace MediaBrowser.Server.Implementations.Library
         private readonly IChannelManager _channelManager;
         private readonly ILiveTvManager _liveTvManager;
         private readonly IServerApplicationPaths _appPaths;
+        private readonly IPlaylistManager _playlists;
 
-        public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IFileSystem fileSystem, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IServerApplicationPaths appPaths)
+        public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IFileSystem fileSystem, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IServerApplicationPaths appPaths, IPlaylistManager playlists)
         {
             _libraryManager = libraryManager;
             _localizationManager = localizationManager;
@@ -43,6 +44,7 @@ namespace MediaBrowser.Server.Implementations.Library
             _channelManager = channelManager;
             _liveTvManager = liveTvManager;
             _appPaths = appPaths;
+            _playlists = playlists;
         }
 
         public async Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken)
@@ -94,6 +96,11 @@ namespace MediaBrowser.Server.Implementations.Library
                 list.Add(await GetUserView(CollectionType.BoxSets, user, CollectionType.BoxSets, cancellationToken).ConfigureAwait(false));
             }
 
+            if (recursiveChildren.OfType<Playlist>().Any())
+            {
+                list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N")));
+            }
+
             if (query.IncludeExternalContent)
             {
                 var channelResult = await _channelManager.GetChannels(new ChannelQuery

+ 2 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -221,6 +221,8 @@
     <Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
     <Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
     <Compile Include="Persistence\TypeMapper.cs" />
+    <Compile Include="Playlists\ManualPlaylistsFolder.cs" />
+    <Compile Include="Playlists\PlaylistManager.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
     <Compile Include="ScheduledTasks\ChapterImagesTask.cs" />

+ 62 - 0
MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs

@@ -0,0 +1,62 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Entities;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Server.Implementations.Playlists
+{
+    public class PlaylistsFolder : BasePluginFolder
+    {
+        public PlaylistsFolder()
+        {
+            Name = "Playlists";
+        }
+
+        public override bool IsVisible(User user)
+        {
+            return GetChildren(user, true).Any() &&
+                base.IsVisible(user);
+        }
+
+        public override bool IsHidden
+        {
+            get
+            {
+                return true;
+            }
+        }
+
+        public override bool IsHiddenFromUser(User user)
+        {
+            return false;
+        }
+
+        public override string CollectionType
+        {
+            get { return Model.Entities.CollectionType.Playlists; }
+        }
+    }
+
+    public class PlaylistssDynamicFolder : IVirtualFolderCreator
+    {
+        private readonly IApplicationPaths _appPaths;
+
+        public PlaylistssDynamicFolder(IApplicationPaths appPaths)
+        {
+            _appPaths = appPaths;
+        }
+
+        public BasePluginFolder GetFolder()
+        {
+            var path = Path.Combine(_appPaths.DataPath, "playlists");
+
+            Directory.CreateDirectory(path);
+
+            return new PlaylistsFolder
+            {
+                Path = path
+            };
+        }
+    }
+}
+

+ 137 - 0
MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs

@@ -0,0 +1,137 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Playlists;
+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;
+
+namespace MediaBrowser.Server.Implementations.Playlists
+{
+    public class PlaylistManager : IPlaylistManager
+    {
+        private readonly ILibraryManager _libraryManager;
+        private readonly IFileSystem _fileSystem;
+        private readonly ILibraryMonitor _iLibraryMonitor;
+        private readonly ILogger _logger;
+        private readonly IUserManager _userManager;
+
+        public PlaylistManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor, ILogger logger, IUserManager userManager)
+        {
+            _libraryManager = libraryManager;
+            _fileSystem = fileSystem;
+            _iLibraryMonitor = iLibraryMonitor;
+            _logger = logger;
+            _userManager = userManager;
+        }
+
+        public IEnumerable<Playlist> GetPlaylists(string userId)
+        {
+            var user = _userManager.GetUserById(new Guid(userId));
+
+            return GetPlaylistsFolder(userId).GetChildren(user, true).OfType<Playlist>();
+        }
+
+        public async Task<Playlist> CreatePlaylist(PlaylistCreationOptions 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) + " [playlist]";
+
+            var parentFolder = GetPlaylistsFolder(null);
+
+            if (parentFolder == null)
+            {
+                throw new ArgumentException();
+            }
+
+            var path = Path.Combine(parentFolder.Path, folderName);
+
+            _iLibraryMonitor.ReportFileSystemChangeBeginning(path);
+
+            try
+            {
+                Directory.CreateDirectory(path);
+
+                var collection = new Playlist
+                {
+                    Name = name,
+                    Parent = parentFolder,
+                    Path = path
+                };
+
+                await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false);
+
+                await collection.RefreshMetadata(new MetadataRefreshOptions(), CancellationToken.None)
+                    .ConfigureAwait(false);
+
+                if (options.ItemIdList.Count > 0)
+                {
+                    await AddToPlaylist(collection.Id.ToString("N"), options.ItemIdList);
+                }
+
+                return collection;
+            }
+            finally
+            {
+                // Refresh handled internally
+                _iLibraryMonitor.ReportFileSystemChangeComplete(path, false);
+            }
+        }
+
+        public async Task AddToPlaylist(string playlistId, IEnumerable<string> itemIds)
+        {
+            var collection = _libraryManager.GetItemById(playlistId) as Playlist;
+
+            if (collection == null)
+            {
+                throw new ArgumentException("No Playlist exists with the supplied Id");
+            }
+
+            var list = new List<LinkedChild>();
+            var itemList = new List<BaseItem>();
+
+            foreach (var itemId in itemIds)
+            {
+                var item = _libraryManager.GetItemById(itemId);
+
+                if (item == null)
+                {
+                    throw new ArgumentException("No item exists with the supplied Id");
+                }
+
+                itemList.Add(item);
+
+                list.Add(new LinkedChild
+                {
+                    Type = LinkedChildType.Manual,
+                    ItemId = item.Id
+                });
+            }
+
+            collection.LinkedChildren.AddRange(list);
+
+            await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+            await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
+        }
+
+        public Task RemoveFromPlaylist(string playlistId, IEnumerable<int> indeces)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Folder GetPlaylistsFolder(string userId)
+        {
+            return _libraryManager.RootFolder.Children.OfType<PlaylistsFolder>()
+                .FirstOrDefault();
+        }
+    }
+}

+ 6 - 1
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -26,6 +26,7 @@ using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.News;
 using MediaBrowser.Controller.Notifications;
 using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Resolvers;
@@ -68,6 +69,7 @@ using MediaBrowser.Server.Implementations.Localization;
 using MediaBrowser.Server.Implementations.MediaEncoder;
 using MediaBrowser.Server.Implementations.Notifications;
 using MediaBrowser.Server.Implementations.Persistence;
+using MediaBrowser.Server.Implementations.Playlists;
 using MediaBrowser.Server.Implementations.Security;
 using MediaBrowser.Server.Implementations.ServerManager;
 using MediaBrowser.Server.Implementations.Session;
@@ -612,10 +614,13 @@ namespace MediaBrowser.ServerApplication
             var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"));
             RegisterSingleInstance<ICollectionManager>(collectionManager);
 
+            var playlistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager);
+            RegisterSingleInstance<IPlaylistManager>(playlistManager);
+
             LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager);
             RegisterSingleInstance(LiveTvManager);
 
-            UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, FileSystemManager, UserManager, ChannelManager, LiveTvManager, ApplicationPaths);
+            UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, FileSystemManager, UserManager, ChannelManager, LiveTvManager, ApplicationPaths, playlistManager);
             RegisterSingleInstance(UserViewManager);
 
             var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, UserViewManager, ChannelManager);