Selaa lähdekoodia

Hide some property setters, init null values, update namespaces

Ionut Andrei Oanca 4 vuotta sitten
vanhempi
sitoutus
5d77f422f0
37 muutettua tiedostoa jossa 363 lisäystä ja 227 poistoa
  1. 12 37
      Emby.Server.Implementations/SyncPlay/GroupController.cs
  2. 22 71
      Jellyfin.Api/Controllers/SyncPlayController.cs
  3. 7 3
      MediaBrowser.Controller/SyncPlay/GroupStates/AbstractGroupState.cs
  4. 2 1
      MediaBrowser.Controller/SyncPlay/GroupStates/IdleGroupState.cs
  5. 2 1
      MediaBrowser.Controller/SyncPlay/GroupStates/PausedGroupState.cs
  6. 2 1
      MediaBrowser.Controller/SyncPlay/GroupStates/PlayingGroupState.cs
  7. 3 3
      MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs
  8. 1 0
      MediaBrowser.Controller/SyncPlay/IGroupController.cs
  9. 1 0
      MediaBrowser.Controller/SyncPlay/IGroupState.cs
  10. 4 10
      MediaBrowser.Controller/SyncPlay/IGroupStateContext.cs
  11. 24 9
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/BufferGroupRequest.cs
  12. 12 3
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/IgnoreWaitGroupRequest.cs
  13. 16 5
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/MovePlaylistItemGroupRequest.cs
  14. 12 3
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/NextTrackGroupRequest.cs
  15. 1 1
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/PauseGroupRequest.cs
  16. 12 3
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/PingGroupRequest.cs
  17. 22 7
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/PlayGroupRequest.cs
  18. 12 3
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/PreviousTrackGroupRequest.cs
  19. 20 7
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/QueueGroupRequest.cs
  20. 24 9
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/ReadyGroupRequest.cs
  21. 13 2
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs
  22. 12 3
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/SeekGroupRequest.cs
  23. 12 3
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetPlaylistItemGroupRequest.cs
  24. 12 3
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetRepeatModeGroupRequest.cs
  25. 12 3
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetShuffleModeGroupRequest.cs
  26. 1 1
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/StopGroupRequest.cs
  27. 1 1
      MediaBrowser.Controller/SyncPlay/PlaybackRequests/UnpauseGroupRequest.cs
  28. 3 6
      MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs
  29. 12 3
      MediaBrowser.Model/SyncPlay/GroupInfoDto.cs
  30. 18 0
      MediaBrowser.Model/SyncPlay/GroupQueueMode.cs
  31. 5 5
      MediaBrowser.Model/SyncPlay/GroupRequestType.cs
  32. 4 4
      MediaBrowser.Model/SyncPlay/GroupStateType.cs
  33. 8 2
      MediaBrowser.Model/SyncPlay/NewGroupRequest.cs
  34. 10 3
      MediaBrowser.Model/SyncPlay/PlayQueueUpdate.cs
  35. 2 2
      MediaBrowser.Model/SyncPlay/PlayQueueUpdateReason.cs
  36. 15 6
      MediaBrowser.Model/SyncPlay/QueueItem.cs
  37. 12 3
      MediaBrowser.Model/SyncPlay/SendCommand.cs

+ 12 - 37
Emby.Server.Implementations/SyncPlay/GroupController.cs

@@ -10,6 +10,8 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.SyncPlay;
+using MediaBrowser.Controller.SyncPlay.GroupStates;
+using MediaBrowser.Controller.SyncPlay.Queue;
 using MediaBrowser.Model.SyncPlay;
 using Microsoft.Extensions.Logging;
 
@@ -358,7 +360,7 @@ namespace Emby.Server.Implementations.SyncPlay
                 GroupName = GroupName,
                 State = _state.Type,
                 Participants = Participants.Values.Select(session => session.Session.UserName).Distinct().ToList(),
-                LastUpdatedAt = DateToUTCString(DateTime.UtcNow)
+                LastUpdatedAt = DateTime.UtcNow
             };
         }
 
@@ -422,8 +424,8 @@ namespace Emby.Server.Implementations.SyncPlay
                 PlaylistItemId = PlayQueue.GetPlayingItemPlaylistId(),
                 PositionTicks = PositionTicks,
                 Command = type,
-                When = DateToUTCString(LastActivity),
-                EmittedAt = DateToUTCString(DateTime.UtcNow)
+                When = LastActivity,
+                EmittedAt = DateTime.UtcNow
             };
         }
 
@@ -438,12 +440,6 @@ namespace Emby.Server.Implementations.SyncPlay
             };
         }
 
-        /// <inheritdoc />
-        public string DateToUTCString(DateTime dateTime)
-        {
-            return dateTime.ToUniversalTime().ToString("o", CultureInfo.InvariantCulture);
-        }
-
         /// <inheritdoc />
         public long SanitizePositionTicks(long? positionTicks)
         {
@@ -580,7 +576,7 @@ namespace Emby.Server.Implementations.SyncPlay
         }
 
         /// <inheritdoc />
-        public bool AddToPlayQueue(IEnumerable<Guid> newItems, string mode)
+        public bool AddToPlayQueue(IEnumerable<Guid> newItems, GroupQueueMode mode)
         {
             // Ignore on empty list.
             if (!newItems.Any())
@@ -594,7 +590,7 @@ namespace Emby.Server.Implementations.SyncPlay
                 return false;
             }
 
-            if (mode.Equals("next", StringComparison.OrdinalIgnoreCase))
+            if (mode.Equals(GroupQueueMode.QueueNext))
             {
                 PlayQueue.QueueNext(newItems);
             }
@@ -648,36 +644,15 @@ namespace Emby.Server.Implementations.SyncPlay
         }
 
         /// <inheritdoc />
-        public void SetRepeatMode(string mode)
+        public void SetRepeatMode(GroupRepeatMode mode)
         {
-            switch (mode)
-            {
-                case "RepeatOne":
-                    PlayQueue.SetRepeatMode(GroupRepeatMode.RepeatOne);
-                    break;
-                case "RepeatAll":
-                    PlayQueue.SetRepeatMode(GroupRepeatMode.RepeatAll);
-                    break;
-                default:
-                    // On unknown values, default to repeat none.
-                    PlayQueue.SetRepeatMode(GroupRepeatMode.RepeatNone);
-                    break;
-            }
+            PlayQueue.SetRepeatMode(mode);
         }
 
         /// <inheritdoc />
-        public void SetShuffleMode(string mode)
+        public void SetShuffleMode(GroupShuffleMode mode)
         {
-            switch (mode)
-            {
-                case "Shuffle":
-                    PlayQueue.SetShuffleMode(GroupShuffleMode.Shuffle);
-                    break;
-                default:
-                    // On unknown values, default to sorted playlist.
-                    PlayQueue.SetShuffleMode(GroupShuffleMode.Sorted);
-                    break;
-            }
+            PlayQueue.SetShuffleMode(mode);
         }
 
         /// <inheritdoc />
@@ -701,7 +676,7 @@ namespace Emby.Server.Implementations.SyncPlay
             return new PlayQueueUpdate()
             {
                 Reason = reason,
-                LastUpdate = DateToUTCString(PlayQueue.LastChange),
+                LastUpdate = PlayQueue.LastChange,
                 Playlist = PlayQueue.GetPlaylist(),
                 PlayingItemIndex = PlayQueue.PlayingItemIndex,
                 StartPositionTicks = startPositionTicks,

+ 22 - 71
Jellyfin.Api/Controllers/SyncPlayController.cs

@@ -7,6 +7,7 @@ using Jellyfin.Api.Helpers;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.SyncPlay;
+using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
 using MediaBrowser.Model.SyncPlay;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
@@ -118,17 +119,12 @@ namespace Jellyfin.Api.Controllers
         [HttpPost("Play")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SyncPlayPlay(
-            [FromQuery, Required] string playingQueue,
+            [FromQuery, Required] Guid[] playingQueue,
             [FromQuery, Required] int playingItemPosition,
             [FromQuery, Required] long startPositionTicks)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new PlayGroupRequest()
-            {
-                PlayingItemPosition = playingItemPosition,
-                StartPositionTicks = startPositionTicks
-            };
-            syncPlayRequest.PlayingQueue.AddRange(RequestHelpers.GetGuids(playingQueue));
+            var syncPlayRequest = new PlayGroupRequest(playingQueue, playingItemPosition, startPositionTicks);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -145,10 +141,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery, Required] string playlistItemId)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new SetPlaylistItemGroupRequest()
-            {
-                PlaylistItemId = playlistItemId
-            };
+            var syncPlayRequest = new SetPlaylistItemGroupRequest(playlistItemId);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -165,8 +158,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery, Required] string[] playlistItemIds)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new RemoveFromPlaylistGroupRequest();
-            syncPlayRequest.PlaylistItemIds.AddRange(playlistItemIds);
+            var syncPlayRequest = new RemoveFromPlaylistGroupRequest(playlistItemIds);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -185,11 +177,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery, Required] int newIndex)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new MovePlaylistItemGroupRequest()
-            {
-                PlaylistItemId = playlistItemId,
-                NewIndex = newIndex
-            };
+            var syncPlayRequest = new MovePlaylistItemGroupRequest(playlistItemId, newIndex);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -197,22 +185,18 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Request to queue items to the playlist of a SyncPlay group.
         /// </summary>
-        /// <param name="itemIds">The items to add. Item ids, comma delimited.</param>
-        /// <param name="mode">The mode in which to queue items.</param>
+        /// <param name="items">The items to add.</param>
+        /// <param name="mode">The mode in which to enqueue the items.</param>
         /// <response code="204">Queue update request sent to all group members.</response>
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Queue")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SyncPlayQueue(
-            [FromQuery, Required] string itemIds,
-            [FromQuery, Required] string mode)
+            [FromQuery, Required] Guid[] items,
+            [FromQuery, Required] GroupQueueMode mode)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new QueueGroupRequest()
-            {
-                Mode = mode
-            };
-            syncPlayRequest.ItemIds.AddRange(RequestHelpers.GetGuids(itemIds));
+            var syncPlayRequest = new QueueGroupRequest(items, mode);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -274,10 +258,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery, Required] long positionTicks)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new SeekGroupRequest()
-            {
-                PositionTicks = positionTicks
-            };
+            var syncPlayRequest = new SeekGroupRequest(positionTicks);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -305,23 +286,11 @@ namespace Jellyfin.Api.Controllers
             IGroupPlaybackRequest syncPlayRequest;
             if (!bufferingDone)
             {
-                syncPlayRequest = new BufferGroupRequest()
-                {
-                    When = when,
-                    PositionTicks = positionTicks,
-                    IsPlaying = isPlaying,
-                    PlaylistItemId = playlistItemId
-                };
+                syncPlayRequest = new BufferGroupRequest(when, positionTicks, isPlaying, playlistItemId);
             }
             else
             {
-                syncPlayRequest = new ReadyGroupRequest()
-                {
-                    When = when,
-                    PositionTicks = positionTicks,
-                    IsPlaying = isPlaying,
-                    PlaylistItemId = playlistItemId
-                };
+                syncPlayRequest = new ReadyGroupRequest(when, positionTicks, isPlaying, playlistItemId);
             }
 
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
@@ -340,10 +309,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery, Required] bool ignoreWait)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new IgnoreWaitGroupRequest()
-            {
-                IgnoreWait = ignoreWait
-            };
+            var syncPlayRequest = new IgnoreWaitGroupRequest(ignoreWait);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -360,10 +326,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery, Required] string playlistItemId)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new NextTrackGroupRequest()
-            {
-                PlaylistItemId = playlistItemId
-            };
+            var syncPlayRequest = new NextTrackGroupRequest(playlistItemId);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -380,10 +343,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery, Required] string playlistItemId)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new PreviousTrackGroupRequest()
-            {
-                PlaylistItemId = playlistItemId
-            };
+            var syncPlayRequest = new PreviousTrackGroupRequest(playlistItemId);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -397,13 +357,10 @@ namespace Jellyfin.Api.Controllers
         [HttpPost("SetRepeatMode")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SyncPlaySetRepeatMode(
-            [FromQuery, Required] string mode)
+            [FromQuery, Required] GroupRepeatMode mode)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new SetRepeatModeGroupRequest()
-            {
-                Mode = mode
-            };
+            var syncPlayRequest = new SetRepeatModeGroupRequest(mode);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -417,13 +374,10 @@ namespace Jellyfin.Api.Controllers
         [HttpPost("SetShuffleMode")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SyncPlaySetShuffleMode(
-            [FromQuery, Required] string mode)
+            [FromQuery, Required] GroupShuffleMode mode)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new SetShuffleModeGroupRequest()
-            {
-                Mode = mode
-            };
+            var syncPlayRequest = new SetShuffleModeGroupRequest(mode);
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }
@@ -440,10 +394,7 @@ namespace Jellyfin.Api.Controllers
             [FromQuery, Required] double ping)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
-            var syncPlayRequest = new PingGroupRequest()
-            {
-                Ping = Convert.ToInt64(ping)
-            };
+            var syncPlayRequest = new PingGroupRequest(Convert.ToInt64(ping));
             _syncPlayManager.HandleRequest(currentSession, syncPlayRequest, CancellationToken.None);
             return NoContent();
         }

+ 7 - 3
MediaBrowser.Controller/SyncPlay/GroupStates/AbstractGroupState.cs

@@ -1,10 +1,10 @@
-using System;
 using System.Threading;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
 using MediaBrowser.Model.SyncPlay;
 using Microsoft.Extensions.Logging;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.GroupStates
 {
     /// <summary>
     /// Class AbstractGroupState.
@@ -104,7 +104,11 @@ namespace MediaBrowser.Controller.SyncPlay
                 return;
             }
 
-            var reason = request.Mode.Equals("next", StringComparison.OrdinalIgnoreCase) ? PlayQueueUpdateReason.QueueNext : PlayQueueUpdateReason.Queue;
+            var reason = request.Mode switch
+            {
+                GroupQueueMode.QueueNext => PlayQueueUpdateReason.QueueNext,
+                _ => PlayQueueUpdateReason.Queue
+            };
             var playQueueUpdate = context.GetPlayQueueUpdate(reason);
             var update = context.NewSyncPlayGroupUpdate(GroupUpdateType.PlayQueue, playQueueUpdate);
             context.SendGroupUpdate(session, SyncPlayBroadcastType.AllGroup, update, cancellationToken);

+ 2 - 1
MediaBrowser.Controller/SyncPlay/GroupStates/IdleGroupState.cs

@@ -1,9 +1,10 @@
 using System.Threading;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
 using MediaBrowser.Model.SyncPlay;
 using Microsoft.Extensions.Logging;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.GroupStates
 {
     /// <summary>
     /// Class IdleGroupState.

+ 2 - 1
MediaBrowser.Controller/SyncPlay/GroupStates/PausedGroupState.cs

@@ -1,10 +1,11 @@
 using System;
 using System.Threading;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
 using MediaBrowser.Model.SyncPlay;
 using Microsoft.Extensions.Logging;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.GroupStates
 {
     /// <summary>
     /// Class PausedGroupState.

+ 2 - 1
MediaBrowser.Controller/SyncPlay/GroupStates/PlayingGroupState.cs

@@ -1,10 +1,11 @@
 using System;
 using System.Threading;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
 using MediaBrowser.Model.SyncPlay;
 using Microsoft.Extensions.Logging;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.GroupStates
 {
     /// <summary>
     /// Class PlayingGroupState.

+ 3 - 3
MediaBrowser.Controller/SyncPlay/GroupStates/WaitingGroupState.cs

@@ -1,10 +1,11 @@
 using System;
 using System.Threading;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
 using MediaBrowser.Model.SyncPlay;
 using Microsoft.Extensions.Logging;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.GroupStates
 {
     /// <summary>
     /// Class WaitingGroupState.
@@ -464,8 +465,7 @@ namespace MediaBrowser.Controller.SyncPlay
                 {
                     // Others are still buffering, tell this client to pause when ready.
                     var command = context.NewSyncPlayCommand(SendCommandType.Pause);
-                    var pauseAtTime = currentTime.AddTicks(delayTicks);
-                    command.When = context.DateToUTCString(pauseAtTime);
+                    command.When = currentTime.AddTicks(delayTicks);
                     context.SendCommand(session, SyncPlayBroadcastType.CurrentSession, command, cancellationToken);
 
                     Logger.LogInformation("HandleRequest: {0} in group {1}, others still buffering, {2} will pause when ready in {3} seconds.", request.Type, context.GroupId.ToString(), session.Id, TimeSpan.FromTicks(delayTicks).TotalSeconds);

+ 1 - 0
MediaBrowser.Controller/SyncPlay/IGroupController.cs

@@ -2,6 +2,7 @@ using System;
 using System.Threading;
 using Jellyfin.Data.Entities;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Controller.SyncPlay.Queue;
 using MediaBrowser.Model.SyncPlay;
 
 namespace MediaBrowser.Controller.SyncPlay

+ 1 - 0
MediaBrowser.Controller/SyncPlay/IGroupState.cs

@@ -1,5 +1,6 @@
 using System.Threading;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Controller.SyncPlay.PlaybackRequests;
 using MediaBrowser.Model.SyncPlay;
 
 namespace MediaBrowser.Controller.SyncPlay

+ 4 - 10
MediaBrowser.Controller/SyncPlay/IGroupStateContext.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Controller.SyncPlay.Queue;
 using MediaBrowser.Model.SyncPlay;
 
 namespace MediaBrowser.Controller.SyncPlay
@@ -97,13 +98,6 @@ namespace MediaBrowser.Controller.SyncPlay
         /// <returns>The group update.</returns>
         GroupUpdate<T> NewSyncPlayGroupUpdate<T>(GroupUpdateType type, T data);
 
-        /// <summary>
-        /// Converts DateTime to UTC string.
-        /// </summary>
-        /// <param name="dateTime">The date to convert.</param>
-        /// <returns>The UTC string.</returns>
-        string DateToUTCString(DateTime dateTime);
-
         /// <summary>
         /// Sanitizes the PositionTicks, considers the current playing item when available.
         /// </summary>
@@ -187,7 +181,7 @@ namespace MediaBrowser.Controller.SyncPlay
         /// <param name="newItems">The new items to add to the play queue.</param>
         /// <param name="mode">The mode with which the items will be added.</param>
         /// <returns><c>true</c> if the play queue has been changed; <c>false</c> if something went wrong.</returns>
-        bool AddToPlayQueue(IEnumerable<Guid> newItems, string mode);
+        bool AddToPlayQueue(IEnumerable<Guid> newItems, GroupQueueMode mode);
 
         /// <summary>
         /// Restarts current item in play queue.
@@ -210,13 +204,13 @@ namespace MediaBrowser.Controller.SyncPlay
         /// Sets the repeat mode.
         /// </summary>
         /// <param name="mode">The new mode.</param>
-        void SetRepeatMode(string mode);
+        void SetRepeatMode(GroupRepeatMode mode);
 
         /// <summary>
         /// Sets the shuffle mode.
         /// </summary>
         /// <param name="mode">The new mode.</param>
-        void SetShuffleMode(string mode);
+        void SetShuffleMode(GroupShuffleMode mode);
 
         /// <summary>
         /// Creates a play queue update.

+ 24 - 9
MediaBrowser.Controller/SyncPlay/PlaybackRequests/BufferGroupRequest.cs

@@ -3,7 +3,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class BufferGroupRequest.
@@ -11,28 +11,43 @@ namespace MediaBrowser.Controller.SyncPlay
     public class BufferGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets when the request has been made by the client.
+        /// Initializes a new instance of the <see cref="BufferGroupRequest"/> class.
+        /// </summary>
+        /// <param name="when">When the request has been made, as reported by the client.</param>
+        /// <param name="positionTicks">The position ticks.</param>
+        /// <param name="isPlaying">Whether the client playback is unpaused.</param>
+        /// <param name="playlistItemId">The playlist item identifier of the playing item.</param>
+        public BufferGroupRequest(DateTime when, long positionTicks, bool isPlaying, string playlistItemId)
+        {
+            When = when;
+            PositionTicks = positionTicks;
+            IsPlaying = isPlaying;
+            PlaylistItemId = playlistItemId;
+        }
+
+        /// <summary>
+        /// Gets when the request has been made by the client.
         /// </summary>
         /// <value>The date of the request.</value>
-        public DateTime When { get; set; }
+        public DateTime When { get; }
 
         /// <summary>
-        /// Gets or sets the position ticks.
+        /// Gets the position ticks.
         /// </summary>
         /// <value>The position ticks.</value>
-        public long PositionTicks { get; set; }
+        public long PositionTicks { get; }
 
         /// <summary>
-        /// Gets or sets a value indicating whether the client playback is unpaused.
+        /// Gets a value indicating whether the client playback is unpaused.
         /// </summary>
         /// <value>The client playback status.</value>
-        public bool IsPlaying { get; set; }
+        public bool IsPlaying { get; }
 
         /// <summary>
-        /// Gets or sets the playlist item identifier of the playing item.
+        /// Gets the playlist item identifier of the playing item.
         /// </summary>
         /// <value>The playlist item identifier.</value>
-        public string PlaylistItemId { get; set; }
+        public string PlaylistItemId { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.Buffer;

+ 12 - 3
MediaBrowser.Controller/SyncPlay/PlaybackRequests/IgnoreWaitGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class IgnoreWaitGroupRequest.
@@ -10,10 +10,19 @@ namespace MediaBrowser.Controller.SyncPlay
     public class IgnoreWaitGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets a value indicating whether the client should be ignored.
+        /// Initializes a new instance of the <see cref="IgnoreWaitGroupRequest"/> class.
+        /// </summary>
+        /// <param name="ignoreWait">Whether the client should be ignored.</param>
+        public IgnoreWaitGroupRequest(bool ignoreWait)
+        {
+            IgnoreWait = ignoreWait;
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether the client should be ignored.
         /// </summary>
         /// <value>The client group-wait status.</value>
-        public bool IgnoreWait { get; set; }
+        public bool IgnoreWait { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.IgnoreWait;

+ 16 - 5
MediaBrowser.Controller/SyncPlay/PlaybackRequests/MovePlaylistItemGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class MovePlaylistItemGroupRequest.
@@ -10,16 +10,27 @@ namespace MediaBrowser.Controller.SyncPlay
     public class MovePlaylistItemGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets the playlist identifier of the item.
+        /// Initializes a new instance of the <see cref="MovePlaylistItemGroupRequest"/> class.
+        /// </summary>
+        /// <param name="playlistItemId">The playlist identifier of the item.</param>
+        /// <param name="newIndex">The new position.</param>
+        public MovePlaylistItemGroupRequest(string playlistItemId, int newIndex)
+        {
+            PlaylistItemId = playlistItemId;
+            NewIndex = newIndex;
+        }
+
+        /// <summary>
+        /// Gets the playlist identifier of the item.
         /// </summary>
         /// <value>The playlist identifier of the item.</value>
-        public string PlaylistItemId { get; set; }
+        public string PlaylistItemId { get; }
 
         /// <summary>
-        /// Gets or sets the new position.
+        /// Gets the new position.
         /// </summary>
         /// <value>The new position.</value>
-        public int NewIndex { get; set; }
+        public int NewIndex { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.MovePlaylistItem;

+ 12 - 3
MediaBrowser.Controller/SyncPlay/PlaybackRequests/NextTrackGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class NextTrackGroupRequest.
@@ -10,10 +10,19 @@ namespace MediaBrowser.Controller.SyncPlay
     public class NextTrackGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets the playing item identifier.
+        /// Initializes a new instance of the <see cref="NextTrackGroupRequest"/> class.
+        /// </summary>
+        /// <param name="playlistItemId">The playing item identifier.</param>
+        public NextTrackGroupRequest(string playlistItemId)
+        {
+            PlaylistItemId = playlistItemId;
+        }
+
+        /// <summary>
+        /// Gets the playing item identifier.
         /// </summary>
         /// <value>The playing item identifier.</value>
-        public string PlaylistItemId { get; set; }
+        public string PlaylistItemId { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.NextTrack;

+ 1 - 1
MediaBrowser.Controller/SyncPlay/PlaybackRequests/PauseGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class PauseGroupRequest.

+ 12 - 3
MediaBrowser.Controller/SyncPlay/PlaybackRequests/PingGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class PingGroupRequest.
@@ -10,10 +10,19 @@ namespace MediaBrowser.Controller.SyncPlay
     public class PingGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets the ping time.
+        /// Initializes a new instance of the <see cref="PingGroupRequest"/> class.
+        /// </summary>
+        /// <param name="ping">The ping time.</param>
+        public PingGroupRequest(long ping)
+        {
+            Ping = ping;
+        }
+
+        /// <summary>
+        /// Gets the ping time.
         /// </summary>
         /// <value>The ping time.</value>
-        public long Ping { get; set; }
+        public long Ping { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.Ping;

+ 22 - 7
MediaBrowser.Controller/SyncPlay/PlaybackRequests/PlayGroupRequest.cs

@@ -4,30 +4,45 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class PlayGroupRequest.
     /// </summary>
     public class PlayGroupRequest : IGroupPlaybackRequest
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PlayGroupRequest"/> class.
+        /// </summary>
+        /// <param name="playingQueue">The playing queue.</param>
+        /// <param name="playingItemPosition">The playing item position.</param>
+        /// <param name="startPositionTicks">The start position ticks.</param>
+        public PlayGroupRequest(Guid[] playingQueue, int playingItemPosition, long startPositionTicks)
+        {
+            var list = new List<Guid>();
+            list.AddRange(playingQueue);
+            PlayingQueue = list;
+            PlayingItemPosition = playingItemPosition;
+            StartPositionTicks = startPositionTicks;
+        }
+
         /// <summary>
         /// Gets the playing queue.
         /// </summary>
         /// <value>The playing queue.</value>
-        public List<Guid> PlayingQueue { get; } = new List<Guid>();
+        public IReadOnlyList<Guid> PlayingQueue { get; }
 
         /// <summary>
-        /// Gets or sets the playing item from the queue.
+        /// Gets the position of the playing item in the queue.
         /// </summary>
-        /// <value>The playing item.</value>
-        public int PlayingItemPosition { get; set; }
+        /// <value>The playing item position.</value>
+        public int PlayingItemPosition { get; }
 
         /// <summary>
-        /// Gets or sets the start position ticks.
+        /// Gets the start position ticks.
         /// </summary>
         /// <value>The start position ticks.</value>
-        public long StartPositionTicks { get; set; }
+        public long StartPositionTicks { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.Play;

+ 12 - 3
MediaBrowser.Controller/SyncPlay/PlaybackRequests/PreviousTrackGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class PreviousTrackGroupRequest.
@@ -10,10 +10,19 @@ namespace MediaBrowser.Controller.SyncPlay
     public class PreviousTrackGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets the playing item identifier.
+        /// Initializes a new instance of the <see cref="PreviousTrackGroupRequest"/> class.
+        /// </summary>
+        /// <param name="playlistItemId">The playing item identifier.</param>
+        public PreviousTrackGroupRequest(string playlistItemId)
+        {
+            PlaylistItemId = playlistItemId;
+        }
+
+        /// <summary>
+        /// Gets the playing item identifier.
         /// </summary>
         /// <value>The playing item identifier.</value>
-        public string PlaylistItemId { get; set; }
+        public string PlaylistItemId { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.PreviousTrack;

+ 20 - 7
MediaBrowser.Controller/SyncPlay/PlaybackRequests/QueueGroupRequest.cs

@@ -4,7 +4,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class QueueGroupRequest.
@@ -12,16 +12,29 @@ namespace MediaBrowser.Controller.SyncPlay
     public class QueueGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets the items to queue.
+        /// Initializes a new instance of the <see cref="QueueGroupRequest"/> class.
         /// </summary>
-        /// <value>The items to queue.</value>
-        public List<Guid> ItemIds { get; } = new List<Guid>();
+        /// <param name="items">The items to add to the queue.</param>
+        /// <param name="mode">The enqueue mode.</param>
+        public QueueGroupRequest(Guid[] items, GroupQueueMode mode)
+        {
+            var list = new List<Guid>();
+            list.AddRange(items);
+            ItemIds = list;
+            Mode = mode;
+        }
+
+        /// <summary>
+        /// Gets the items to enqueue.
+        /// </summary>
+        /// <value>The items to enqueue.</value>
+        public IReadOnlyList<Guid> ItemIds { get; }
 
         /// <summary>
-        /// Gets or sets the mode in which to add the new items.
+        /// Gets the mode in which to add the new items.
         /// </summary>
-        /// <value>The mode.</value>
-        public string Mode { get; set; }
+        /// <value>The enqueue mode.</value>
+        public GroupQueueMode Mode { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.Queue;

+ 24 - 9
MediaBrowser.Controller/SyncPlay/PlaybackRequests/ReadyGroupRequest.cs

@@ -3,7 +3,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class ReadyGroupRequest.
@@ -11,28 +11,43 @@ namespace MediaBrowser.Controller.SyncPlay
     public class ReadyGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets when the request has been made by the client.
+        /// Initializes a new instance of the <see cref="ReadyGroupRequest"/> class.
+        /// </summary>
+        /// <param name="when">When the request has been made, as reported by the client.</param>
+        /// <param name="positionTicks">The position ticks.</param>
+        /// <param name="isPlaying">Whether the client playback is unpaused.</param>
+        /// <param name="playlistItemId">The playlist item identifier of the playing item.</param>
+        public ReadyGroupRequest(DateTime when, long positionTicks, bool isPlaying, string playlistItemId)
+        {
+            When = when;
+            PositionTicks = positionTicks;
+            IsPlaying = isPlaying;
+            PlaylistItemId = playlistItemId;
+        }
+
+        /// <summary>
+        /// Gets when the request has been made by the client.
         /// </summary>
         /// <value>The date of the request.</value>
-        public DateTime When { get; set; }
+        public DateTime When { get; }
 
         /// <summary>
-        /// Gets or sets the position ticks.
+        /// Gets the position ticks.
         /// </summary>
         /// <value>The position ticks.</value>
-        public long PositionTicks { get; set; }
+        public long PositionTicks { get; }
 
         /// <summary>
-        /// Gets or sets a value indicating whether the client playback is unpaused.
+        /// Gets a value indicating whether the client playback is unpaused.
         /// </summary>
         /// <value>The client playback status.</value>
-        public bool IsPlaying { get; set; }
+        public bool IsPlaying { get; }
 
         /// <summary>
-        /// Gets or sets the playlist item identifier of the playing item.
+        /// Gets the playlist item identifier of the playing item.
         /// </summary>
         /// <value>The playlist item identifier.</value>
-        public string PlaylistItemId { get; set; }
+        public string PlaylistItemId { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.Ready;

+ 13 - 2
MediaBrowser.Controller/SyncPlay/PlaybackRequests/RemoveFromPlaylistGroupRequest.cs

@@ -3,18 +3,29 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class RemoveFromPlaylistGroupRequest.
     /// </summary>
     public class RemoveFromPlaylistGroupRequest : IGroupPlaybackRequest
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RemoveFromPlaylistGroupRequest"/> class.
+        /// </summary>
+        /// <param name="items">The playlist ids of the items to remove.</param>
+        public RemoveFromPlaylistGroupRequest(string[] items)
+        {
+            var list = new List<string>();
+            list.AddRange(items);
+            PlaylistItemIds = list;
+        }
+
         /// <summary>
         /// Gets the playlist identifiers ot the items.
         /// </summary>
         /// <value>The playlist identifiers ot the items.</value>
-        public List<string> PlaylistItemIds { get; } = new List<string>();
+        public IReadOnlyList<string> PlaylistItemIds { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.RemoveFromPlaylist;

+ 12 - 3
MediaBrowser.Controller/SyncPlay/PlaybackRequests/SeekGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class SeekGroupRequest.
@@ -10,10 +10,19 @@ namespace MediaBrowser.Controller.SyncPlay
     public class SeekGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets the position ticks.
+        /// Initializes a new instance of the <see cref="SeekGroupRequest"/> class.
+        /// </summary>
+        /// <param name="positionTicks">The position ticks.</param>
+        public SeekGroupRequest(long positionTicks)
+        {
+            PositionTicks = positionTicks;
+        }
+
+        /// <summary>
+        /// Gets the position ticks.
         /// </summary>
         /// <value>The position ticks.</value>
-        public long PositionTicks { get; set; }
+        public long PositionTicks { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.Seek;

+ 12 - 3
MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetPlaylistItemGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class SetPlaylistItemGroupRequest.
@@ -10,10 +10,19 @@ namespace MediaBrowser.Controller.SyncPlay
     public class SetPlaylistItemGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets the playlist identifier of the playing item.
+        /// Initializes a new instance of the <see cref="SetPlaylistItemGroupRequest"/> class.
+        /// </summary>
+        /// <param name="playlistItemId">The playlist identifier of the item.</param>
+        public SetPlaylistItemGroupRequest(string playlistItemId)
+        {
+            PlaylistItemId = playlistItemId;
+        }
+
+        /// <summary>
+        /// Gets the playlist identifier of the playing item.
         /// </summary>
         /// <value>The playlist identifier of the playing item.</value>
-        public string PlaylistItemId { get; set; }
+        public string PlaylistItemId { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.SetPlaylistItem;

+ 12 - 3
MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetRepeatModeGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class SetRepeatModeGroupRequest.
@@ -10,10 +10,19 @@ namespace MediaBrowser.Controller.SyncPlay
     public class SetRepeatModeGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets the repeat mode.
+        /// Initializes a new instance of the <see cref="SetRepeatModeGroupRequest"/> class.
+        /// </summary>
+        /// <param name="mode">The repeat mode.</param>
+        public SetRepeatModeGroupRequest(GroupRepeatMode mode)
+        {
+            Mode = mode;
+        }
+
+        /// <summary>
+        /// Gets the repeat mode.
         /// </summary>
         /// <value>The repeat mode.</value>
-        public string Mode { get; set; }
+        public GroupRepeatMode Mode { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.SetRepeatMode;

+ 12 - 3
MediaBrowser.Controller/SyncPlay/PlaybackRequests/SetShuffleModeGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class SetShuffleModeGroupRequest.
@@ -10,10 +10,19 @@ namespace MediaBrowser.Controller.SyncPlay
     public class SetShuffleModeGroupRequest : IGroupPlaybackRequest
     {
         /// <summary>
-        /// Gets or sets the shuffle mode.
+        /// Initializes a new instance of the <see cref="SetShuffleModeGroupRequest"/> class.
+        /// </summary>
+        /// <param name="mode">The shuffle mode.</param>
+        public SetShuffleModeGroupRequest(GroupShuffleMode mode)
+        {
+            Mode = mode;
+        }
+
+        /// <summary>
+        /// Gets the shuffle mode.
         /// </summary>
         /// <value>The shuffle mode.</value>
-        public string Mode { get; set; }
+        public GroupShuffleMode Mode { get; }
 
         /// <inheritdoc />
         public PlaybackRequestType Type { get; } = PlaybackRequestType.SetShuffleMode;

+ 1 - 1
MediaBrowser.Controller/SyncPlay/PlaybackRequests/StopGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class StopGroupRequest.

+ 1 - 1
MediaBrowser.Controller/SyncPlay/PlaybackRequests/UnpauseGroupRequest.cs

@@ -2,7 +2,7 @@ using System.Threading;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.PlaybackRequests
 {
     /// <summary>
     /// Class UnpauseGroupRequest.

+ 3 - 6
MediaBrowser.Controller/SyncPlay/Queue/PlayQueueManager.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using MediaBrowser.Model.SyncPlay;
 
-namespace MediaBrowser.Controller.SyncPlay
+namespace MediaBrowser.Controller.SyncPlay.Queue
 {
     /// <summary>
     /// Class PlayQueueManager.
@@ -563,11 +563,8 @@ namespace MediaBrowser.Controller.SyncPlay
             var list = new List<QueueItem>();
             foreach (var item in items)
             {
-                list.Add(new QueueItem()
-                {
-                    ItemId = item,
-                    PlaylistItemId = "syncPlayItem" + GetNextProgressiveId()
-                });
+                var queueItem = new QueueItem(item, "syncPlayItem" + GetNextProgressiveId());
+                list.Add(queueItem);
             }
 
             return list;

+ 12 - 3
MediaBrowser.Model/SyncPlay/GroupInfoDto.cs

@@ -1,5 +1,4 @@
-#nullable disable
-
+using System;
 using System.Collections.Generic;
 
 namespace MediaBrowser.Model.SyncPlay
@@ -9,6 +8,16 @@ namespace MediaBrowser.Model.SyncPlay
     /// </summary>
     public class GroupInfoDto
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GroupInfoDto"/> class.
+        /// </summary>
+        public GroupInfoDto()
+        {
+            GroupId = string.Empty;
+            GroupName = string.Empty;
+            Participants = new List<string>();
+        }
+
         /// <summary>
         /// Gets or sets the group identifier.
         /// </summary>
@@ -37,6 +46,6 @@ namespace MediaBrowser.Model.SyncPlay
         /// Gets or sets the date when this dto has been updated.
         /// </summary>
         /// <value>The date when this dto has been updated.</value>
-        public string LastUpdatedAt { get; set; }
+        public DateTime LastUpdatedAt { get; set; }
     }
 }

+ 18 - 0
MediaBrowser.Model/SyncPlay/GroupQueueMode.cs

@@ -0,0 +1,18 @@
+namespace MediaBrowser.Model.SyncPlay
+{
+    /// <summary>
+    /// Enum GroupQueueMode.
+    /// </summary>
+    public enum GroupQueueMode
+    {
+        /// <summary>
+        /// Insert items at the end of the queue.
+        /// </summary>
+        Queue = 0,
+
+        /// <summary>
+        /// Insert items after the currently playing item.
+        /// </summary>
+        QueueNext = 1
+    }
+}

+ 5 - 5
MediaBrowser.Model/SyncPlay/GroupRequestType.cs

@@ -8,26 +8,26 @@ namespace MediaBrowser.Model.SyncPlay
         /// <summary>
         /// A user is requesting to create a new group.
         /// </summary>
-        NewGroup,
+        NewGroup = 0,
 
         /// <summary>
         /// A user is requesting to join a group.
         /// </summary>
-        JoinGroup,
+        JoinGroup = 1,
 
         /// <summary>
         /// A user is requesting to leave a group.
         /// </summary>
-        LeaveGroup,
+        LeaveGroup = 2,
 
         /// <summary>
         /// A user is requesting the list of available groups.
         /// </summary>
-        ListGroups,
+        ListGroups = 3,
 
         /// <summary>
         /// A user is sending a playback command to a group.
         /// </summary>
-        Playback
+        Playback = 4
     }
 }

+ 4 - 4
MediaBrowser.Model/SyncPlay/GroupStateType.cs

@@ -8,21 +8,21 @@ namespace MediaBrowser.Model.SyncPlay
         /// <summary>
         /// The group is in idle state. No media is playing.
         /// </summary>
-        Idle,
+        Idle = 0,
 
         /// <summary>
         /// The group is in wating state. Playback is paused. Will start playing when users are ready.
         /// </summary>
-        Waiting,
+        Waiting = 1,
 
         /// <summary>
         /// The group is in paused state. Playback is paused. Will resume on play command.
         /// </summary>
-        Paused,
+        Paused = 2,
 
         /// <summary>
         /// The group is in playing state. Playback is advancing.
         /// </summary>
-        Playing
+        Playing = 3
     }
 }

+ 8 - 2
MediaBrowser.Model/SyncPlay/NewGroupRequest.cs

@@ -1,5 +1,3 @@
-#nullable disable
-
 namespace MediaBrowser.Model.SyncPlay
 {
     /// <summary>
@@ -7,6 +5,14 @@ namespace MediaBrowser.Model.SyncPlay
     /// </summary>
     public class NewGroupRequest
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="NewGroupRequest"/> class.
+        /// </summary>
+        public NewGroupRequest()
+        {
+            GroupName = string.Empty;
+        }
+
         /// <summary>
         /// Gets or sets the group name.
         /// </summary>

+ 10 - 3
MediaBrowser.Model/SyncPlay/PlayQueueUpdate.cs

@@ -1,5 +1,4 @@
-#nullable disable
-
+using System;
 using System.Collections.Generic;
 
 namespace MediaBrowser.Model.SyncPlay
@@ -9,6 +8,14 @@ namespace MediaBrowser.Model.SyncPlay
     /// </summary>
     public class PlayQueueUpdate
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PlayQueueUpdate"/> class.
+        /// </summary>
+        public PlayQueueUpdate()
+        {
+            Playlist = new List<QueueItem>();
+        }
+
         /// <summary>
         /// Gets or sets the request type that originated this update.
         /// </summary>
@@ -19,7 +26,7 @@ namespace MediaBrowser.Model.SyncPlay
         /// Gets or sets the UTC time of the last change to the playing queue.
         /// </summary>
         /// <value>The UTC time of the last change to the playing queue.</value>
-        public string LastUpdate { get; set; }
+        public DateTime LastUpdate { get; set; }
 
         /// <summary>
         /// Gets or sets the playlist.

+ 2 - 2
MediaBrowser.Model/SyncPlay/PlayQueueUpdateReason.cs

@@ -26,12 +26,12 @@ namespace MediaBrowser.Model.SyncPlay
         MoveItem = 3,
 
         /// <summary>
-        /// A user is making changes to the queue.
+        /// A user is adding items the queue.
         /// </summary>
         Queue = 4,
 
         /// <summary>
-        /// A user is making changes to the queue.
+        /// A user is adding items to the queue, after the currently playing item.
         /// </summary>
         QueueNext = 5,
 

+ 15 - 6
MediaBrowser.Model/SyncPlay/QueueItem.cs

@@ -1,5 +1,3 @@
-#nullable disable
-
 using System;
 
 namespace MediaBrowser.Model.SyncPlay
@@ -10,15 +8,26 @@ namespace MediaBrowser.Model.SyncPlay
     public class QueueItem
     {
         /// <summary>
-        /// Gets or sets the item identifier.
+        /// Initializes a new instance of the <see cref="QueueItem"/> class.
+        /// </summary>
+        /// <param name="itemId">The item identifier.</param>
+        /// <param name="playlistItemId">The playlist identifier of the item.</param>
+        public QueueItem(Guid itemId, string playlistItemId)
+        {
+            ItemId = itemId;
+            PlaylistItemId = playlistItemId;
+        }
+
+        /// <summary>
+        /// Gets the item identifier.
         /// </summary>
         /// <value>The item identifier.</value>
-        public Guid ItemId { get; set; }
+        public Guid ItemId { get; }
 
         /// <summary>
-        /// Gets or sets the playlist identifier of the item.
+        /// Gets the playlist identifier of the item.
         /// </summary>
         /// <value>The playlist identifier of the item.</value>
-        public string PlaylistItemId { get; set; }
+        public string PlaylistItemId { get; }
     }
 }

+ 12 - 3
MediaBrowser.Model/SyncPlay/SendCommand.cs

@@ -1,4 +1,4 @@
-#nullable disable
+using System;
 
 namespace MediaBrowser.Model.SyncPlay
 {
@@ -7,6 +7,15 @@ namespace MediaBrowser.Model.SyncPlay
     /// </summary>
     public class SendCommand
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SendCommand"/> class.
+        /// </summary>
+        public SendCommand()
+        {
+            GroupId = string.Empty;
+            PlaylistItemId = string.Empty;
+        }
+
         /// <summary>
         /// Gets or sets the group identifier.
         /// </summary>
@@ -23,7 +32,7 @@ namespace MediaBrowser.Model.SyncPlay
         /// Gets or sets the UTC time when to execute the command.
         /// </summary>
         /// <value>The UTC time when to execute the command.</value>
-        public string When { get; set; }
+        public DateTime When { get; set; }
 
         /// <summary>
         /// Gets or sets the position ticks.
@@ -41,6 +50,6 @@ namespace MediaBrowser.Model.SyncPlay
         /// Gets or sets the UTC time when this command has been emitted.
         /// </summary>
         /// <value>The UTC time when this command has been emitted.</value>
-        public string EmittedAt { get; set; }
+        public DateTime EmittedAt { get; set; }
     }
 }