mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-10-31 10:37:22 -04:00 
			
		
		
		
	Merge pull request #3324 from Ullmie02/api-sessionservice
Move SessionService to Jellyfin.Api
This commit is contained in:
		
						commit
						576ffeb2a9
					
				
							
								
								
									
										474
									
								
								Jellyfin.Api/Controllers/SessionController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										474
									
								
								Jellyfin.Api/Controllers/SessionController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,474 @@ | ||||
| #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 Jellyfin.Data.Enums; | ||||
| 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 | ||||
| { | ||||
|     /// <summary> | ||||
|     /// The session controller. | ||||
|     /// </summary> | ||||
|     public class SessionController : BaseJellyfinApiController | ||||
|     { | ||||
|         private readonly ISessionManager _sessionManager; | ||||
|         private readonly IUserManager _userManager; | ||||
|         private readonly IAuthorizationContext _authContext; | ||||
|         private readonly IDeviceManager _deviceManager; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="SessionController"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="sessionManager">Instance of <see cref="ISessionManager"/> interface.</param> | ||||
|         /// <param name="userManager">Instance of <see cref="IUserManager"/> interface.</param> | ||||
|         /// <param name="authContext">Instance of <see cref="IAuthorizationContext"/> interface.</param> | ||||
|         /// <param name="deviceManager">Instance of <see cref="IDeviceManager"/> interface.</param> | ||||
|         public SessionController( | ||||
|             ISessionManager sessionManager, | ||||
|             IUserManager userManager, | ||||
|             IAuthorizationContext authContext, | ||||
|             IDeviceManager deviceManager) | ||||
|         { | ||||
|             _sessionManager = sessionManager; | ||||
|             _userManager = userManager; | ||||
|             _authContext = authContext; | ||||
|             _deviceManager = deviceManager; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets a list of sessions. | ||||
|         /// </summary> | ||||
|         /// <param name="controllableByUserId">Filter by sessions that a given user is allowed to remote control.</param> | ||||
|         /// <param name="deviceId">Filter by device Id.</param> | ||||
|         /// <param name="activeWithinSeconds">Optional. Filter by sessions that were active in the last n seconds.</param> | ||||
|         /// <response code="200">List of sessions returned.</response> | ||||
|         /// <returns>An <see cref="IEnumerable{SessionInfo}"/> with the available sessions.</returns> | ||||
|         [HttpGet("/Sessions")] | ||||
|         [Authorize] | ||||
|         [ProducesResponseType(StatusCodes.Status200OK)] | ||||
|         public ActionResult<IEnumerable<SessionInfo>> 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.HasPermission(PermissionKind.EnableRemoteControlOfOtherUsers)) | ||||
|                 { | ||||
|                     result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(controllableByUserId)); | ||||
|                 } | ||||
| 
 | ||||
|                 if (!user.HasPermission(PermissionKind.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); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Instructs a session to browse to an item or view. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session Id.</param> | ||||
|         /// <param name="itemType">The type of item to browse to.</param> | ||||
|         /// <param name="itemId">The Id of the item.</param> | ||||
|         /// <param name="itemName">The name of the item.</param> | ||||
|         /// <response code="204">Instruction sent to session.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [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(_sessionManager, _authContext, Request).Id, | ||||
|                 id, | ||||
|                 command, | ||||
|                 CancellationToken.None); | ||||
| 
 | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Instructs a session to play an item. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="itemIds">The ids of the items to play, comma delimited.</param> | ||||
|         /// <param name="startPositionTicks">The starting position of the first item.</param> | ||||
|         /// <param name="playCommand">The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now.</param> | ||||
|         /// <param name="playRequest">The <see cref="PlayRequest"/>.</param> | ||||
|         /// <response code="204">Instruction sent to session.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [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(_sessionManager, _authContext, Request).Id, | ||||
|                 id, | ||||
|                 playRequest, | ||||
|                 CancellationToken.None); | ||||
| 
 | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Issues a playstate command to a client. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="playstateRequest">The <see cref="PlaystateRequest"/>.</param> | ||||
|         /// <response code="204">Playstate command sent to session.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [HttpPost("/Sessions/{id}/Playing/{command}")] | ||||
|         [ProducesResponseType(StatusCodes.Status204NoContent)] | ||||
|         public ActionResult SendPlaystateCommand( | ||||
|             [FromRoute] string id, | ||||
|             [FromBody] PlaystateRequest playstateRequest) | ||||
|         { | ||||
|             _sessionManager.SendPlaystateCommand( | ||||
|                 RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id, | ||||
|                 id, | ||||
|                 playstateRequest, | ||||
|                 CancellationToken.None); | ||||
| 
 | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Issues a system command to a client. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="command">The command to send.</param> | ||||
|         /// <response code="204">System command sent to session.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [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(_sessionManager, _authContext, Request); | ||||
|             var generalCommand = new GeneralCommand | ||||
|             { | ||||
|                 Name = name, | ||||
|                 ControllingUserId = currentSession.UserId | ||||
|             }; | ||||
| 
 | ||||
|             _sessionManager.SendGeneralCommand(currentSession.Id, id, generalCommand, CancellationToken.None); | ||||
| 
 | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Issues a general command to a client. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="command">The command to send.</param> | ||||
|         /// <response code="204">General command sent to session.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [HttpPost("/Sessions/{id}/Command/{Command}")] | ||||
|         [ProducesResponseType(StatusCodes.Status204NoContent)] | ||||
|         public ActionResult SendGeneralCommand( | ||||
|             [FromRoute] string id, | ||||
|             [FromRoute] string command) | ||||
|         { | ||||
|             var currentSession = RequestHelpers.GetSession(_sessionManager, _authContext, Request); | ||||
| 
 | ||||
|             var generalCommand = new GeneralCommand | ||||
|             { | ||||
|                 Name = command, | ||||
|                 ControllingUserId = currentSession.UserId | ||||
|             }; | ||||
| 
 | ||||
|             _sessionManager.SendGeneralCommand(currentSession.Id, id, generalCommand, CancellationToken.None); | ||||
| 
 | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Issues a full general command to a client. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="command">The <see cref="GeneralCommand"/>.</param> | ||||
|         /// <response code="204">Full general command sent to session.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [HttpPost("/Sessions/{id}/Command")] | ||||
|         [ProducesResponseType(StatusCodes.Status204NoContent)] | ||||
|         public ActionResult SendFullGeneralCommand( | ||||
|             [FromRoute] string id, | ||||
|             [FromBody, Required] GeneralCommand command) | ||||
|         { | ||||
|             var currentSession = RequestHelpers.GetSession(_sessionManager, _authContext, Request); | ||||
| 
 | ||||
|             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(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Issues a command to a client to display a message to the user. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="text">The message test.</param> | ||||
|         /// <param name="header">The message header.</param> | ||||
|         /// <param name="timeoutMs">The message timeout. If omitted the user will have to confirm viewing the message.</param> | ||||
|         /// <response code="204">Message sent.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [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(_sessionManager, _authContext, Request).Id, id, command, CancellationToken.None); | ||||
| 
 | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Adds an additional user to a session. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="userId">The user id.</param> | ||||
|         /// <response code="204">User added to session.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [HttpPost("/Sessions/{id}/User/{userId}")] | ||||
|         [ProducesResponseType(StatusCodes.Status204NoContent)] | ||||
|         public ActionResult AddUserToSession( | ||||
|             [FromRoute] string id, | ||||
|             [FromRoute] Guid userId) | ||||
|         { | ||||
|             _sessionManager.AddAdditionalUser(id, userId); | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Removes an additional user from a session. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="userId">The user id.</param> | ||||
|         /// <response code="204">User removed from session.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [HttpDelete("/Sessions/{id}/User/{userId}")] | ||||
|         [ProducesResponseType(StatusCodes.Status204NoContent)] | ||||
|         public ActionResult RemoveUserFromSession( | ||||
|             [FromRoute] string id, | ||||
|             [FromRoute] Guid userId) | ||||
|         { | ||||
|             _sessionManager.RemoveAdditionalUser(id, userId); | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Updates capabilities for a device. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="playableMediaTypes">A list of playable media types, comma delimited. Audio, Video, Book, Photo.</param> | ||||
|         /// <param name="supportedCommands">A list of supported remote control commands, comma delimited.</param> | ||||
|         /// <param name="supportsMediaControl">Determines whether media can be played remotely..</param> | ||||
|         /// <param name="supportsSync">Determines whether sync is supported.</param> | ||||
|         /// <param name="supportsPersistentIdentifier">Determines whether the device supports a unique identifier.</param> | ||||
|         /// <response code="204">Capabilities posted.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [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(_sessionManager, _authContext, Request).Id; | ||||
|             } | ||||
| 
 | ||||
|             _sessionManager.ReportCapabilities(id, new ClientCapabilities | ||||
|             { | ||||
|                 PlayableMediaTypes = RequestHelpers.Split(playableMediaTypes, ',', true), | ||||
|                 SupportedCommands = RequestHelpers.Split(supportedCommands, ',', true), | ||||
|                 SupportsMediaControl = supportsMediaControl, | ||||
|                 SupportsSync = supportsSync, | ||||
|                 SupportsPersistentIdentifier = supportsPersistentIdentifier | ||||
|             }); | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Updates capabilities for a device. | ||||
|         /// </summary> | ||||
|         /// <param name="id">The session id.</param> | ||||
|         /// <param name="capabilities">The <see cref="ClientCapabilities"/>.</param> | ||||
|         /// <response code="204">Capabilities updated.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [HttpPost("/Sessions/Capabilities/Full")] | ||||
|         [ProducesResponseType(StatusCodes.Status204NoContent)] | ||||
|         public ActionResult PostFullCapabilities( | ||||
|             [FromQuery] string id, | ||||
|             [FromBody, Required] ClientCapabilities capabilities) | ||||
|         { | ||||
|             if (string.IsNullOrWhiteSpace(id)) | ||||
|             { | ||||
|                 id = RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id; | ||||
|             } | ||||
| 
 | ||||
|             _sessionManager.ReportCapabilities(id, capabilities); | ||||
| 
 | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Reports that a session is viewing an item. | ||||
|         /// </summary> | ||||
|         /// <param name="sessionId">The session id.</param> | ||||
|         /// <param name="itemId">The item id.</param> | ||||
|         /// <response code="204">Session reported to server.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [HttpPost("/Sessions/Viewing")] | ||||
|         [ProducesResponseType(StatusCodes.Status204NoContent)] | ||||
|         public ActionResult ReportViewing( | ||||
|             [FromQuery] string sessionId, | ||||
|             [FromQuery] string itemId) | ||||
|         { | ||||
|             string session = RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id; | ||||
| 
 | ||||
|             _sessionManager.ReportNowViewingItem(session, itemId); | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Reports that a session has ended. | ||||
|         /// </summary> | ||||
|         /// <response code="204">Session end reported to server.</response> | ||||
|         /// <returns>A <see cref="NoContentResult"/>.</returns> | ||||
|         [HttpPost("/Sessions/Logout")] | ||||
|         [ProducesResponseType(StatusCodes.Status204NoContent)] | ||||
|         public ActionResult ReportSessionEnded() | ||||
|         { | ||||
|             AuthorizationInfo auth = _authContext.GetAuthorizationInfo(Request); | ||||
| 
 | ||||
|             _sessionManager.Logout(auth.Token); | ||||
|             return NoContent(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Get all auth providers. | ||||
|         /// </summary> | ||||
|         /// <response code="200">Auth providers retrieved.</response> | ||||
|         /// <returns>An <see cref="IEnumerable{NameIdPair}"/> with the auth providers.</returns> | ||||
|         [HttpGet("/Auth/Providers")] | ||||
|         [ProducesResponseType(StatusCodes.Status200OK)] | ||||
|         public ActionResult<IEnumerable<NameIdPair>> GetAuthProviders() | ||||
|         { | ||||
|             return _userManager.GetAuthenticationProviders(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Get all password reset providers. | ||||
|         /// </summary> | ||||
|         /// <response code="200">Password reset providers retrieved.</response> | ||||
|         /// <returns>An <see cref="IEnumerable{NameIdPair}"/> with the password reset providers.</returns> | ||||
|         [HttpGet("/Auto/PasswordResetProviders")] | ||||
|         [ProducesResponseType(StatusCodes.Status200OK)] | ||||
|         public ActionResult<IEnumerable<NameIdPair>> GetPasswordResetProviders() | ||||
|         { | ||||
|             return _userManager.GetPasswordResetProviders(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,6 +1,7 @@ | ||||
| using System; | ||||
| using Jellyfin.Data.Enums; | ||||
| using MediaBrowser.Controller.Net; | ||||
| using MediaBrowser.Controller.Session; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| 
 | ||||
| namespace Jellyfin.Api.Helpers | ||||
| @ -52,5 +53,25 @@ namespace Jellyfin.Api.Helpers | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         internal static SessionInfo GetSession(ISessionManager sessionManager, IAuthorizationContext authContext, HttpRequest request) | ||||
|         { | ||||
|             var authorization = authContext.GetAuthorizationInfo(request); | ||||
|             var user = authorization.User; | ||||
|             var session = sessionManager.LogSessionActivity( | ||||
|                 authorization.Client, | ||||
|                 authorization.Version, | ||||
|                 authorization.DeviceId, | ||||
|                 authorization.Device, | ||||
|                 request.HttpContext.Connection.RemoteIpAddress.ToString(), | ||||
|                 user); | ||||
| 
 | ||||
|             if (session == null) | ||||
|             { | ||||
|                 throw new ArgumentException("Session not found."); | ||||
|             } | ||||
| 
 | ||||
|             return session; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,499 +0,0 @@ | ||||
| using System; | ||||
| using System.Linq; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using Jellyfin.Data.Enums; | ||||
| 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 | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Class GetSessions. | ||||
|     /// </summary> | ||||
|     [Route("/Sessions", "GET", Summary = "Gets a list of sessions")] | ||||
|     [Authenticated] | ||||
|     public class GetSessions : IReturn<SessionInfo[]> | ||||
|     { | ||||
|         [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; } | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Class DisplayContent. | ||||
|     /// </summary> | ||||
|     [Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")] | ||||
|     [Authenticated] | ||||
|     public class DisplayContent : IReturnVoid | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] | ||||
|         public string Id { get; set; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Artist, Genre, Studio, Person, or any kind of BaseItem | ||||
|         /// </summary> | ||||
|         /// <value>The type of the item.</value> | ||||
|         [ApiMember(Name = "ItemType", Description = "The type of item to browse to.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] | ||||
|         public string ItemType { get; set; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Artist name, genre name, item Id, etc | ||||
|         /// </summary> | ||||
|         /// <value>The item identifier.</value> | ||||
|         [ApiMember(Name = "ItemId", Description = "The Id of the item.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] | ||||
|         public string ItemId { get; set; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets or sets the name of the item. | ||||
|         /// </summary> | ||||
|         /// <value>The name of the item.</value> | ||||
|         [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 | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [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 | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [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 | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] | ||||
|         public string Id { get; set; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets or sets the command. | ||||
|         /// </summary> | ||||
|         /// <value>The play command.</value> | ||||
|         [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 | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] | ||||
|         public string Id { get; set; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets or sets the command. | ||||
|         /// </summary> | ||||
|         /// <value>The play command.</value> | ||||
|         [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 | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [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 | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [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 | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [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 | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the id. | ||||
|         /// </summary> | ||||
|         /// <value>The id.</value> | ||||
|         [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<NameIdPair[]> | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     [Route("/Auth/PasswordResetProviders", "GET")] | ||||
|     [Authenticated(Roles = "Admin")] | ||||
|     public class GetPasswordResetProviders : IReturn<NameIdPair[]> | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Class SessionsService. | ||||
|     /// </summary> | ||||
|     public class SessionService : BaseApiService | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// The session manager. | ||||
|         /// </summary> | ||||
|         private readonly ISessionManager _sessionManager; | ||||
| 
 | ||||
|         private readonly IUserManager _userManager; | ||||
|         private readonly IAuthorizationContext _authContext; | ||||
|         private readonly IDeviceManager _deviceManager; | ||||
|         private readonly ISessionContext _sessionContext; | ||||
| 
 | ||||
|         public SessionService( | ||||
|             ILogger<SessionService> 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); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets the specified request. | ||||
|         /// </summary> | ||||
|         /// <param name="request">The request.</param> | ||||
|         /// <returns>System.Object.</returns> | ||||
|         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.HasPermission(PermissionKind.EnableRemoteControlOfOtherUsers)) | ||||
|                 { | ||||
|                     result = result.Where(i => i.UserId.Equals(Guid.Empty) || i.ContainsUser(request.ControllableByUserId)); | ||||
|                 } | ||||
| 
 | ||||
|                 if (!user.HasPermission(PermissionKind.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); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Posts the specified request. | ||||
|         /// </summary> | ||||
|         /// <param name="request">The request.</param> | ||||
|         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); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Posts the specified request. | ||||
|         /// </summary> | ||||
|         /// <param name="request">The request.</param> | ||||
|         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); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Posts the specified request. | ||||
|         /// </summary> | ||||
|         /// <param name="request">The request.</param> | ||||
|         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); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Posts the specified request. | ||||
|         /// </summary> | ||||
|         /// <param name="request">The request.</param> | ||||
|         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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user