2
0
Эх сурвалжийг харах

support adding additional users to sessions

Luke Pulverenti 11 жил өмнө
parent
commit
135168b0e0

+ 33 - 1
MediaBrowser.Api/SessionsService.cs

@@ -172,6 +172,28 @@ namespace MediaBrowser.Api
         public long? TimeoutMs { get; set; }
     }
 
+    [Route("/Sessions/{Id}/Users/{UserId}", "POST")]
+    [Api(("Adds an additional user to a session"))]
+    public class AddUserToSession : IReturnVoid
+    {
+        [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+        public Guid Id { get; set; }
+
+        [ApiMember(Name = "UserId", Description = "UserId Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+        public Guid UserId { get; set; }
+    }
+
+    [Route("/Sessions/{Id}/Users/{UserId}", "DELETE")]
+    [Api(("Removes an additional user from a session"))]
+    public class RemoveUserFromSession : IReturnVoid
+    {
+        [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+        public Guid Id { get; set; }
+
+        [ApiMember(Name = "UserId", Description = "UserId Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+        public Guid UserId { get; set; }
+    }
+
     /// <summary>
     /// Class SessionsService
     /// </summary>
@@ -217,7 +239,7 @@ namespace MediaBrowser.Api
 
                 if (!user.Configuration.EnableRemoteControlOfOtherUsers)
                 {
-                    result = result.Where(i => i.User == null || i.User.Id == request.ControllableByUserId.Value);
+                    result = result.Where(i => !i.UserId.HasValue || i.UserId.Value == request.ControllableByUserId.Value);
                 }
             }
 
@@ -303,5 +325,15 @@ namespace MediaBrowser.Api
 
             Task.WaitAll(task);
         }
+
+        public void Post(AddUserToSession request)
+        {
+            _sessionManager.AddAdditionalUser(request.Id, request.UserId);
+        }
+
+        public void Delete(RemoveUserFromSession request)
+        {
+            _sessionManager.RemoveAdditionalUser(request.Id, request.UserId);
+        }
     }
 }

+ 3 - 0
MediaBrowser.Controller/Entities/TV/Series.cs

@@ -45,6 +45,9 @@ namespace MediaBrowser.Controller.Entities.TV
         
         public List<MediaUrl> RemoteTrailers { get; set; }
 
+        /// <summary>
+        /// airdate, dvd or absolute
+        /// </summary>
         public string DisplayOrder { get; set; }
         
         /// <summary>

+ 9 - 4
MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs

@@ -1,5 +1,6 @@
-using System;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
+using System;
+using System.Collections.Generic;
 
 namespace MediaBrowser.Controller.Library
 {
@@ -8,10 +9,14 @@ namespace MediaBrowser.Controller.Library
     /// </summary>
     public class PlaybackProgressEventArgs : EventArgs
     {
-        public User User { get; set; }
+        public List<User> Users { get; set; }
         public long? PlaybackPositionTicks { get; set; }
         public BaseItem Item { get; set; }
-        public UserItemData UserData { get; set; }
+
+        public PlaybackProgressEventArgs()
+        {
+            Users = new List<User>();
+        }
     }
 
     public class PlaybackStopEventArgs : PlaybackProgressEventArgs

+ 14 - 0
MediaBrowser.Controller/Session/ISessionManager.cs

@@ -141,5 +141,19 @@ namespace MediaBrowser.Controller.Session
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         Task SendServerRestartNotification(CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Adds the additional user.
+        /// </summary>
+        /// <param name="sessionId">The session identifier.</param>
+        /// <param name="userId">The user identifier.</param>
+        void AddAdditionalUser(Guid sessionId, Guid userId);
+
+        /// <summary>
+        /// Removes the additional user.
+        /// </summary>
+        /// <param name="sessionId">The session identifier.</param>
+        /// <param name="userId">The user identifier.</param>
+        void RemoveAdditionalUser(Guid sessionId, Guid userId);
     }
 }

+ 13 - 2
MediaBrowser.Controller/Session/SessionInfo.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Session;
 using System;
 using System.Collections.Generic;
 
@@ -12,8 +13,12 @@ namespace MediaBrowser.Controller.Session
         public SessionInfo()
         {
             QueueableMediaTypes = new List<string>();
+
+            AdditionalUsersPresent = new List<SessionUserInfo>();
         }
 
+        public List<SessionUserInfo> AdditionalUsersPresent { get; set; }
+        
         /// <summary>
         /// Gets or sets the remote end point.
         /// </summary>
@@ -31,7 +36,7 @@ namespace MediaBrowser.Controller.Session
         /// </summary>
         /// <value>The queueable media types.</value>
         public List<string> QueueableMediaTypes { get; set; }
-
+        
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
@@ -42,7 +47,13 @@ namespace MediaBrowser.Controller.Session
         /// Gets or sets the user id.
         /// </summary>
         /// <value>The user id.</value>
-        public User User { get; set; }
+        public Guid? UserId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the username.
+        /// </summary>
+        /// <value>The username.</value>
+        public string UserName { get; set; }
 
         /// <summary>
         /// Gets or sets the type of the client.

+ 6 - 0
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -392,6 +392,12 @@ namespace MediaBrowser.Model.Dto
         /// <value>The album.</value>
         public string Album { get; set; }
 
+        /// <summary>
+        /// Gets or sets the type of the collection.
+        /// </summary>
+        /// <value>The type of the collection.</value>
+        public string CollectionType { get; set; }
+        
         /// <summary>
         /// Gets or sets the display order.
         /// </summary>

+ 28 - 0
MediaBrowser.Model/Session/SessionInfoDto.cs

@@ -43,6 +43,12 @@ namespace MediaBrowser.Model.Session
         /// <value>The name of the user.</value>
         public string UserName { get; set; }
 
+        /// <summary>
+        /// Gets or sets the additional users present.
+        /// </summary>
+        /// <value>The additional users present.</value>
+        public List<SessionUserInfo> AdditionalUsersPresent { get; set; }
+
         /// <summary>
         /// Gets or sets the application version.
         /// </summary>
@@ -128,5 +134,27 @@ namespace MediaBrowser.Model.Session
         public bool SupportsRemoteControl { get; set; }
 
         public event PropertyChangedEventHandler PropertyChanged;
+
+        public SessionInfoDto()
+        {
+            AdditionalUsersPresent = new List<SessionUserInfo>();
+        }
+    }
+
+    /// <summary>
+    /// Class SessionUserInfo.
+    /// </summary>
+    public class SessionUserInfo
+    {
+        /// <summary>
+        /// Gets or sets the user identifier.
+        /// </summary>
+        /// <value>The user identifier.</value>
+        public string UserId { get; set; }
+        /// <summary>
+        /// Gets or sets the name of the user.
+        /// </summary>
+        /// <value>The name of the user.</value>
+        public string UserName { get; set; }
     }
 }

+ 11 - 4
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -244,7 +244,8 @@ namespace MediaBrowser.Server.Implementations.Dto
                 ApplicationVersion = session.ApplicationVersion,
                 CanSeek = session.CanSeek,
                 QueueableMediaTypes = session.QueueableMediaTypes,
-                RemoteEndPoint = session.RemoteEndPoint
+                RemoteEndPoint = session.RemoteEndPoint,
+                AdditionalUsersPresent = session.AdditionalUsersPresent
             };
 
             if (session.NowPlayingItem != null)
@@ -252,11 +253,11 @@ namespace MediaBrowser.Server.Implementations.Dto
                 dto.NowPlayingItem = GetBaseItemInfo(session.NowPlayingItem);
             }
 
-            if (session.User != null)
+            if (session.UserId.HasValue)
             {
-                dto.UserId = session.User.Id.ToString("N");
-                dto.UserName = session.User.Name;
+                dto.UserId = session.UserId.Value.ToString("N");
             }
+            dto.UserName = session.UserName;
 
             return dto;
         }
@@ -769,6 +770,12 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
                 dto.DisplayOrder = hasDisplayOrder.DisplayOrder;
             }
+
+            var collectionFolder = item as CollectionFolder;
+            if (collectionFolder != null)
+            {
+                dto.CollectionType = collectionFolder.CollectionType;
+            }
             
             if (fields.Contains(ItemFields.RemoteTrailers))
             {

+ 1 - 1
MediaBrowser.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs

@@ -190,7 +190,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             {
                 var id = user.Id;
                 var userSessions = _sessionManager.Sessions
-                    .Where(u => u.User != null && u.User.Id == id && u.SessionController != null && u.IsActive)
+                    .Where(u => u.UserId.HasValue && u.UserId.Value == id && u.SessionController != null && u.IsActive)
                     .ToList();
 
                 if (userSessions.Count > 0)

+ 1 - 1
MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs

@@ -94,7 +94,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             {
                 var userId = pair.Key;
                 var userSessions = _sessionManager.Sessions
-                    .Where(u => u.User != null && u.User.Id == userId && u.SessionController != null && u.IsActive)
+                    .Where(u => u.UserId.HasValue && u.UserId.Value == userId && u.SessionController != null && u.IsActive)
                     .ToList();
 
                 if (userSessions.Count > 0)

+ 190 - 46
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -39,6 +39,7 @@ namespace MediaBrowser.Server.Implementations.Session
         private readonly ILogger _logger;
 
         private readonly ILibraryManager _libraryManager;
+        private readonly IUserManager _userManager;
 
         /// <summary>
         /// Gets or sets the configuration manager.
@@ -75,13 +76,14 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <param name="logger">The logger.</param>
         /// <param name="userRepository">The user repository.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager)
+        public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager)
         {
             _userDataRepository = userDataRepository;
             _configurationManager = configurationManager;
             _logger = logger;
             _userRepository = userRepository;
             _libraryManager = libraryManager;
+            _userManager = userManager;
         }
 
         /// <summary>
@@ -140,7 +142,10 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var activityDate = DateTime.UtcNow;
 
-            var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, remoteEndPoint, user);
+            var userId = user == null ? (Guid?)null : user.Id;
+            var username = user == null ? null : user.Name;
+
+            var session = GetSessionInfo(clientType, appVersion, deviceId, deviceName, remoteEndPoint, userId, username);
 
             session.LastActivityDate = activityDate;
 
@@ -209,9 +214,10 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <param name="deviceId">The device id.</param>
         /// <param name="deviceName">Name of the device.</param>
         /// <param name="remoteEndPoint">The remote end point.</param>
-        /// <param name="user">The user.</param>
+        /// <param name="userId">The user identifier.</param>
+        /// <param name="username">The username.</param>
         /// <returns>SessionInfo.</returns>
-        private SessionInfo GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
+        private SessionInfo GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Guid? userId, string username)
         {
             var key = clientType + deviceId + appVersion;
 
@@ -224,9 +230,15 @@ namespace MediaBrowser.Server.Implementations.Session
             });
 
             connection.DeviceName = deviceName;
-            connection.User = user;
+            connection.UserId = userId;
+            connection.UserName = username;
             connection.RemoteEndPoint = remoteEndPoint;
 
+            if (!userId.HasValue)
+            {
+                connection.AdditionalUsersPresent.Clear();
+            }
+
             if (connection.SessionController == null)
             {
                 connection.SessionController = _sessionFactories
@@ -237,6 +249,31 @@ namespace MediaBrowser.Server.Implementations.Session
             return connection;
         }
 
+        private List<User> GetUsers(SessionInfo session)
+        {
+            var users = new List<User>();
+
+            if (session.UserId.HasValue)
+            {
+                var user = _userManager.GetUserById(session.UserId.Value);
+
+                if (user == null)
+                {
+                    throw new InvalidOperationException("User not found");
+                }
+
+                users.Add(user);
+
+                var additionalUsers = session.AdditionalUsersPresent
+                    .Select(i => _userManager.GetUserById(new Guid(i.UserId)))
+                    .Where(i => i != null);
+
+                users.AddRange(additionalUsers);
+            }
+
+            return users;
+        }
+
         /// <summary>
         /// Used to report that playback has started for an item
         /// </summary>
@@ -265,31 +302,45 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var key = item.GetUserDataKey();
 
-            var user = session.User;
-
-            var data = _userDataRepository.GetUserData(user.Id, key);
-
-            data.PlayCount++;
-            data.LastPlayedDate = DateTime.UtcNow;
+            var users = GetUsers(session);
 
-            if (!(item is Video))
+            foreach (var user in users)
             {
-                data.Played = true;
+                await OnPlaybackStart(user.Id, key, item).ConfigureAwait(false);
             }
 
-            await _userDataRepository.SaveUserData(user.Id, info.Item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
-
             // Nothing to save here
             // Fire events to inform plugins
             EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs
             {
                 Item = item,
-                User = user,
-                UserData = data
+                Users = users
 
             }, _logger);
         }
 
+        /// <summary>
+        /// Called when [playback start].
+        /// </summary>
+        /// <param name="userId">The user identifier.</param>
+        /// <param name="userDataKey">The user data key.</param>
+        /// <param name="item">The item.</param>
+        /// <returns>Task.</returns>
+        private async Task OnPlaybackStart(Guid userId, string userDataKey, IHasUserData item)
+        {
+            var data = _userDataRepository.GetUserData(userId, userDataKey);
+
+            data.PlayCount++;
+            data.LastPlayedDate = DateTime.UtcNow;
+
+            if (!(item is Video))
+            {
+                data.Played = true;
+            }
+
+            await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
+        }
+
         /// <summary>
         /// Used to report playback progress for an item
         /// </summary>
@@ -315,27 +366,34 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var key = info.Item.GetUserDataKey();
 
-            var user = session.User;
+            var users = GetUsers(session);
 
-            var data = _userDataRepository.GetUserData(user.Id, key);
-
-            if (info.PositionTicks.HasValue)
+            foreach (var user in users)
             {
-                UpdatePlayState(info.Item, data, info.PositionTicks.Value);
-
-                await _userDataRepository.SaveUserData(user.Id, info.Item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false);
+                await OnPlaybackProgress(user.Id, key, info.Item, info.PositionTicks).ConfigureAwait(false);
             }
 
             EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs
             {
                 Item = info.Item,
-                User = user,
-                PlaybackPositionTicks = info.PositionTicks,
-                UserData = data
+                Users = users,
+                PlaybackPositionTicks = info.PositionTicks
 
             }, _logger);
         }
 
+        private async Task OnPlaybackProgress(Guid userId, string userDataKey, BaseItem item, long? positionTicks)
+        {
+            var data = _userDataRepository.GetUserData(userId, userDataKey);
+
+            if (positionTicks.HasValue)
+            {
+                UpdatePlayState(item, data, positionTicks.Value);
+
+                await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false);
+            }
+        }
+
         /// <summary>
         /// Used to report that playback has ended for an item
         /// </summary>
@@ -371,14 +429,32 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var key = info.Item.GetUserDataKey();
 
-            var user = session.User;
+            var users = GetUsers(session);
+
+            var playedToCompletion = false;
+            foreach (var user in users)
+            {
+                playedToCompletion = await OnPlaybackStopped(user.Id, key, info.Item, info.PositionTicks).ConfigureAwait(false);
+            }
+
+            EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackStopEventArgs
+            {
+                Item = info.Item,
+                Users = users,
+                PlaybackPositionTicks = info.PositionTicks,
+                PlayedToCompletion = playedToCompletion
+
+            }, _logger);
+        }
 
-            var data = _userDataRepository.GetUserData(user.Id, key);
+        private async Task<bool> OnPlaybackStopped(Guid userId, string userDataKey, BaseItem item, long? positionTicks)
+        {
+            var data = _userDataRepository.GetUserData(userId, userDataKey);
             bool playedToCompletion;
 
-            if (info.PositionTicks.HasValue)
+            if (positionTicks.HasValue)
             {
-                playedToCompletion = UpdatePlayState(info.Item, data, info.PositionTicks.Value);
+                playedToCompletion = UpdatePlayState(item, data, positionTicks.Value);
             }
             else
             {
@@ -389,19 +465,11 @@ namespace MediaBrowser.Server.Implementations.Session
                 playedToCompletion = true;
             }
 
-            await _userDataRepository.SaveUserData(user.Id, info.Item, data, UserDataSaveReason.PlaybackFinished, CancellationToken.None).ConfigureAwait(false);
-
-            EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackStopEventArgs
-            {
-                Item = info.Item,
-                User = user,
-                PlaybackPositionTicks = info.PositionTicks,
-                UserData = data,
-                PlayedToCompletion = playedToCompletion
+            await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackFinished, CancellationToken.None).ConfigureAwait(false);
 
-            }, _logger);
+            return playedToCompletion;
         }
-
+        
         /// <summary>
         /// Updates playstate position for an item but does not save
         /// </summary>
@@ -462,12 +530,12 @@ namespace MediaBrowser.Server.Implementations.Session
         }
 
         /// <summary>
-        /// Gets the session for remote control.
+        /// Gets the session.
         /// </summary>
-        /// <param name="sessionId">The session id.</param>
+        /// <param name="sessionId">The session identifier.</param>
         /// <returns>SessionInfo.</returns>
         /// <exception cref="ResourceNotFoundException"></exception>
-        private SessionInfo GetSessionForRemoteControl(Guid sessionId)
+        private SessionInfo GetSession(Guid sessionId)
         {
             var session = Sessions.First(i => i.Id.Equals(sessionId));
 
@@ -476,6 +544,19 @@ namespace MediaBrowser.Server.Implementations.Session
                 throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId));
             }
 
+            return session;
+        }
+
+        /// <summary>
+        /// Gets the session for remote control.
+        /// </summary>
+        /// <param name="sessionId">The session id.</param>
+        /// <returns>SessionInfo.</returns>
+        /// <exception cref="ResourceNotFoundException"></exception>
+        private SessionInfo GetSessionForRemoteControl(Guid sessionId)
+        {
+            var session = GetSession(sessionId);
+
             if (!session.SupportsRemoteControl)
             {
                 throw new ArgumentException(string.Format("Session {0} does not support remote control.", session.Id));
@@ -595,7 +676,7 @@ namespace MediaBrowser.Server.Implementations.Session
                     _logger.ErrorException("Error in SendRestartRequiredNotification.", ex);
                 }
 
-            }));
+            }, cancellationToken));
 
             return Task.WhenAll(tasks);
         }
@@ -649,5 +730,68 @@ namespace MediaBrowser.Server.Implementations.Session
 
             return Task.WhenAll(tasks);
         }
+
+
+        /// <summary>
+        /// Adds the additional user.
+        /// </summary>
+        /// <param name="sessionId">The session identifier.</param>
+        /// <param name="userId">The user identifier.</param>
+        /// <exception cref="System.UnauthorizedAccessException">Cannot modify additional users without authenticating first.</exception>
+        /// <exception cref="System.ArgumentException">The requested user is already the primary user of the session.</exception>
+        public void AddAdditionalUser(Guid sessionId, Guid userId)
+        {
+            var session = GetSession(sessionId);
+
+            if (!session.UserId.HasValue)
+            {
+                throw new UnauthorizedAccessException("Cannot modify additional users without authenticating first.");
+            }
+
+            if (session.UserId.Value == userId)
+            {
+                throw new ArgumentException("The requested user is already the primary user of the session.");
+            }
+
+            if (session.AdditionalUsersPresent.All(i => new Guid(i.UserId) != userId))
+            {
+                var user = _userManager.GetUserById(userId);
+
+                session.AdditionalUsersPresent.Add(new SessionUserInfo
+                {
+                    UserId = userId.ToString("N"),
+                    UserName = user.Name
+                });
+            }
+        }
+
+        /// <summary>
+        /// Removes the additional user.
+        /// </summary>
+        /// <param name="sessionId">The session identifier.</param>
+        /// <param name="userId">The user identifier.</param>
+        /// <exception cref="System.UnauthorizedAccessException">Cannot modify additional users without authenticating first.</exception>
+        /// <exception cref="System.ArgumentException">The requested user is already the primary user of the session.</exception>
+        public void RemoveAdditionalUser(Guid sessionId, Guid userId)
+        {
+            var session = GetSession(sessionId);
+
+            if (!session.UserId.HasValue)
+            {
+                throw new UnauthorizedAccessException("Cannot modify additional users without authenticating first.");
+            }
+
+            if (session.UserId.Value == userId)
+            {
+                throw new ArgumentException("The requested user is already the primary user of the session.");
+            }
+
+            var user = session.AdditionalUsersPresent.FirstOrDefault(i => new Guid(i.UserId) == userId);
+
+            if (user != null)
+            {
+                session.AdditionalUsersPresent.Remove(user);
+            }
+        }
     }
 }

+ 3 - 3
MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs

@@ -191,7 +191,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var session = GetSessionFromMessage(message);
 
-            if (session != null && session.User != null)
+            if (session != null && session.UserId.HasValue)
             {
                 var vals = message.Data.Split('|');
 
@@ -229,7 +229,7 @@ namespace MediaBrowser.Server.Implementations.Session
         {
             var session = GetSessionFromMessage(message);
 
-            if (session != null && session.User != null)
+            if (session != null && session.UserId.HasValue)
             {
                 var vals = message.Data.Split('|');
 
@@ -273,7 +273,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var session = GetSessionFromMessage(message);
 
-            if (session != null && session.User != null)
+            if (session != null && session.UserId.HasValue)
             {
                 var vals = message.Data.Split('|');
 

+ 1 - 1
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -254,7 +254,7 @@ namespace MediaBrowser.ServerApplication
 
             RegisterSingleInstance<ILibrarySearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager));
 
-            SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager);
+            SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager);
             RegisterSingleInstance(SessionManager);
 
             HttpServer = ServerFactory.CreateServer(this, LogManager, "Media Browser", "mediabrowser", "dashboard/index.html");

+ 3 - 3
MediaBrowser.WebDashboard/ApiClient.js

@@ -2,7 +2,7 @@
     window.MediaBrowser = {};
 }
 
-MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, window) {
+MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, window, FileReader) {
 
     /**
      * Creates a new api client instance
@@ -3982,7 +3982,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
 
     };
 
-}(jQuery, navigator, window.JSON, window.WebSocket, setTimeout, window);
+}(jQuery, navigator, window.JSON, window.WebSocket, setTimeout, window, window.FileReader);
 
 /**
  * Provides a friendly way to create an api client instance using information from the browser's current url
@@ -4208,7 +4208,7 @@ MediaBrowser.SHA1 = function (msg) {
     }
 
     if (matched.platform) {
-        browser[matched.platform] = true
+        browser[matched.platform] = true;
     }
 
     // Chrome is Webkit, but Webkit is also Safari.

+ 1 - 1
MediaBrowser.WebDashboard/packages.config

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.217" targetFramework="net45" />
+  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.218" targetFramework="net45" />
 </packages>