diff --git a/Jellyfin.Api/Controllers/SessionController.cs b/Jellyfin.Api/Controllers/SessionController.cs
new file mode 100644
index 0000000000..5b60275eb6
--- /dev/null
+++ b/Jellyfin.Api/Controllers/SessionController.cs
@@ -0,0 +1,478 @@
+#pragma warning disable CA1801
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading;
+using Jellyfin.Api.Helpers;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Session;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Jellyfin.Api.Controllers
+{
+ ///
+ /// The session controller.
+ ///
+ public class SessionController : BaseJellyfinApiController
+ {
+ private readonly ISessionManager _sessionManager;
+ private readonly IUserManager _userManager;
+ private readonly IAuthorizationContext _authContext;
+ private readonly IDeviceManager _deviceManager;
+ private readonly ISessionContext _sessionContext;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of interface.
+ /// Instance of interface.
+ /// Instance of interface.
+ /// Instance of interface.
+ /// Instance of interface.
+ public SessionController(
+ ISessionManager sessionManager,
+ IUserManager userManager,
+ IAuthorizationContext authContext,
+ IDeviceManager deviceManager,
+ ISessionContext sessionContext)
+ {
+ _sessionManager = sessionManager;
+ _userManager = userManager;
+ _authContext = authContext;
+ _deviceManager = deviceManager;
+ _sessionContext = sessionContext;
+ }
+
+ ///
+ /// Gets a list of sessions.
+ ///
+ /// Filter by sessions that a given user is allowed to remote control.
+ /// Filter by device Id.
+ /// Optional. Filter by sessions that were active in the last n seconds.
+ /// List of sessions returned.
+ /// An with the available sessions.
+ [HttpGet("/Sessions")]
+ [Authorize]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult> GetSessions(
+ [FromQuery] Guid controllableByUserId,
+ [FromQuery] string deviceId,
+ [FromQuery] int? activeWithinSeconds)
+ {
+ var result = _sessionManager.Sessions;
+
+ if (!string.IsNullOrEmpty(deviceId))
+ {
+ result = result.Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase));
+ }
+
+ if (!controllableByUserId.Equals(Guid.Empty))
+ {
+ result = result.Where(i => i.SupportsRemoteControl);
+
+ var user = _userManager.GetUserById(controllableByUserId);
+
+ if (!user.Policy.EnableRemoteControlOfOtherUsers)
+ {
+ result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(controllableByUserId));
+ }
+
+ if (!user.Policy.EnableSharedDeviceControl)
+ {
+ result = result.Where(i => !i.UserId.Equals(Guid.Empty));
+ }
+
+ if (activeWithinSeconds.HasValue && activeWithinSeconds.Value > 0)
+ {
+ var minActiveDate = DateTime.UtcNow.AddSeconds(0 - activeWithinSeconds.Value);
+ result = result.Where(i => i.LastActivityDate >= minActiveDate);
+ }
+
+ result = result.Where(i =>
+ {
+ if (!string.IsNullOrWhiteSpace(i.DeviceId))
+ {
+ if (!_deviceManager.CanAccessDevice(user, i.DeviceId))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ });
+ }
+
+ return Ok(result);
+ }
+
+ ///
+ /// Instructs a session to browse to an item or view.
+ ///
+ /// The session Id.
+ /// The type of item to browse to.
+ /// The Id of the item.
+ /// The name of the item.
+ /// Instruction sent to session.
+ /// A .
+ [HttpPost("/Sessions/{id}/Viewing")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult DisplayContent(
+ [FromRoute] string id,
+ [FromQuery] string itemType,
+ [FromQuery] string itemId,
+ [FromQuery] string itemName)
+ {
+ var command = new BrowseRequest
+ {
+ ItemId = itemId,
+ ItemName = itemName,
+ ItemType = itemType
+ };
+
+ _sessionManager.SendBrowseCommand(
+ RequestHelpers.GetSession(_sessionContext).Id,
+ id,
+ command,
+ CancellationToken.None);
+
+ return NoContent();
+ }
+
+ ///
+ /// Instructs a session to play an item.
+ ///
+ /// The session id.
+ /// The ids of the items to play, comma delimited.
+ /// The starting position of the first item.
+ /// The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now.
+ /// The .
+ /// Instruction sent to session.
+ /// A .
+ [HttpPost("/Sessions/{id}/Playing")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult Play(
+ [FromRoute] string id,
+ [FromQuery] Guid[] itemIds,
+ [FromQuery] long? startPositionTicks,
+ [FromQuery] PlayCommand playCommand,
+ [FromBody, Required] PlayRequest playRequest)
+ {
+ if (playRequest == null)
+ {
+ throw new ArgumentException("Request Body may not be null");
+ }
+
+ playRequest.ItemIds = itemIds;
+ playRequest.StartPositionTicks = startPositionTicks;
+ playRequest.PlayCommand = playCommand;
+
+ _sessionManager.SendPlayCommand(
+ RequestHelpers.GetSession(_sessionContext).Id,
+ id,
+ playRequest,
+ CancellationToken.None);
+
+ return NoContent();
+ }
+
+ ///
+ /// Issues a playstate command to a client.
+ ///
+ /// The session id.
+ /// The .
+ /// Playstate command sent to session.
+ /// A .
+ [HttpPost("/Sessions/{id}/Playing/{command}")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult SendPlaystateCommand(
+ [FromRoute] string id,
+ [FromBody] PlaystateRequest playstateRequest)
+ {
+ _sessionManager.SendPlaystateCommand(
+ RequestHelpers.GetSession(_sessionContext).Id,
+ id,
+ playstateRequest,
+ CancellationToken.None);
+
+ return NoContent();
+ }
+
+ ///
+ /// Issues a system command to a client.
+ ///
+ /// The session id.
+ /// The command to send.
+ /// System command sent to session.
+ /// A .
+ [HttpPost("/Sessions/{id}/System/{Command}")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult SendSystemCommand(
+ [FromRoute] string id,
+ [FromRoute] string command)
+ {
+ var name = command;
+ if (Enum.TryParse(name, true, out GeneralCommandType commandType))
+ {
+ name = commandType.ToString();
+ }
+
+ var currentSession = RequestHelpers.GetSession(_sessionContext);
+ var generalCommand = new GeneralCommand
+ {
+ Name = name,
+ ControllingUserId = currentSession.UserId
+ };
+
+ _sessionManager.SendGeneralCommand(currentSession.Id, id, generalCommand, CancellationToken.None);
+
+ return NoContent();
+ }
+
+ ///
+ /// Issues a general command to a client.
+ ///
+ /// The session id.
+ /// The command to send.
+ /// General command sent to session.
+ /// A .
+ [HttpPost("/Sessions/{id}/Command/{Command}")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult SendGeneralCommand(
+ [FromRoute] string id,
+ [FromRoute] string command)
+ {
+ var currentSession = RequestHelpers.GetSession(_sessionContext);
+
+ var generalCommand = new GeneralCommand
+ {
+ Name = command,
+ ControllingUserId = currentSession.UserId
+ };
+
+ _sessionManager.SendGeneralCommand(currentSession.Id, id, generalCommand, CancellationToken.None);
+
+ return NoContent();
+ }
+
+ ///
+ /// Issues a full general command to a client.
+ ///
+ /// The session id.
+ /// The .
+ /// Full general command sent to session.
+ /// A .
+ [HttpPost("/Sessions/{id}/Command")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult SendFullGeneralCommand(
+ [FromRoute] string id,
+ [FromBody, Required] GeneralCommand command)
+ {
+ var currentSession = RequestHelpers.GetSession(_sessionContext);
+
+ if (command == null)
+ {
+ throw new ArgumentException("Request body may not be null");
+ }
+
+ command.ControllingUserId = currentSession.UserId;
+
+ _sessionManager.SendGeneralCommand(
+ currentSession.Id,
+ id,
+ command,
+ CancellationToken.None);
+
+ return NoContent();
+ }
+
+ ///
+ /// Issues a command to a client to display a message to the user.
+ ///
+ /// The session id.
+ /// The message test.
+ /// The message header.
+ /// The message timeout. If omitted the user will have to confirm viewing the message.
+ /// Message sent.
+ /// A .
+ [HttpPost("/Sessions/{id}/Message")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult SendMessageCommand(
+ [FromRoute] string id,
+ [FromQuery] string text,
+ [FromQuery] string header,
+ [FromQuery] long? timeoutMs)
+ {
+ var command = new MessageCommand
+ {
+ Header = string.IsNullOrEmpty(header) ? "Message from Server" : header,
+ TimeoutMs = timeoutMs,
+ Text = text
+ };
+
+ _sessionManager.SendMessageCommand(RequestHelpers.GetSession(_sessionContext).Id, id, command, CancellationToken.None);
+
+ return NoContent();
+ }
+
+ ///
+ /// Adds an additional user to a session.
+ ///
+ /// The session id.
+ /// The user id.
+ /// User added to session.
+ /// A .
+ [HttpPost("/Sessions/{id}/User/{userId}")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult AddUserToSession(
+ [FromRoute] string id,
+ [FromRoute] Guid userId)
+ {
+ _sessionManager.AddAdditionalUser(id, userId);
+ return NoContent();
+ }
+
+ ///
+ /// Removes an additional user from a session.
+ ///
+ /// The session id.
+ /// The user id.
+ /// User removed from session.
+ /// A .
+ [HttpDelete("/Sessions/{id}/User/{userId}")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult RemoveUserFromSession(
+ [FromRoute] string id,
+ [FromRoute] Guid userId)
+ {
+ _sessionManager.RemoveAdditionalUser(id, userId);
+ return NoContent();
+ }
+
+ ///
+ /// Updates capabilities for a device.
+ ///
+ /// The session id.
+ /// A list of playable media types, comma delimited. Audio, Video, Book, Photo.
+ /// A list of supported remote control commands, comma delimited.
+ /// Determines whether media can be played remotely..
+ /// Determines whether sync is supported.
+ /// Determines whether the device supports a unique identifier.
+ /// Capabilities posted.
+ /// A .
+ [HttpPost("/Sessions/Capabilities")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult PostCapabilities(
+ [FromQuery] string id,
+ [FromQuery] string playableMediaTypes,
+ [FromQuery] string supportedCommands,
+ [FromQuery] bool supportsMediaControl,
+ [FromQuery] bool supportsSync,
+ [FromQuery] bool supportsPersistentIdentifier = true)
+ {
+ if (string.IsNullOrWhiteSpace(id))
+ {
+ id = RequestHelpers.GetSession(_sessionContext).Id;
+ }
+
+ _sessionManager.ReportCapabilities(id, new ClientCapabilities
+ {
+ PlayableMediaTypes = RequestHelpers.Split(playableMediaTypes, ',', true),
+ SupportedCommands = RequestHelpers.Split(supportedCommands, ',', true),
+ SupportsMediaControl = supportsMediaControl,
+ SupportsSync = supportsSync,
+ SupportsPersistentIdentifier = supportsPersistentIdentifier
+ });
+ return NoContent();
+ }
+
+ ///
+ /// Updates capabilities for a device.
+ ///
+ /// The session id.
+ /// The .
+ /// Capabilities updated.
+ /// A .
+ [HttpPost("/Sessions/Capabilities/Full")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult PostFullCapabilities(
+ [FromQuery] string id,
+ [FromBody, Required] ClientCapabilities capabilities)
+ {
+ if (string.IsNullOrWhiteSpace(id))
+ {
+ id = RequestHelpers.GetSession(_sessionContext).Id;
+ }
+
+ _sessionManager.ReportCapabilities(id, capabilities);
+
+ return NoContent();
+ }
+
+ ///
+ /// Reports that a session is viewing an item.
+ ///
+ /// The session id.
+ /// The item id.
+ /// Session reported to server.
+ /// A .
+ [HttpPost("/Sessions/Viewing")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult ReportViewing(
+ [FromQuery] string sessionId,
+ [FromQuery] string itemId)
+ {
+ string session = RequestHelpers.GetSession(_sessionContext).Id;
+
+ _sessionManager.ReportNowViewingItem(session, itemId);
+ return NoContent();
+ }
+
+ ///
+ /// Reports that a session has ended.
+ ///
+ /// Session end reported to server.
+ /// A .
+ [HttpPost("/Sessions/Logout")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public ActionResult ReportSessionEnded()
+ {
+ // TODO: how do we get AuthorizationInfo without an IRequest?
+ AuthorizationInfo auth = _authContext.GetAuthorizationInfo(Request);
+
+ _sessionManager.Logout(auth.Token);
+ return NoContent();
+ }
+
+ ///
+ /// Get all auth providers.
+ ///
+ /// Auth providers retrieved.
+ /// An with the auth providers.
+ [HttpGet("/Auth/Providers")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult> GetAuthProviders()
+ {
+ return _userManager.GetAuthenticationProviders();
+ }
+
+ ///
+ /// Get all password reset providers.
+ ///
+ /// Password reset providers retrieved.
+ /// An with the password reset providers.
+ [HttpGet("/Auto/PasswordResetProviders")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ public ActionResult> GetPasswordResetProviders()
+ {
+ return _userManager.GetPasswordResetProviders();
+ }
+ }
+}
diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs
index 9f4d34f9c6..ae8ab37e8e 100644
--- a/Jellyfin.Api/Helpers/RequestHelpers.cs
+++ b/Jellyfin.Api/Helpers/RequestHelpers.cs
@@ -1,4 +1,6 @@
using System;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Session;
namespace Jellyfin.Api.Helpers
{
@@ -25,5 +27,18 @@ namespace Jellyfin.Api.Helpers
? value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries)
: value.Split(separator);
}
+
+ internal static SessionInfo GetSession(ISessionContext sessionContext)
+ {
+ // TODO: how do we get a SessionInfo without IRequest?
+ SessionInfo session = sessionContext.GetSession("Request");
+
+ if (session == null)
+ {
+ throw new ArgumentException("Session not found.");
+ }
+
+ return session;
+ }
}
}
diff --git a/MediaBrowser.Api/Sessions/SessionService.cs b/MediaBrowser.Api/Sessions/SessionService.cs
deleted file mode 100644
index 020bb5042b..0000000000
--- a/MediaBrowser.Api/Sessions/SessionService.cs
+++ /dev/null
@@ -1,498 +0,0 @@
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Services;
-using MediaBrowser.Model.Session;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api.Sessions
-{
- ///
- /// Class GetSessions.
- ///
- [Route("/Sessions", "GET", Summary = "Gets a list of sessions")]
- [Authenticated]
- public class GetSessions : IReturn
- {
- [ApiMember(Name = "ControllableByUserId", Description = "Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public Guid ControllableByUserId { get; set; }
-
- [ApiMember(Name = "DeviceId", Description = "Filter by device Id.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
- public string DeviceId { get; set; }
-
- public int? ActiveWithinSeconds { get; set; }
- }
-
- ///
- /// Class DisplayContent.
- ///
- [Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")]
- [Authenticated]
- public class DisplayContent : IReturnVoid
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- ///
- /// Artist, Genre, Studio, Person, or any kind of BaseItem
- ///
- /// The type of the item.
- [ApiMember(Name = "ItemType", Description = "The type of item to browse to.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ItemType { get; set; }
-
- ///
- /// Artist name, genre name, item Id, etc
- ///
- /// The item identifier.
- [ApiMember(Name = "ItemId", Description = "The Id of the item.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ItemId { get; set; }
-
- ///
- /// Gets or sets the name of the item.
- ///
- /// The name of the item.
- [ApiMember(Name = "ItemName", Description = "The name of the item.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ItemName { get; set; }
- }
-
- [Route("/Sessions/{Id}/Playing", "POST", Summary = "Instructs a session to play an item")]
- [Authenticated]
- public class Play : PlayRequest
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/{Id}/Playing/{Command}", "POST", Summary = "Issues a playstate command to a client")]
- [Authenticated]
- public class SendPlaystateCommand : PlaystateRequest, IReturnVoid
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/{Id}/System/{Command}", "POST", Summary = "Issues a system command to a client")]
- [Authenticated]
- public class SendSystemCommand : IReturnVoid
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- ///
- /// Gets or sets the command.
- ///
- /// The play command.
- [ApiMember(Name = "Command", Description = "The command to send.", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Command { get; set; }
- }
-
- [Route("/Sessions/{Id}/Command/{Command}", "POST", Summary = "Issues a system command to a client")]
- [Authenticated]
- public class SendGeneralCommand : IReturnVoid
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- ///
- /// Gets or sets the command.
- ///
- /// The play command.
- [ApiMember(Name = "Command", Description = "The command to send.", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Command { get; set; }
- }
-
- [Route("/Sessions/{Id}/Command", "POST", Summary = "Issues a system command to a client")]
- [Authenticated]
- public class SendFullGeneralCommand : GeneralCommand, IReturnVoid
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/{Id}/Message", "POST", Summary = "Issues a command to a client to display a message to the user")]
- [Authenticated]
- public class SendMessageCommand : IReturnVoid
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- [ApiMember(Name = "Text", Description = "The message text.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Text { get; set; }
-
- [ApiMember(Name = "Header", Description = "The message header.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Header { get; set; }
-
- [ApiMember(Name = "TimeoutMs", Description = "The message timeout. If omitted the user will have to confirm viewing the message.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public long? TimeoutMs { get; set; }
- }
-
- [Route("/Sessions/{Id}/Users/{UserId}", "POST", Summary = "Adds an additional user to a session")]
- [Authenticated]
- public class AddUserToSession : IReturnVoid
- {
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- [ApiMember(Name = "UserId", Description = "UserId Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string UserId { get; set; }
- }
-
- [Route("/Sessions/{Id}/Users/{UserId}", "DELETE", Summary = "Removes an additional user from a session")]
- [Authenticated]
- public class RemoveUserFromSession : IReturnVoid
- {
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string Id { get; set; }
-
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
- public string UserId { get; set; }
- }
-
- [Route("/Sessions/Capabilities", "POST", Summary = "Updates capabilities for a device")]
- [Authenticated]
- public class PostCapabilities : IReturnVoid
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Id { get; set; }
-
- [ApiMember(Name = "PlayableMediaTypes", Description = "A list of playable media types, comma delimited. Audio, Video, Book, Photo.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string PlayableMediaTypes { get; set; }
-
- [ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string SupportedCommands { get; set; }
-
- [ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
- public bool SupportsMediaControl { get; set; }
-
- [ApiMember(Name = "SupportsSync", Description = "Determines whether sync is supported.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
- public bool SupportsSync { get; set; }
-
- [ApiMember(Name = "SupportsPersistentIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
- public bool SupportsPersistentIdentifier { get; set; }
-
- public PostCapabilities()
- {
- SupportsPersistentIdentifier = true;
- }
- }
-
- [Route("/Sessions/Capabilities/Full", "POST", Summary = "Updates capabilities for a device")]
- [Authenticated]
- public class PostFullCapabilities : ClientCapabilities, IReturnVoid
- {
- ///
- /// Gets or sets the id.
- ///
- /// The id.
- [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string Id { get; set; }
- }
-
- [Route("/Sessions/Viewing", "POST", Summary = "Reports that a session is viewing an item")]
- [Authenticated]
- public class ReportViewing : IReturnVoid
- {
- [ApiMember(Name = "SessionId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string SessionId { get; set; }
-
- [ApiMember(Name = "ItemId", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
- public string ItemId { get; set; }
- }
-
- [Route("/Sessions/Logout", "POST", Summary = "Reports that a session has ended")]
- [Authenticated]
- public class ReportSessionEnded : IReturnVoid
- {
- }
-
- [Route("/Auth/Providers", "GET")]
- [Authenticated(Roles = "Admin")]
- public class GetAuthProviders : IReturn
- {
- }
-
- [Route("/Auth/PasswordResetProviders", "GET")]
- [Authenticated(Roles = "Admin")]
- public class GetPasswordResetProviders : IReturn
- {
- }
-
- ///
- /// Class SessionsService.
- ///
- public class SessionService : BaseApiService
- {
- ///
- /// The session manager.
- ///
- private readonly ISessionManager _sessionManager;
-
- private readonly IUserManager _userManager;
- private readonly IAuthorizationContext _authContext;
- private readonly IDeviceManager _deviceManager;
- private readonly ISessionContext _sessionContext;
-
- public SessionService(
- ILogger logger,
- IServerConfigurationManager serverConfigurationManager,
- IHttpResultFactory httpResultFactory,
- ISessionManager sessionManager,
- IUserManager userManager,
- IAuthorizationContext authContext,
- IDeviceManager deviceManager,
- ISessionContext sessionContext)
- : base(logger, serverConfigurationManager, httpResultFactory)
- {
- _sessionManager = sessionManager;
- _userManager = userManager;
- _authContext = authContext;
- _deviceManager = deviceManager;
- _sessionContext = sessionContext;
- }
-
- public object Get(GetAuthProviders request)
- {
- return _userManager.GetAuthenticationProviders();
- }
-
- public object Get(GetPasswordResetProviders request)
- {
- return _userManager.GetPasswordResetProviders();
- }
-
- public void Post(ReportSessionEnded request)
- {
- var auth = _authContext.GetAuthorizationInfo(Request);
-
- _sessionManager.Logout(auth.Token);
- }
-
- ///
- /// Gets the specified request.
- ///
- /// The request.
- /// System.Object.
- public object Get(GetSessions request)
- {
- var result = _sessionManager.Sessions;
-
- if (!string.IsNullOrEmpty(request.DeviceId))
- {
- result = result.Where(i => string.Equals(i.DeviceId, request.DeviceId, StringComparison.OrdinalIgnoreCase));
- }
-
- if (!request.ControllableByUserId.Equals(Guid.Empty))
- {
- result = result.Where(i => i.SupportsRemoteControl);
-
- var user = _userManager.GetUserById(request.ControllableByUserId);
-
- if (!user.Policy.EnableRemoteControlOfOtherUsers)
- {
- result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(request.ControllableByUserId));
- }
-
- if (!user.Policy.EnableSharedDeviceControl)
- {
- result = result.Where(i => !i.UserId.Equals(Guid.Empty));
- }
-
- if (request.ActiveWithinSeconds.HasValue && request.ActiveWithinSeconds.Value > 0)
- {
- var minActiveDate = DateTime.UtcNow.AddSeconds(0 - request.ActiveWithinSeconds.Value);
- result = result.Where(i => i.LastActivityDate >= minActiveDate);
- }
-
- result = result.Where(i =>
- {
- var deviceId = i.DeviceId;
-
- if (!string.IsNullOrWhiteSpace(deviceId))
- {
- if (!_deviceManager.CanAccessDevice(user, deviceId))
- {
- return false;
- }
- }
-
- return true;
- });
- }
-
- return ToOptimizedResult(result.ToArray());
- }
-
- public Task Post(SendPlaystateCommand request)
- {
- return _sessionManager.SendPlaystateCommand(GetSession(_sessionContext).Id, request.Id, request, CancellationToken.None);
- }
-
- ///
- /// Posts the specified request.
- ///
- /// The request.
- public Task Post(DisplayContent request)
- {
- var command = new BrowseRequest
- {
- ItemId = request.ItemId,
- ItemName = request.ItemName,
- ItemType = request.ItemType
- };
-
- return _sessionManager.SendBrowseCommand(GetSession(_sessionContext).Id, request.Id, command, CancellationToken.None);
- }
-
- ///
- /// Posts the specified request.
- ///
- /// The request.
- public Task Post(SendSystemCommand request)
- {
- var name = request.Command;
- if (Enum.TryParse(name, true, out GeneralCommandType commandType))
- {
- name = commandType.ToString();
- }
-
- var currentSession = GetSession(_sessionContext);
- var command = new GeneralCommand
- {
- Name = name,
- ControllingUserId = currentSession.UserId
- };
-
- return _sessionManager.SendGeneralCommand(currentSession.Id, request.Id, command, CancellationToken.None);
- }
-
- ///
- /// Posts the specified request.
- ///
- /// The request.
- public Task Post(SendMessageCommand request)
- {
- var command = new MessageCommand
- {
- Header = string.IsNullOrEmpty(request.Header) ? "Message from Server" : request.Header,
- TimeoutMs = request.TimeoutMs,
- Text = request.Text
- };
-
- return _sessionManager.SendMessageCommand(GetSession(_sessionContext).Id, request.Id, command, CancellationToken.None);
- }
-
- ///
- /// Posts the specified request.
- ///
- /// The request.
- public Task Post(Play request)
- {
- return _sessionManager.SendPlayCommand(GetSession(_sessionContext).Id, request.Id, request, CancellationToken.None);
- }
-
- public Task Post(SendGeneralCommand request)
- {
- var currentSession = GetSession(_sessionContext);
-
- var command = new GeneralCommand
- {
- Name = request.Command,
- ControllingUserId = currentSession.UserId
- };
-
- return _sessionManager.SendGeneralCommand(currentSession.Id, request.Id, command, CancellationToken.None);
- }
-
- public Task Post(SendFullGeneralCommand request)
- {
- var currentSession = GetSession(_sessionContext);
-
- request.ControllingUserId = currentSession.UserId;
-
- return _sessionManager.SendGeneralCommand(currentSession.Id, request.Id, request, CancellationToken.None);
- }
-
- public void Post(AddUserToSession request)
- {
- _sessionManager.AddAdditionalUser(request.Id, new Guid(request.UserId));
- }
-
- public void Delete(RemoveUserFromSession request)
- {
- _sessionManager.RemoveAdditionalUser(request.Id, new Guid(request.UserId));
- }
-
- public void Post(PostCapabilities request)
- {
- if (string.IsNullOrWhiteSpace(request.Id))
- {
- request.Id = GetSession(_sessionContext).Id;
- }
-
- _sessionManager.ReportCapabilities(request.Id, new ClientCapabilities
- {
- PlayableMediaTypes = SplitValue(request.PlayableMediaTypes, ','),
- SupportedCommands = SplitValue(request.SupportedCommands, ','),
- SupportsMediaControl = request.SupportsMediaControl,
- SupportsSync = request.SupportsSync,
- SupportsPersistentIdentifier = request.SupportsPersistentIdentifier
- });
- }
-
- public void Post(PostFullCapabilities request)
- {
- if (string.IsNullOrWhiteSpace(request.Id))
- {
- request.Id = GetSession(_sessionContext).Id;
- }
-
- _sessionManager.ReportCapabilities(request.Id, request);
- }
-
- public void Post(ReportViewing request)
- {
- request.SessionId = GetSession(_sessionContext).Id;
-
- _sessionManager.ReportNowViewingItem(request.SessionId, request.ItemId);
- }
- }
-}