< Summary - Jellyfin

Information
Class: Jellyfin.Api.Controllers.SyncPlayController
Assembly: Jellyfin.Api
File(s): /srv/git/jellyfin/Jellyfin.Api/Controllers/SyncPlayController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 8
Coverable lines: 8
Total lines: 424
Line coverage: 0%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%

File(s)

/srv/git/jellyfin/Jellyfin.Api/Controllers/SyncPlayController.cs

#LineLine coverage
 1using System.Collections.Generic;
 2using System.ComponentModel.DataAnnotations;
 3using System.Linq;
 4using System.Threading;
 5using System.Threading.Tasks;
 6using Jellyfin.Api.Constants;
 7using Jellyfin.Api.Helpers;
 8using Jellyfin.Api.Models.SyncPlayDtos;
 9using MediaBrowser.Common.Api;
 10using MediaBrowser.Controller.Library;
 11using MediaBrowser.Controller.Session;
 12using MediaBrowser.Controller.SyncPlay;
 13using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
 14using MediaBrowser.Controller.SyncPlay.Requests;
 15using MediaBrowser.Model.SyncPlay;
 16using Microsoft.AspNetCore.Authorization;
 17using Microsoft.AspNetCore.Http;
 18using Microsoft.AspNetCore.Mvc;
 19
 20namespace Jellyfin.Api.Controllers;
 21
 22/// <summary>
 23/// The sync play controller.
 24/// </summary>
 25[Authorize(Policy = Policies.SyncPlayHasAccess)]
 26public class SyncPlayController : BaseJellyfinApiController
 27{
 28    private readonly ISessionManager _sessionManager;
 29    private readonly ISyncPlayManager _syncPlayManager;
 30    private readonly IUserManager _userManager;
 31
 32    /// <summary>
 33    /// Initializes a new instance of the <see cref="SyncPlayController"/> class.
 34    /// </summary>
 35    /// <param name="sessionManager">Instance of the <see cref="ISessionManager"/> interface.</param>
 36    /// <param name="syncPlayManager">Instance of the <see cref="ISyncPlayManager"/> interface.</param>
 37    /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
 038    public SyncPlayController(
 039        ISessionManager sessionManager,
 040        ISyncPlayManager syncPlayManager,
 041        IUserManager userManager)
 42    {
 043        _sessionManager = sessionManager;
 044        _syncPlayManager = syncPlayManager;
 045        _userManager = userManager;
 046    }
 47
 48    /// <summary>
 49    /// Create a new SyncPlay group.
 50    /// </summary>
 51    /// <param name="requestData">The settings of the new group.</param>
 52    /// <response code="204">New group created.</response>
 53    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 54    [HttpPost("New")]
 55    [ProducesResponseType(StatusCodes.Status204NoContent)]
 56    [Authorize(Policy = Policies.SyncPlayCreateGroup)]
 57    public async Task<ActionResult> SyncPlayCreateGroup(
 58        [FromBody, Required] NewGroupRequestDto requestData)
 59    {
 60        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 61        var syncPlayRequest = new NewGroupRequest(requestData.GroupName);
 62        _syncPlayManager.NewGroup(currentSession, syncPlayRequest, CancellationToken.None);
 63        return NoContent();
 64    }
 65
 66    /// <summary>
 67    /// Join an existing SyncPlay group.
 68    /// </summary>
 69    /// <param name="requestData">The group to join.</param>
 70    /// <response code="204">Group join successful.</response>
 71    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 72    [HttpPost("Join")]
 73    [ProducesResponseType(StatusCodes.Status204NoContent)]
 74    [Authorize(Policy = Policies.SyncPlayJoinGroup)]
 75    public async Task<ActionResult> SyncPlayJoinGroup(
 76        [FromBody, Required] JoinGroupRequestDto requestData)
 77    {
 78        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 79        var syncPlayRequest = new JoinGroupRequest(requestData.GroupId);
 80        _syncPlayManager.JoinGroup(currentSession, syncPlayRequest, CancellationToken.None);
 81        return NoContent();
 82    }
 83
 84    /// <summary>
 85    /// Leave the joined SyncPlay group.
 86    /// </summary>
 87    /// <response code="204">Group leave successful.</response>
 88    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 89    [HttpPost("Leave")]
 90    [ProducesResponseType(StatusCodes.Status204NoContent)]
 91    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 92    public async Task<ActionResult> SyncPlayLeaveGroup()
 93    {
 94        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 95        var syncPlayRequest = new LeaveGroupRequest();
 96        _syncPlayManager.LeaveGroup(currentSession, syncPlayRequest, CancellationToken.None);
 97        return NoContent();
 98    }
 99
 100    /// <summary>
 101    /// Gets all SyncPlay groups.
 102    /// </summary>
 103    /// <response code="200">Groups returned.</response>
 104    /// <returns>An <see cref="IEnumerable{GroupInfoView}"/> containing the available SyncPlay groups.</returns>
 105    [HttpGet("List")]
 106    [ProducesResponseType(StatusCodes.Status200OK)]
 107    [Authorize(Policy = Policies.SyncPlayJoinGroup)]
 108    public async Task<ActionResult<IEnumerable<GroupInfoDto>>> SyncPlayGetGroups()
 109    {
 110        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 111        var syncPlayRequest = new ListGroupsRequest();
 112        return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest).AsEnumerable());
 113    }
 114
 115    /// <summary>
 116    /// Request to set new playlist in SyncPlay group.
 117    /// </summary>
 118    /// <param name="requestData">The new playlist to play in the group.</param>
 119    /// <response code="204">Queue update sent to all group members.</response>
 120    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 121    [HttpPost("SetNewQueue")]
 122    [ProducesResponseType(StatusCodes.Status204NoContent)]
 123    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 124    public async Task<ActionResult> SyncPlaySetNewQueue(
 125        [FromBody, Required] PlayRequestDto requestData)
 126    {
 127        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 128        var syncPlayRequest = new PlayGroupRequest(
 129            requestData.PlayingQueue,
 130            requestData.PlayingItemPosition,
 131            requestData.StartPositionTicks);
 132        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 133        return NoContent();
 134    }
 135
 136    /// <summary>
 137    /// Request to change playlist item in SyncPlay group.
 138    /// </summary>
 139    /// <param name="requestData">The new item to play.</param>
 140    /// <response code="204">Queue update sent to all group members.</response>
 141    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 142    [HttpPost("SetPlaylistItem")]
 143    [ProducesResponseType(StatusCodes.Status204NoContent)]
 144    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 145    public async Task<ActionResult> SyncPlaySetPlaylistItem(
 146        [FromBody, Required] SetPlaylistItemRequestDto requestData)
 147    {
 148        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 149        var syncPlayRequest = new SetPlaylistItemGroupRequest(requestData.PlaylistItemId);
 150        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 151        return NoContent();
 152    }
 153
 154    /// <summary>
 155    /// Request to remove items from the playlist in SyncPlay group.
 156    /// </summary>
 157    /// <param name="requestData">The items to remove.</param>
 158    /// <response code="204">Queue update sent to all group members.</response>
 159    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 160    [HttpPost("RemoveFromPlaylist")]
 161    [ProducesResponseType(StatusCodes.Status204NoContent)]
 162    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 163    public async Task<ActionResult> SyncPlayRemoveFromPlaylist(
 164        [FromBody, Required] RemoveFromPlaylistRequestDto requestData)
 165    {
 166        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 167        var syncPlayRequest = new RemoveFromPlaylistGroupRequest(requestData.PlaylistItemIds, requestData.ClearPlaylist,
 168        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 169        return NoContent();
 170    }
 171
 172    /// <summary>
 173    /// Request to move an item in the playlist in SyncPlay group.
 174    /// </summary>
 175    /// <param name="requestData">The new position for the item.</param>
 176    /// <response code="204">Queue update sent to all group members.</response>
 177    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 178    [HttpPost("MovePlaylistItem")]
 179    [ProducesResponseType(StatusCodes.Status204NoContent)]
 180    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 181    public async Task<ActionResult> SyncPlayMovePlaylistItem(
 182        [FromBody, Required] MovePlaylistItemRequestDto requestData)
 183    {
 184        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 185        var syncPlayRequest = new MovePlaylistItemGroupRequest(requestData.PlaylistItemId, requestData.NewIndex);
 186        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 187        return NoContent();
 188    }
 189
 190    /// <summary>
 191    /// Request to queue items to the playlist of a SyncPlay group.
 192    /// </summary>
 193    /// <param name="requestData">The items to add.</param>
 194    /// <response code="204">Queue update sent to all group members.</response>
 195    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 196    [HttpPost("Queue")]
 197    [ProducesResponseType(StatusCodes.Status204NoContent)]
 198    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 199    public async Task<ActionResult> SyncPlayQueue(
 200        [FromBody, Required] QueueRequestDto requestData)
 201    {
 202        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 203        var syncPlayRequest = new QueueGroupRequest(requestData.ItemIds, requestData.Mode);
 204        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 205        return NoContent();
 206    }
 207
 208    /// <summary>
 209    /// Request unpause in SyncPlay group.
 210    /// </summary>
 211    /// <response code="204">Unpause update sent to all group members.</response>
 212    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 213    [HttpPost("Unpause")]
 214    [ProducesResponseType(StatusCodes.Status204NoContent)]
 215    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 216    public async Task<ActionResult> SyncPlayUnpause()
 217    {
 218        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 219        var syncPlayRequest = new UnpauseGroupRequest();
 220        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 221        return NoContent();
 222    }
 223
 224    /// <summary>
 225    /// Request pause in SyncPlay group.
 226    /// </summary>
 227    /// <response code="204">Pause update sent to all group members.</response>
 228    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 229    [HttpPost("Pause")]
 230    [ProducesResponseType(StatusCodes.Status204NoContent)]
 231    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 232    public async Task<ActionResult> SyncPlayPause()
 233    {
 234        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 235        var syncPlayRequest = new PauseGroupRequest();
 236        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 237        return NoContent();
 238    }
 239
 240    /// <summary>
 241    /// Request stop in SyncPlay group.
 242    /// </summary>
 243    /// <response code="204">Stop update sent to all group members.</response>
 244    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 245    [HttpPost("Stop")]
 246    [ProducesResponseType(StatusCodes.Status204NoContent)]
 247    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 248    public async Task<ActionResult> SyncPlayStop()
 249    {
 250        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 251        var syncPlayRequest = new StopGroupRequest();
 252        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 253        return NoContent();
 254    }
 255
 256    /// <summary>
 257    /// Request seek in SyncPlay group.
 258    /// </summary>
 259    /// <param name="requestData">The new playback position.</param>
 260    /// <response code="204">Seek update sent to all group members.</response>
 261    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 262    [HttpPost("Seek")]
 263    [ProducesResponseType(StatusCodes.Status204NoContent)]
 264    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 265    public async Task<ActionResult> SyncPlaySeek(
 266        [FromBody, Required] SeekRequestDto requestData)
 267    {
 268        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 269        var syncPlayRequest = new SeekGroupRequest(requestData.PositionTicks);
 270        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 271        return NoContent();
 272    }
 273
 274    /// <summary>
 275    /// Notify SyncPlay group that member is buffering.
 276    /// </summary>
 277    /// <param name="requestData">The player status.</param>
 278    /// <response code="204">Group state update sent to all group members.</response>
 279    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 280    [HttpPost("Buffering")]
 281    [ProducesResponseType(StatusCodes.Status204NoContent)]
 282    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 283    public async Task<ActionResult> SyncPlayBuffering(
 284        [FromBody, Required] BufferRequestDto requestData)
 285    {
 286        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 287        var syncPlayRequest = new BufferGroupRequest(
 288            requestData.When,
 289            requestData.PositionTicks,
 290            requestData.IsPlaying,
 291            requestData.PlaylistItemId);
 292        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 293        return NoContent();
 294    }
 295
 296    /// <summary>
 297    /// Notify SyncPlay group that member is ready for playback.
 298    /// </summary>
 299    /// <param name="requestData">The player status.</param>
 300    /// <response code="204">Group state update sent to all group members.</response>
 301    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 302    [HttpPost("Ready")]
 303    [ProducesResponseType(StatusCodes.Status204NoContent)]
 304    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 305    public async Task<ActionResult> SyncPlayReady(
 306        [FromBody, Required] ReadyRequestDto requestData)
 307    {
 308        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 309        var syncPlayRequest = new ReadyGroupRequest(
 310            requestData.When,
 311            requestData.PositionTicks,
 312            requestData.IsPlaying,
 313            requestData.PlaylistItemId);
 314        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 315        return NoContent();
 316    }
 317
 318    /// <summary>
 319    /// Request SyncPlay group to ignore member during group-wait.
 320    /// </summary>
 321    /// <param name="requestData">The settings to set.</param>
 322    /// <response code="204">Member state updated.</response>
 323    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 324    [HttpPost("SetIgnoreWait")]
 325    [ProducesResponseType(StatusCodes.Status204NoContent)]
 326    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 327    public async Task<ActionResult> SyncPlaySetIgnoreWait(
 328        [FromBody, Required] IgnoreWaitRequestDto requestData)
 329    {
 330        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 331        var syncPlayRequest = new IgnoreWaitGroupRequest(requestData.IgnoreWait);
 332        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 333        return NoContent();
 334    }
 335
 336    /// <summary>
 337    /// Request next item in SyncPlay group.
 338    /// </summary>
 339    /// <param name="requestData">The current item information.</param>
 340    /// <response code="204">Next item update sent to all group members.</response>
 341    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 342    [HttpPost("NextItem")]
 343    [ProducesResponseType(StatusCodes.Status204NoContent)]
 344    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 345    public async Task<ActionResult> SyncPlayNextItem(
 346        [FromBody, Required] NextItemRequestDto requestData)
 347    {
 348        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 349        var syncPlayRequest = new NextItemGroupRequest(requestData.PlaylistItemId);
 350        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 351        return NoContent();
 352    }
 353
 354    /// <summary>
 355    /// Request previous item in SyncPlay group.
 356    /// </summary>
 357    /// <param name="requestData">The current item information.</param>
 358    /// <response code="204">Previous item update sent to all group members.</response>
 359    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 360    [HttpPost("PreviousItem")]
 361    [ProducesResponseType(StatusCodes.Status204NoContent)]
 362    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 363    public async Task<ActionResult> SyncPlayPreviousItem(
 364        [FromBody, Required] PreviousItemRequestDto requestData)
 365    {
 366        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 367        var syncPlayRequest = new PreviousItemGroupRequest(requestData.PlaylistItemId);
 368        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 369        return NoContent();
 370    }
 371
 372    /// <summary>
 373    /// Request to set repeat mode in SyncPlay group.
 374    /// </summary>
 375    /// <param name="requestData">The new repeat mode.</param>
 376    /// <response code="204">Play queue update sent to all group members.</response>
 377    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 378    [HttpPost("SetRepeatMode")]
 379    [ProducesResponseType(StatusCodes.Status204NoContent)]
 380    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 381    public async Task<ActionResult> SyncPlaySetRepeatMode(
 382        [FromBody, Required] SetRepeatModeRequestDto requestData)
 383    {
 384        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 385        var syncPlayRequest = new SetRepeatModeGroupRequest(requestData.Mode);
 386        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 387        return NoContent();
 388    }
 389
 390    /// <summary>
 391    /// Request to set shuffle mode in SyncPlay group.
 392    /// </summary>
 393    /// <param name="requestData">The new shuffle mode.</param>
 394    /// <response code="204">Play queue update sent to all group members.</response>
 395    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 396    [HttpPost("SetShuffleMode")]
 397    [ProducesResponseType(StatusCodes.Status204NoContent)]
 398    [Authorize(Policy = Policies.SyncPlayIsInGroup)]
 399    public async Task<ActionResult> SyncPlaySetShuffleMode(
 400        [FromBody, Required] SetShuffleModeRequestDto requestData)
 401    {
 402        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 403        var syncPlayRequest = new SetShuffleModeGroupRequest(requestData.Mode);
 404        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 405        return NoContent();
 406    }
 407
 408    /// <summary>
 409    /// Update session ping.
 410    /// </summary>
 411    /// <param name="requestData">The new ping.</param>
 412    /// <response code="204">Ping updated.</response>
 413    /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
 414    [HttpPost("Ping")]
 415    [ProducesResponseType(StatusCodes.Status204NoContent)]
 416    public async Task<ActionResult> SyncPlayPing(
 417        [FromBody, Required] PingRequestDto requestData)
 418    {
 419        var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(
 420        var syncPlayRequest = new PingGroupRequest(requestData.Ping);
 421        _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
 422        return NoContent();
 423    }
 424}