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