SyncPlayController.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel.DataAnnotations;
  4. using System.Threading;
  5. using Jellyfin.Api.Constants;
  6. using Jellyfin.Api.Helpers;
  7. using MediaBrowser.Controller.Net;
  8. using MediaBrowser.Controller.Session;
  9. using MediaBrowser.Controller.SyncPlay;
  10. using MediaBrowser.Model.SyncPlay;
  11. using Microsoft.AspNetCore.Authorization;
  12. using Microsoft.AspNetCore.Http;
  13. using Microsoft.AspNetCore.Mvc;
  14. namespace Jellyfin.Api.Controllers
  15. {
  16. /// <summary>
  17. /// The sync play controller.
  18. /// </summary>
  19. [Authorize(Policy = Policies.DefaultAuthorization)]
  20. public class SyncPlayController : BaseJellyfinApiController
  21. {
  22. private readonly ISessionManager _sessionManager;
  23. private readonly IAuthorizationContext _authorizationContext;
  24. private readonly ISyncPlayManager _syncPlayManager;
  25. /// <summary>
  26. /// Initializes a new instance of the <see cref="SyncPlayController"/> class.
  27. /// </summary>
  28. /// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param>
  29. /// <param name="authorizationContext">Instance of the <see cref="IAuthorizationContext"/> interface.</param>
  30. /// <param name="syncPlayManager">Instance of the <see cref="ISyncPlayManager"/> interface.</param>
  31. public SyncPlayController(
  32. ISessionManager sessionManager,
  33. IAuthorizationContext authorizationContext,
  34. ISyncPlayManager syncPlayManager)
  35. {
  36. _sessionManager = sessionManager;
  37. _authorizationContext = authorizationContext;
  38. _syncPlayManager = syncPlayManager;
  39. }
  40. /// <summary>
  41. /// Create a new SyncPlay group.
  42. /// </summary>
  43. /// <response code="204">New group created.</response>
  44. /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
  45. [HttpPost("New")]
  46. [ProducesResponseType(StatusCodes.Status204NoContent)]
  47. public ActionResult SyncPlayCreateGroup()
  48. {
  49. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  50. _syncPlayManager.NewGroup(currentSession, CancellationToken.None);
  51. return NoContent();
  52. }
  53. /// <summary>
  54. /// Join an existing SyncPlay group.
  55. /// </summary>
  56. /// <param name="groupId">The sync play group id.</param>
  57. /// <response code="204">Group join successful.</response>
  58. /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
  59. [HttpPost("Join")]
  60. [ProducesResponseType(StatusCodes.Status204NoContent)]
  61. public ActionResult SyncPlayJoinGroup([FromQuery, Required] Guid groupId)
  62. {
  63. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  64. var joinRequest = new JoinGroupRequest()
  65. {
  66. GroupId = groupId
  67. };
  68. _syncPlayManager.JoinGroup(currentSession, groupId, joinRequest, CancellationToken.None);
  69. return NoContent();
  70. }
  71. /// <summary>
  72. /// Leave the joined SyncPlay group.
  73. /// </summary>
  74. /// <response code="204">Group leave successful.</response>
  75. /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
  76. [HttpPost("Leave")]
  77. [ProducesResponseType(StatusCodes.Status204NoContent)]
  78. public ActionResult SyncPlayLeaveGroup()
  79. {
  80. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  81. _syncPlayManager.LeaveGroup(currentSession, CancellationToken.None);
  82. return NoContent();
  83. }
  84. /// <summary>
  85. /// Gets all SyncPlay groups.
  86. /// </summary>
  87. /// <param name="filterItemId">Optional. Filter by item id.</param>
  88. /// <response code="200">Groups returned.</response>
  89. /// <returns>An <see cref="IEnumerable{GroupInfoView}"/> containing the available SyncPlay groups.</returns>
  90. [HttpGet("List")]
  91. [ProducesResponseType(StatusCodes.Status200OK)]
  92. public ActionResult<IEnumerable<GroupInfoView>> SyncPlayGetGroups([FromQuery] Guid? filterItemId)
  93. {
  94. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  95. return Ok(_syncPlayManager.ListGroups(currentSession, filterItemId.HasValue ? filterItemId.Value : Guid.Empty));
  96. }
  97. /// <summary>
  98. /// Request play in SyncPlay group.
  99. /// </summary>
  100. /// <response code="204">Play request sent to all group members.</response>
  101. /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
  102. [HttpPost("Play")]
  103. [ProducesResponseType(StatusCodes.Status204NoContent)]
  104. public ActionResult SyncPlayPlay()
  105. {
  106. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  107. var syncPlayRequest = new PlaybackRequest()
  108. {
  109. Type = PlaybackRequestType.Play
  110. };
  111. _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
  112. return NoContent();
  113. }
  114. /// <summary>
  115. /// Request pause in SyncPlay group.
  116. /// </summary>
  117. /// <response code="204">Pause request sent to all group members.</response>
  118. /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
  119. [HttpPost("Pause")]
  120. [ProducesResponseType(StatusCodes.Status204NoContent)]
  121. public ActionResult SyncPlayPause()
  122. {
  123. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  124. var syncPlayRequest = new PlaybackRequest()
  125. {
  126. Type = PlaybackRequestType.Pause
  127. };
  128. _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
  129. return NoContent();
  130. }
  131. /// <summary>
  132. /// Request seek in SyncPlay group.
  133. /// </summary>
  134. /// <param name="positionTicks">The playback position in ticks.</param>
  135. /// <response code="204">Seek request sent to all group members.</response>
  136. /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
  137. [HttpPost("Seek")]
  138. [ProducesResponseType(StatusCodes.Status204NoContent)]
  139. public ActionResult SyncPlaySeek([FromQuery] long positionTicks)
  140. {
  141. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  142. var syncPlayRequest = new PlaybackRequest()
  143. {
  144. Type = PlaybackRequestType.Seek,
  145. PositionTicks = positionTicks
  146. };
  147. _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
  148. return NoContent();
  149. }
  150. /// <summary>
  151. /// Request group wait in SyncPlay group while buffering.
  152. /// </summary>
  153. /// <param name="when">When the request has been made by the client.</param>
  154. /// <param name="positionTicks">The playback position in ticks.</param>
  155. /// <param name="bufferingDone">Whether the buffering is done.</param>
  156. /// <response code="204">Buffering request sent to all group members.</response>
  157. /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
  158. [HttpPost("Buffering")]
  159. [ProducesResponseType(StatusCodes.Status204NoContent)]
  160. public ActionResult SyncPlayBuffering([FromQuery] DateTime when, [FromQuery] long positionTicks, [FromQuery] bool bufferingDone)
  161. {
  162. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  163. var syncPlayRequest = new PlaybackRequest()
  164. {
  165. Type = bufferingDone ? PlaybackRequestType.Ready : PlaybackRequestType.Buffer,
  166. When = when,
  167. PositionTicks = positionTicks
  168. };
  169. _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
  170. return NoContent();
  171. }
  172. /// <summary>
  173. /// Update session ping.
  174. /// </summary>
  175. /// <param name="ping">The ping.</param>
  176. /// <response code="204">Ping updated.</response>
  177. /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
  178. [HttpPost("Ping")]
  179. [ProducesResponseType(StatusCodes.Status204NoContent)]
  180. public ActionResult SyncPlayPing([FromQuery] double ping)
  181. {
  182. var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
  183. var syncPlayRequest = new PlaybackRequest()
  184. {
  185. Type = PlaybackRequestType.Ping,
  186. Ping = Convert.ToInt64(ping)
  187. };
  188. _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
  189. return NoContent();
  190. }
  191. }
  192. }