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