diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index e688973f9..0e69c96d1 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -217,6 +217,9 @@ namespace MediaBrowser.Api [ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] public string SupportedCommands { get; set; } + + [ApiMember(Name = "SupportsMediaControl", Description = "Determines whether media can be played remotely.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")] + public bool SupportsMediaControl { get; set; } } /// @@ -258,6 +261,8 @@ namespace MediaBrowser.Api if (request.ControllableByUserId.HasValue) { + result = result.Where(i => i.SupportsMediaControl); + var user = _userManager.GetUserById(request.ControllableByUserId.Value); if (!user.Configuration.EnableRemoteControlOfOtherUsers) @@ -407,7 +412,9 @@ namespace MediaBrowser.Api { PlayableMediaTypes = request.PlayableMediaTypes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(), - SupportedCommands = request.SupportedCommands.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() + SupportedCommands = request.SupportedCommands.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(), + + SupportsMediaControl = request.SupportsMediaControl }); } diff --git a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs index 24ac48e83..014fd6f82 100644 --- a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs +++ b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs @@ -351,18 +351,21 @@ namespace MediaBrowser.Common.Implementations.IO throw new ArgumentNullException("to"); } - path = path.Replace(from, to, StringComparison.OrdinalIgnoreCase); + var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase); - if (to.IndexOf('/') != -1) + if (!string.Equals(newPath, path)) { - path = path.Replace('\\', '/'); - } - else - { - path = path.Replace('/', '\\'); + if (to.IndexOf('/') != -1) + { + newPath = path.Replace('\\', '/'); + } + else + { + newPath = path.Replace('/', '\\'); + } } - return path; + return newPath; } } } diff --git a/MediaBrowser.Common/Net/IWebSocket.cs b/MediaBrowser.Common/Net/IWebSocket.cs index 748c6642c..05f7975bc 100644 --- a/MediaBrowser.Common/Net/IWebSocket.cs +++ b/MediaBrowser.Common/Net/IWebSocket.cs @@ -10,6 +10,11 @@ namespace MediaBrowser.Common.Net /// public interface IWebSocket : IDisposable { + /// + /// Occurs when [closed]. + /// + event EventHandler Closed; + /// /// Gets or sets the state. /// diff --git a/MediaBrowser.Common/Net/IWebSocketConnection.cs b/MediaBrowser.Common/Net/IWebSocketConnection.cs index 514a52d96..9f9dfaeca 100644 --- a/MediaBrowser.Common/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Common/Net/IWebSocketConnection.cs @@ -7,6 +7,11 @@ namespace MediaBrowser.Common.Net { public interface IWebSocketConnection : IDisposable { + /// + /// Occurs when [closed]. + /// + event EventHandler Closed; + /// /// Gets the id. /// diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs index 1b50bad47..5f07b9ff8 100644 --- a/MediaBrowser.Controller/Session/ISessionController.cs +++ b/MediaBrowser.Controller/Session/ISessionController.cs @@ -13,6 +13,12 @@ namespace MediaBrowser.Controller.Session /// true if this instance is session active; otherwise, false. bool IsSessionActive { get; } + /// + /// Gets a value indicating whether [supports media remote control]. + /// + /// true if [supports media remote control]; otherwise, false. + bool SupportsMediaControl { get; } + /// /// Sends the play command. /// diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index 9f5b687cc..bc0f8a5d1 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -139,6 +139,19 @@ namespace MediaBrowser.Controller.Session } } + public bool SupportsMediaControl + { + get + { + if (SessionController != null) + { + return SessionController.SupportsMediaControl; + } + + return false; + } + } + public bool ContainsUser(Guid userId) { return (UserId ?? Guid.Empty) == UserId || AdditionalUsers.Any(i => userId == new Guid(i.UserId)); diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index f0fc8c485..9312b8442 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -46,6 +46,11 @@ namespace MediaBrowser.Dlna.PlayTo } } + public bool SupportsMediaControl + { + get { return IsSessionActive; } + } + private Timer _updateTimer; public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IDtoService dtoService, IImageProcessor imageProcessor, SsdpHandler ssdpHandler, string serverAddress) diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs index 5bd85d3c9..240a87b90 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs @@ -306,7 +306,9 @@ namespace MediaBrowser.Dlna.PlayTo GeneralCommandType.Unmute.ToString(), GeneralCommandType.ToggleMute.ToString(), GeneralCommandType.SetVolume.ToString() - } + }, + + SupportsMediaControl = true }); _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName); diff --git a/MediaBrowser.Model/Configuration/LiveTvOptions.cs b/MediaBrowser.Model/Configuration/LiveTvOptions.cs index ae8aeb200..575f0b863 100644 --- a/MediaBrowser.Model/Configuration/LiveTvOptions.cs +++ b/MediaBrowser.Model/Configuration/LiveTvOptions.cs @@ -3,5 +3,6 @@ public class LiveTvOptions { public int? GuideDays { get; set; } + public string ActiveService { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Model/Session/SessionCapabilities.cs b/MediaBrowser.Model/Session/SessionCapabilities.cs index 290b0e4d4..5eeede126 100644 --- a/MediaBrowser.Model/Session/SessionCapabilities.cs +++ b/MediaBrowser.Model/Session/SessionCapabilities.cs @@ -8,6 +8,8 @@ namespace MediaBrowser.Model.Session public List SupportedCommands { get; set; } + public bool SupportsMediaControl { get; set; } + public SessionCapabilities() { PlayableMediaTypes = new List(); diff --git a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs index ff822a4e6..f89cdac47 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Net; +using MediaBrowser.Common.Events; +using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; using System; using System.Net.WebSockets; @@ -19,6 +20,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// private readonly ILogger _logger; + public event EventHandler Closed; + /// /// Gets or sets the web socket. /// @@ -97,6 +100,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (bytes == null) { // Connection closed + EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); break; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 11d010ca1..d989c0866 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -84,7 +84,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv { _services.AddRange(services); - SetActiveService(_services.FirstOrDefault()); + SetActiveService(_config.Configuration.LiveTvOptions.ActiveService); + } + + private void SetActiveService(string name) + { + var service = _services.FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)) ?? + _services.FirstOrDefault(); + + SetActiveService(service); } private void SetActiveService(ILiveTvService service) diff --git a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs index b800a9cbe..2b60f3116 100644 --- a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs +++ b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Net; +using MediaBrowser.Common.Events; +using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; @@ -14,6 +15,8 @@ namespace MediaBrowser.Server.Implementations.ServerManager /// public class WebSocketConnection : IWebSocketConnection { + public event EventHandler Closed; + /// /// The _socket /// @@ -96,6 +99,13 @@ namespace MediaBrowser.Server.Implementations.ServerManager _socket.OnReceive = OnReceiveInternal; RemoteEndPoint = remoteEndPoint; _logger = logger; + + socket.Closed += socket_Closed; + } + + void socket_Closed(object sender, EventArgs e) + { + EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); } /// diff --git a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs index 8d6289217..236963b9b 100644 --- a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs +++ b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs @@ -45,6 +45,11 @@ namespace MediaBrowser.Server.Implementations.Session } } + public bool SupportsMediaControl + { + get { return true; } + } + private Task SendMessage(object obj, CancellationToken cancellationToken) { var json = _json.SerializeToString(obj); diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 26e451a81..cfa7cef67 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1164,7 +1164,7 @@ namespace MediaBrowser.Server.Implementations.Session SupportedCommands = session.SupportedCommands, UserName = session.UserName, NowPlayingItem = session.NowPlayingItem, - + SupportsRemoteControl = session.SupportsMediaControl, PlayState = session.PlayState }; diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs index 565d83ac3..1a042ede6 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs @@ -138,10 +138,10 @@ namespace MediaBrowser.Server.Implementations.Session if (controller == null) { - controller = new WebSocketController(session, _appHost, _logger); + controller = new WebSocketController(session, _appHost, _logger, _sessionManager); } - controller.Sockets.Add(message.Connection); + controller.AddWebSocket(message.Connection); session.SessionController = controller; } diff --git a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs index 040705171..6f4dd0a72 100644 --- a/MediaBrowser.Server.Implementations/Session/WebSocketController.cs +++ b/MediaBrowser.Server.Implementations/Session/WebSocketController.cs @@ -17,16 +17,19 @@ namespace MediaBrowser.Server.Implementations.Session public class WebSocketController : ISessionController { public SessionInfo Session { get; private set; } - public List Sockets { get; private set; } + public IReadOnlyList Sockets { get; private set; } private readonly IServerApplicationHost _appHost; private readonly ILogger _logger; - public WebSocketController(SessionInfo session, IServerApplicationHost appHost, ILogger logger) + private readonly ISessionManager _sessionManager; + + public WebSocketController(SessionInfo session, IServerApplicationHost appHost, ILogger logger, ISessionManager sessionManager) { Session = session; _appHost = appHost; _logger = logger; + _sessionManager = sessionManager; Sockets = new List(); } @@ -38,6 +41,11 @@ namespace MediaBrowser.Server.Implementations.Session } } + public bool SupportsMediaControl + { + get { return GetActiveSockets().Any(); } + } + private IEnumerable GetActiveSockets() { return Sockets @@ -45,6 +53,28 @@ namespace MediaBrowser.Server.Implementations.Session .Where(i => i.State == WebSocketState.Open); } + public void AddWebSocket(IWebSocketConnection connection) + { + var sockets = Sockets.ToList(); + sockets.Add(connection); + + Sockets = sockets; + + connection.Closed += connection_Closed; + } + + void connection_Closed(object sender, EventArgs e) + { + var capabilities = new SessionCapabilities + { + PlayableMediaTypes = Session.PlayableMediaTypes, + SupportedCommands = Session.SupportedCommands, + SupportsMediaControl = SupportsMediaControl + }; + + _sessionManager.ReportCapabilities(Session.Id, capabilities); + } + private IWebSocketConnection GetActiveSocket() { var socket = GetActiveSockets() diff --git a/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs b/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs index 2918c7ecd..35c5e780b 100644 --- a/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs +++ b/MediaBrowser.Server.Implementations/WebSocket/AlchemyWebSocket.cs @@ -1,4 +1,5 @@ using Alchemy.Classes; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; @@ -18,6 +19,8 @@ namespace MediaBrowser.Server.Implementations.WebSocket /// private readonly ILogger _logger; + public event EventHandler Closed; + /// /// Gets or sets the web socket. /// @@ -66,6 +69,8 @@ namespace MediaBrowser.Server.Implementations.WebSocket private void OnDisconnected(UserContext context) { _disconnected = true; + + EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); } /// diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 1c90bdc87..6dd8fb458 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.366 + 3.0.367 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater 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 72bd0cbc0..2a9820925 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.366 + 3.0.367 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 2fa54ab0d..7df46236c 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.366 + 3.0.367 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 - +