diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index 590fd6f06..271e5bbd6 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -1,9 +1,13 @@ -using MediaBrowser.Controller.Dto; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Session; using ServiceStack.ServiceHost; +using System; using System.Collections.Generic; using System.Linq; +using System.Threading; namespace MediaBrowser.Api { @@ -14,11 +18,39 @@ namespace MediaBrowser.Api [Api(("Gets a list of sessions"))] public class GetSessions : IReturn> { + [ApiMember(Name = "SupportsRemoteControl", Description = "Optional. Filter by sessions that can be remote controlled.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] + public bool? SupportsRemoteControl { get; set; } + } + + [Route("/Sessions/{Id}/Viewing", "POST")] + [Api(("Instructs a session to browse to an item or view"))] + public class BrowseTo : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public Guid Id { get; set; } + /// - /// Gets or sets a value indicating whether this instance is recent. + /// Artist, Genre, Studio, Person, or any kind of BaseItem /// - /// true if this instance is recent; otherwise, false. - public bool IsRecent { get; set; } + /// The type of the item. + [ApiMember(Name = "ItemType", Description = "Only required if the item is an Artist, Genre, Studio, or Person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public string ItemType { get; set; } + + /// + /// Artist name, genre name, item Id, etc + /// + /// The item identifier. + [ApiMember(Name = "ItemIdentifier", Description = "The Id of the item, unless it is an Artist, Genre, Studio, or Person, in which case it should be the name.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string ItemIdentifier { get; set; } + + /// + /// Gets or sets the context (Movies, Music, TvShows, etc) + /// Applicable to genres, studios and persons only because the context of items and artists can be inferred. + /// This is optional to supply and clients are free to ignore it. + /// + /// The context. + [ApiMember(Name = "Context", Description = "The navigation context for the client (movies, music, tvshows, games etc). This is optional to supply and clients are free to ignore it.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public string Context { get; set; } } /// @@ -47,9 +79,31 @@ namespace MediaBrowser.Api /// System.Object. public object Get(GetSessions request) { - var result = request.IsRecent ? _sessionManager.RecentConnections : _sessionManager.AllConnections; + var result = _sessionManager.Sessions.Where(i => i.IsActive); + + if (request.SupportsRemoteControl.HasValue) + { + result = result.Where(i => i.IsActive == request.SupportsRemoteControl.Value); + } return ToOptimizedResult(result.Select(SessionInfoDtoBuilder.GetSessionInfoDto).ToList()); } + + public void Post(BrowseTo request) + { + var session = _sessionManager.Sessions.FirstOrDefault(i => i.Id == request.Id); + + if (session == null) + { + throw new ResourceNotFoundException(string.Format("Session {0} not found.", request.Id)); + } + + session.WebSocket.SendAsync(new WebSocketMessage + { + MessageType = "Browse", + Data = request + + }, CancellationToken.None); + } } } diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 53f2e9bca..3eadfd4be 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -262,6 +262,9 @@ namespace MediaBrowser.Api.UserLibrary /// The position ticks. [ApiMember(Name = "PositionTicks", Description = "Optional. The current position, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")] public long? PositionTicks { get; set; } + + [ApiMember(Name = "IsPaused", Description = "Indicates if the player is paused.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] + public bool IsPaused { get; set; } } /// @@ -715,7 +718,7 @@ namespace MediaBrowser.Api.UserLibrary if (auth != null) { - var task = _sessionManager.OnPlaybackProgress(user, item, request.PositionTicks, auth["Client"], auth["DeviceId"], auth["Device"] ?? string.Empty); + var task = _sessionManager.OnPlaybackProgress(user, item, request.PositionTicks, request.IsPaused, auth["Client"], auth["DeviceId"], auth["Device"] ?? string.Empty); Task.WaitAll(task); } diff --git a/MediaBrowser.Controller/Dto/SessionInfoDtoBuilder.cs b/MediaBrowser.Controller/Dto/SessionInfoDtoBuilder.cs index 850af573f..27a237ba7 100644 --- a/MediaBrowser.Controller/Dto/SessionInfoDtoBuilder.cs +++ b/MediaBrowser.Controller/Dto/SessionInfoDtoBuilder.cs @@ -1,5 +1,4 @@ using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Session; namespace MediaBrowser.Controller.Dto @@ -23,7 +22,12 @@ namespace MediaBrowser.Controller.Dto DeviceName = session.DeviceName, Id = session.Id, LastActivityDate = session.LastActivityDate, - NowPlayingPositionTicks = session.NowPlayingPositionTicks + NowPlayingPositionTicks = session.NowPlayingPositionTicks, + SupportsRemoteControl = session.SupportsRemoteControl, + IsPaused = session.IsPaused, + NowViewingContext = session.NowViewingContext, + NowViewingItemIdentifier = session.NowViewingItemIdentifier, + NowViewingItemType = session.NowViewingItemType }; if (session.NowPlayingItem != null) @@ -36,9 +40,6 @@ namespace MediaBrowser.Controller.Dto dto.UserId = session.UserId.Value.ToString("N"); } - dto.SupportsRemoteControl = session.WebSocket != null && - session.WebSocket.State == WebSocketState.Open; - return dto; } } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 66facdf6d..8227170d4 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -3,7 +3,6 @@ using MediaBrowser.Controller.Library; using System; using System.Collections.Generic; using System.Threading.Tasks; -using MediaBrowser.Model.Session; namespace MediaBrowser.Controller.Session { @@ -28,16 +27,10 @@ namespace MediaBrowser.Controller.Session event EventHandler PlaybackStopped; /// - /// Gets all connections. + /// Gets the sessions. /// - /// All connections. - IEnumerable AllConnections { get; } - - /// - /// Gets the active connections. - /// - /// The active connections. - IEnumerable RecentConnections { get; } + /// The sessions. + IEnumerable Sessions { get; } /// /// Logs the user activity. @@ -67,12 +60,13 @@ namespace MediaBrowser.Controller.Session /// The user. /// The item. /// The position ticks. + /// if set to true [is paused]. /// Type of the client. /// The device id. /// Name of the device. /// Task. /// - Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, string clientType, string deviceId, string deviceName); + Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, bool isPaused, string clientType, string deviceId, string deviceName); /// /// Used to report that playback has ended for an item diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 21c65df97..93ef4f694 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Net; using System; namespace MediaBrowser.Controller.Session @@ -39,6 +40,24 @@ namespace MediaBrowser.Controller.Session /// The name of the device. public string DeviceName { get; set; } + /// + /// Gets or sets the now viewing context. + /// + /// The now viewing context. + public string NowViewingContext { get; set; } + + /// + /// Gets or sets the type of the now viewing item. + /// + /// The type of the now viewing item. + public string NowViewingItemType { get; set; } + + /// + /// Gets or sets the now viewing item identifier. + /// + /// The now viewing item identifier. + public string NowViewingItemIdentifier { get; set; } + /// /// Gets or sets the now playing item. /// @@ -51,6 +70,12 @@ namespace MediaBrowser.Controller.Session /// The now playing position ticks. public long? NowPlayingPositionTicks { get; set; } + /// + /// Gets or sets a value indicating whether this instance is paused. + /// + /// true if this instance is paused; otherwise, false. + public bool? IsPaused { get; set; } + /// /// Gets or sets the device id. /// @@ -62,5 +87,34 @@ namespace MediaBrowser.Controller.Session /// /// The web socket. public IWebSocketConnection WebSocket { get; set; } + + /// + /// Gets a value indicating whether this instance is active. + /// + /// true if this instance is active; otherwise, false. + public bool IsActive + { + get + { + if (WebSocket != null) + { + return WebSocket.State == WebSocketState.Open; + } + + return (DateTime.UtcNow - LastActivityDate).TotalMinutes <= 5; + } + } + + /// + /// Gets a value indicating whether [supports remote control]. + /// + /// true if [supports remote control]; otherwise, false. + public bool SupportsRemoteControl + { + get + { + return WebSocket != null && WebSocket.State == WebSocketState.Open; + } + } } } diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs index 0548876a1..2b9c1a64e 100644 --- a/MediaBrowser.Model/Session/SessionInfoDto.cs +++ b/MediaBrowser.Model/Session/SessionInfoDto.cs @@ -29,12 +29,36 @@ namespace MediaBrowser.Model.Session /// The last activity date. public DateTime LastActivityDate { get; set; } + /// + /// Gets or sets the now viewing context. + /// + /// The now viewing context. + public string NowViewingContext { get; set; } + + /// + /// Gets or sets the type of the now viewing item. + /// + /// The type of the now viewing item. + public string NowViewingItemType { get; set; } + + /// + /// Gets or sets the now viewing item identifier. + /// + /// The now viewing item identifier. + public string NowViewingItemIdentifier { get; set; } + /// /// Gets or sets the name of the device. /// /// The name of the device. public string DeviceName { get; set; } + /// + /// Gets or sets a value indicating whether this instance is paused. + /// + /// true if this instance is paused; otherwise, false. + public bool? IsPaused { get; set; } + /// /// Gets or sets the now playing item. /// diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 45515b81f..3474f2e05 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -207,7 +207,9 @@ - + + PreserveNewest + PreserveNewest diff --git a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs index 5a074d194..6b6826bdc 100644 --- a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs +++ b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager /// /// The _send semaphore /// - private readonly SemaphoreSlim _sendSemaphore = new SemaphoreSlim(1,1); + private readonly SemaphoreSlim _sendSemaphore = new SemaphoreSlim(1, 1); /// /// The logger @@ -100,7 +100,13 @@ namespace MediaBrowser.Server.Implementations.ServerManager using (var memoryStream = new MemoryStream(bytes)) { - info = (WebSocketMessageInfo)_jsonSerializer.DeserializeFromStream(memoryStream, typeof(WebSocketMessageInfo)); + var stub = (WebSocketMessage)_jsonSerializer.DeserializeFromStream(memoryStream, typeof(WebSocketMessage)); + + info = new WebSocketMessageInfo + { + MessageType = stub.MessageType, + Data = stub.Data == null ? null : stub.Data.ToString() + }; } info.Connection = this; @@ -163,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.ServerManager { throw new ArgumentNullException("cancellationToken"); } - + cancellationToken.ThrowIfCancellationRequested(); // Per msdn docs, attempting to send simultaneous messages will result in one failing. diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 99407e349..2f9c7e389 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1,14 +1,12 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Session; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -18,10 +16,19 @@ using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.Session { + /// + /// Class SessionManager + /// public class SessionManager : ISessionManager { + /// + /// The _user data repository + /// private readonly IUserDataRepository _userDataRepository; + /// + /// The _user repository + /// private readonly IUserRepository _userRepository; /// @@ -54,6 +61,13 @@ namespace MediaBrowser.Server.Implementations.Session /// public event EventHandler PlaybackStopped; + /// + /// Initializes a new instance of the class. + /// + /// The user data repository. + /// The configuration manager. + /// The logger. + /// The user repository. public SessionManager(IUserDataRepository userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository) { _userDataRepository = userDataRepository; @@ -66,20 +80,14 @@ namespace MediaBrowser.Server.Implementations.Session /// Gets all connections. /// /// All connections. - public IEnumerable AllConnections + public IEnumerable Sessions { - get { return _activeConnections.Values.OrderByDescending(c => c.LastActivityDate); } + get { return _activeConnections.Values.OrderByDescending(c => c.LastActivityDate).ToList(); } } /// - /// Gets the active connections. + /// The _true task result /// - /// The active connections. - public IEnumerable RecentConnections - { - get { return AllConnections.Where(c => (DateTime.UtcNow - c.LastActivityDate).TotalMinutes <= 5); } - } - private readonly Task _trueTaskResult = Task.FromResult(true); /// @@ -124,11 +132,13 @@ namespace MediaBrowser.Server.Implementations.Session /// The device id. /// Name of the device. /// The item. + /// if set to true [is paused]. /// The current position ticks. - private void UpdateNowPlayingItemId(User user, string clientType, string deviceId, string deviceName, BaseItem item, long? currentPositionTicks = null) + private void UpdateNowPlayingItemId(User user, string clientType, string deviceId, string deviceName, BaseItem item, bool isPaused, long? currentPositionTicks = null) { var conn = GetConnection(clientType, deviceId, deviceName, user); + conn.IsPaused = isPaused; conn.NowPlayingPositionTicks = currentPositionTicks; conn.NowPlayingItem = item; conn.LastActivityDate = DateTime.UtcNow; @@ -150,6 +160,7 @@ namespace MediaBrowser.Server.Implementations.Session { conn.NowPlayingItem = null; conn.NowPlayingPositionTicks = null; + conn.IsPaused = null; } } @@ -187,7 +198,8 @@ namespace MediaBrowser.Server.Implementations.Session /// Type of the client. /// The device id. /// Name of the device. - /// + /// + /// public void OnPlaybackStart(User user, BaseItem item, string clientType, string deviceId, string deviceName) { if (user == null) @@ -199,7 +211,7 @@ namespace MediaBrowser.Server.Implementations.Session throw new ArgumentNullException(); } - UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item); + UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, false); // Nothing to save here // Fire events to inform plugins @@ -216,12 +228,14 @@ namespace MediaBrowser.Server.Implementations.Session /// The user. /// The item. /// The position ticks. + /// if set to true [is paused]. /// Type of the client. /// The device id. /// Name of the device. /// Task. - /// - public async Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, string clientType, string deviceId, string deviceName) + /// + /// + public async Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, bool isPaused, string clientType, string deviceId, string deviceName) { if (user == null) { @@ -232,7 +246,7 @@ namespace MediaBrowser.Server.Implementations.Session throw new ArgumentNullException(); } - UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, positionTicks); + UpdateNowPlayingItemId(user, clientType, deviceId, deviceName, item, isPaused, positionTicks); var key = item.GetUserDataKey(); @@ -262,7 +276,8 @@ namespace MediaBrowser.Server.Implementations.Session /// The device id. /// Name of the device. /// Task. - /// + /// + /// public async Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, string clientType, string deviceId, string deviceName) { if (user == null) @@ -355,20 +370,5 @@ namespace MediaBrowser.Server.Implementations.Session data.LastPlayedDate = DateTime.UtcNow; } } - - /// - /// Identifies the web socket. - /// - /// The session id. - /// The web socket. - public void IdentifyWebSocket(Guid sessionId, IWebSocketConnection webSocket) - { - var session = AllConnections.FirstOrDefault(i => i.Id == sessionId); - - if (session != null) - { - session.WebSocket = webSocket; - } - } } } diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs index 59c79c23e..ed1280ea9 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs @@ -1,5 +1,9 @@ -using MediaBrowser.Common.Net; +using System.Globalization; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Logging; using System; using System.Linq; using System.Threading.Tasks; @@ -22,12 +26,26 @@ namespace MediaBrowser.Server.Implementations.Session private readonly ISessionManager _sessionManager; /// - /// Initializes a new instance of the class. + /// The _logger + /// + private readonly ILogger _logger; + + private readonly IUserManager _userManager; + private readonly ILibraryManager _libraryManager; + + /// + /// Initializes a new instance of the class. /// /// The session manager. - public SessionWebSocketListener(ISessionManager sessionManager) + /// The logger. + /// The library manager. + /// The user manager. + public SessionWebSocketListener(ISessionManager sessionManager, ILogger logger, ILibraryManager libraryManager, IUserManager userManager) { _sessionManager = sessionManager; + _logger = logger; + _libraryManager = libraryManager; + _userManager = userManager; } /// @@ -44,11 +62,87 @@ namespace MediaBrowser.Server.Implementations.Session var client = vals[0]; var deviceId = vals[1]; - var session = _sessionManager.AllConnections.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId) && string.Equals(i.Client, client)); + var session = _sessionManager.Sessions.FirstOrDefault(i => string.Equals(i.DeviceId, deviceId) && string.Equals(i.Client, client)); if (session != null) { - ((SessionManager)_sessionManager).IdentifyWebSocket(session.Id, message.Connection); + session.WebSocket = message.Connection; + } + } + else if (string.Equals(message.MessageType, "Context", StringComparison.OrdinalIgnoreCase)) + { + var session = _sessionManager.Sessions.FirstOrDefault(i => i.WebSocket == message.Connection); + + if (session != null) + { + var vals = message.Data.Split('|'); + + session.NowViewingItemType = vals[0]; + session.NowViewingItemIdentifier = vals[1]; + session.NowViewingContext = vals.Length > 2 ? vals[2] : null; + } + } + else if (string.Equals(message.MessageType, "PlaybackStart", StringComparison.OrdinalIgnoreCase)) + { + var session = _sessionManager.Sessions.FirstOrDefault(i => i.WebSocket == message.Connection); + + if (session != null && session.UserId.HasValue) + { + var item = DtoBuilder.GetItemByClientId(message.Data, _userManager, _libraryManager); + + _sessionManager.OnPlaybackStart(_userManager.GetUserById(session.UserId.Value), item, session.Client, session.DeviceId, session.DeviceName); + } + } + else if (string.Equals(message.MessageType, "PlaybackProgress", StringComparison.OrdinalIgnoreCase)) + { + var session = _sessionManager.Sessions.FirstOrDefault(i => i.WebSocket == message.Connection); + + if (session != null && session.UserId.HasValue) + { + var vals = message.Data.Split('|'); + + var item = DtoBuilder.GetItemByClientId(vals[0], _userManager, _libraryManager); + + long? positionTicks = null; + + if (vals.Length > 1) + { + long pos; + + if (long.TryParse(vals[1], out pos)) + { + positionTicks = pos; + } + } + + var isPaused = vals.Length > 2 && string.Equals(vals[2], "true", StringComparison.OrdinalIgnoreCase); + + _sessionManager.OnPlaybackProgress(_userManager.GetUserById(session.UserId.Value), item, positionTicks, isPaused, session.Client, session.DeviceId, session.DeviceName); + } + } + else if (string.Equals(message.MessageType, "PlaybackStopped", StringComparison.OrdinalIgnoreCase)) + { + var session = _sessionManager.Sessions.FirstOrDefault(i => i.WebSocket == message.Connection); + + if (session != null && session.UserId.HasValue) + { + var vals = message.Data.Split('|'); + + var item = DtoBuilder.GetItemByClientId(vals[0], _userManager, _libraryManager); + + long? positionTicks = null; + + if (vals.Length > 1) + { + long pos; + + if (long.TryParse(vals[1], out pos)) + { + positionTicks = pos; + } + } + + _sessionManager.OnPlaybackStopped(_userManager.GetUserById(session.UserId.Value), item, positionTicks, session.Client, session.DeviceId, session.DeviceName); } } diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index a0892060f..56c7b99f9 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -206,7 +206,7 @@ namespace MediaBrowser.WebDashboard.Api ILibraryManager libraryManager, ISessionManager connectionManager) { - var connections = connectionManager.RecentConnections.ToArray(); + var connections = connectionManager.Sessions.Where(i => i.IsActive).ToArray(); var dtoBuilder = new UserDtoBuilder(logger); diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 2982a40a9..999a7d918 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -2379,6 +2379,16 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) { throw new Error("null itemId"); } + if (self.isWebSocketOpen()) { + + var deferred = $.Deferred(); + + self.sendWebSocketMessage("PlaybackStart", itemId); + + deferred.resolveWith(null, []); + return deferred.promise(); + } + var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId); return self.ajax({ @@ -2392,7 +2402,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) { * @param {String} userId * @param {String} itemId */ - self.reportPlaybackProgress = function (userId, itemId, positionTicks) { + self.reportPlaybackProgress = function (userId, itemId, positionTicks, isPaused) { if (!userId) { throw new Error("null userId"); @@ -2402,6 +2412,16 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) { throw new Error("null itemId"); } + if (self.isWebSocketOpen()) { + + var deferred = $.Deferred(); + + self.sendWebSocketMessage("PlaybackProgress", itemId + "|" + (positionTicks == null ? "" : positionTicks) + "|" + (isPaused == null ? "" : isPaused)); + + deferred.resolveWith(null, []); + return deferred.promise(); + } + var params = { }; @@ -2433,6 +2453,16 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) { throw new Error("null itemId"); } + if (self.isWebSocketOpen()) { + + var deferred = $.Deferred(); + + self.sendWebSocketMessage("PlaybackStopped", itemId + "|" + (positionTicks == null ? "" : positionTicks)); + + deferred.resolveWith(null, []); + return deferred.promise(); + } + var params = { }; diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config index 8072ff77d..be1673780 100644 --- a/MediaBrowser.WebDashboard/packages.config +++ b/MediaBrowser.WebDashboard/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 56feae805..1feb82848 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.97 + 3.0.98 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,9 +12,9 @@ Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 0860c7c9c..85d2ca3c5 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.97 + 3.0.98 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index ed83cc8d8..5670f8a6c 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.97 + 3.0.98 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - +