From 416a494b7866ca048b75728a54e8867ac61ab4cb Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Mon, 7 Apr 2014 09:26:48 -0700 Subject: [PATCH 01/18] Additional cast params --- MediaBrowser.WebDashboard/ApiClient.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index c937c28ee6..1a526d8a18 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -3846,7 +3846,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi * @param {String} userId * @param {String} itemId */ - self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, positionTicks, isPaused, isMuted) { + self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, params) { if (!userId) { throw new Error("null userId"); @@ -3862,25 +3862,29 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var msgData = itemId; - msgData += "|" + (positionTicks == null ? "" : positionTicks); - msgData += "|" + (isPaused == null ? "" : isPaused); - msgData += "|" + (isMuted == null ? "" : isMuted); + msgData += "|" + (params.positionTicks == null ? "" : params.positionTicks); + msgData += "|" + (params.isPaused == null ? "" : params.isPaused); + msgData += "|" + (params.isMuted == null ? "" : params.isMuted); msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); + msgData += "|" + (params.audioStreamIndex == null ? "" : params.audioStreamIndex); + msgData += "|" + (params.subtitleStreamIndex == null ? "" : params.subtitleStreamIndex); + msgData += "|" + (params.volumeLevel == null ? "" : params.volumeLevel); + self.sendWebSocketMessage("PlaybackProgress", msgData); deferred.resolveWith(null, []); return deferred.promise(); } - var params = { - isPaused: isPaused, - isMuted: isMuted - }; + ////var params = { + //// isPaused: isPaused, + //// isMuted: isMuted + ////}; - if (positionTicks) { - params.positionTicks = positionTicks; - } + ////if (positionTicks) { + //// params.positionTicks = positionTicks; + ////} if (mediaSourceId) { params.mediaSourceId = mediaSourceId; From f64c7bb0c0702445a4dbcffdae55dcc36da6d931 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Mon, 7 Apr 2014 12:12:16 -0700 Subject: [PATCH 02/18] Undo some changes --- MediaBrowser.WebDashboard/ApiClient.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 1a526d8a18..74f989fc07 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -3846,7 +3846,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi * @param {String} userId * @param {String} itemId */ - self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, params) { + self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, positionTicks, isPaused, isMuted) { if (!userId) { throw new Error("null userId"); @@ -3867,9 +3867,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi msgData += "|" + (params.isMuted == null ? "" : params.isMuted); msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); - msgData += "|" + (params.audioStreamIndex == null ? "" : params.audioStreamIndex); - msgData += "|" + (params.subtitleStreamIndex == null ? "" : params.subtitleStreamIndex); - msgData += "|" + (params.volumeLevel == null ? "" : params.volumeLevel); + ////msgData += "|" + (params.audioStreamIndex == null ? "" : params.audioStreamIndex); + ////msgData += "|" + (params.subtitleStreamIndex == null ? "" : params.subtitleStreamIndex); + ////msgData += "|" + (params.volumeLevel == null ? "" : params.volumeLevel); self.sendWebSocketMessage("PlaybackProgress", msgData); @@ -3877,14 +3877,14 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi return deferred.promise(); } - ////var params = { - //// isPaused: isPaused, - //// isMuted: isMuted - ////}; + var params = { + isPaused: isPaused, + isMuted: isMuted + }; - ////if (positionTicks) { - //// params.positionTicks = positionTicks; - ////} + if (positionTicks) { + params.positionTicks = positionTicks; + } if (mediaSourceId) { params.mediaSourceId = mediaSourceId; From 655c7ccd139bdeecbdc24e551679e01c7db893ed Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:22:03 -0700 Subject: [PATCH 03/18] Enabled lazy load of poster images This should make initial load of the movies page a little more responsive for larger libraries. This can be used on any page loading images. --- MediaBrowser.WebDashboard/Api/DashboardService.cs | 1 + MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 3 +++ 2 files changed, 4 insertions(+) diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 6252a03465..dcfa7f2b67 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -419,6 +419,7 @@ namespace MediaBrowser.WebDashboard.Api { "scripts/all.js" + versionString, "thirdparty/jstree1.0/jquery.jstree.min.js", + "thirdparty/jquery.unveil-custom.js", "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js" }; diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 0ddb055771..5b219f451f 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -653,6 +653,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From 564b165b943b6a9e886d834eefd409fbc3bd5084 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:25:45 -0700 Subject: [PATCH 04/18] Removed api client changes --- MediaBrowser.WebDashboard/ApiClient.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index dbc7ca6d75..6109faf91b 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -3865,15 +3865,11 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var msgData = itemId; - msgData += "|" + (params.positionTicks == null ? "" : params.positionTicks); - msgData += "|" + (params.isPaused == null ? "" : params.isPaused); - msgData += "|" + (params.isMuted == null ? "" : params.isMuted); + msgData += "|" + (positionTicks == null ? "" : params.positionTicks); + msgData += "|" + (isPaused == null ? "" : params.isPaused); + msgData += "|" + (isMuted == null ? "" : params.isMuted); msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); - ////msgData += "|" + (params.audioStreamIndex == null ? "" : params.audioStreamIndex); - ////msgData += "|" + (params.subtitleStreamIndex == null ? "" : params.subtitleStreamIndex); - ////msgData += "|" + (params.volumeLevel == null ? "" : params.volumeLevel); - self.sendWebSocketMessage("PlaybackProgress", msgData); deferred.resolveWith(null, []); From badbc5aa247cc704083d64e8cb0c424ab35a97a2 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Tue, 8 Apr 2014 11:28:25 -0700 Subject: [PATCH 05/18] Removed api client changes --- MediaBrowser.WebDashboard/ApiClient.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js index 6109faf91b..a4c4d97830 100644 --- a/MediaBrowser.WebDashboard/ApiClient.js +++ b/MediaBrowser.WebDashboard/ApiClient.js @@ -3865,9 +3865,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var msgData = itemId; - msgData += "|" + (positionTicks == null ? "" : params.positionTicks); - msgData += "|" + (isPaused == null ? "" : params.isPaused); - msgData += "|" + (isMuted == null ? "" : params.isMuted); + msgData += "|" + (positionTicks == null ? "" : positionTicks); + msgData += "|" + (isPaused == null ? "" : isPaused); + msgData += "|" + (isMuted == null ? "" : isMuted); msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); self.sendWebSocketMessage("PlaybackProgress", msgData); From 8f7d14eabb8c078071d2324a75cad193b9c37a0c Mon Sep 17 00:00:00 2001 From: 7illusions Date: Wed, 9 Apr 2014 12:11:53 +0200 Subject: [PATCH 06/18] PlayTo Error 500 fix --- MediaBrowser.Dlna/PlayTo/Device.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Dlna/PlayTo/Device.cs b/MediaBrowser.Dlna/PlayTo/Device.cs index 1c243b6d3f..054b7e136b 100644 --- a/MediaBrowser.Dlna/PlayTo/Device.cs +++ b/MediaBrowser.Dlna/PlayTo/Device.cs @@ -337,7 +337,7 @@ namespace MediaBrowser.Dlna.PlayTo throw new InvalidOperationException("Unable to find service"); } - var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1)) + var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, 1)) .ConfigureAwait(false); _lapsCount = GetLapsCount(); @@ -352,7 +352,7 @@ namespace MediaBrowser.Dlna.PlayTo var service = Properties.Services.FirstOrDefault(s => s.ServiceType == ServiceAvtransportType); - var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1)) + var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, 1)) .ConfigureAwait(false); await Task.Delay(50).ConfigureAwait(false); return true; @@ -366,7 +366,7 @@ namespace MediaBrowser.Dlna.PlayTo var service = Properties.Services.FirstOrDefault(s => s.ServiceType == ServiceAvtransportType); - var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType, 1)) + var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType, 1)) .ConfigureAwait(false); await Task.Delay(50).ConfigureAwait(false); From 4b206b9cac8fb3e34989aaa442a9389537c61d11 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Thu, 10 Apr 2014 04:12:48 -0700 Subject: [PATCH 07/18] Cast audio playback enhancements * Instant mix works, but not sure about managing the mix * Shuffle _should_ work, but same thing with mgmt Receiver page has also been enhanced for music playback. --- MediaBrowser.WebDashboard/Api/DashboardService.cs | 1 + MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 3 +++ 2 files changed, 4 insertions(+) diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index dcfa7f2b67..7ab4894508 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -442,6 +442,7 @@ namespace MediaBrowser.WebDashboard.Api // jQuery + jQuery mobile await AppendResource(memoryStream, "thirdparty/jquery-2.0.3.min.js", newLineBytes).ConfigureAwait(false); await AppendResource(memoryStream, "thirdparty/jquerymobile-1.4.2/jquery.mobile-1.4.2.min.js", newLineBytes).ConfigureAwait(false); + await AppendResource(memoryStream, "thirdparty/jquery.ba-tinypubsub.min.js", newLineBytes).ConfigureAwait(false); await AppendLocalization(memoryStream).ConfigureAwait(false); await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false); diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 5b219f451f..94265501c0 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -653,6 +653,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From 3094868a83937d2f5c49b06abd53757ef304a7e2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 10 Apr 2014 11:06:54 -0400 Subject: [PATCH 08/18] beginning dlna server --- MediaBrowser.Api/Dlna/DlnaServerService.cs | 89 ++++ MediaBrowser.Api/{ => Dlna}/DlnaService.cs | 2 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 3 +- .../Playback/BaseStreamingService.cs | 20 +- MediaBrowser.Api/Playback/StreamState.cs | 3 + .../Networking/BaseNetworkManager.cs | 41 +- .../Dlna/ControlRequest.cs | 28 ++ MediaBrowser.Controller/Dlna/IDlnaManager.cs | 22 + .../LiveTv/LiveStreamInfo.cs | 21 +- .../MediaBrowser.Controller.csproj | 1 + MediaBrowser.Dlna/Common/Argument.cs | 12 + .../{PlayTo => Common}/DeviceIcon.cs | 2 +- .../{PlayTo => Common}/DeviceService.cs | 11 +- MediaBrowser.Dlna/Common/ServiceAction.cs | 21 + MediaBrowser.Dlna/Common/StateVariable.cs | 25 + MediaBrowser.Dlna/DlnaManager.cs | 26 +- MediaBrowser.Dlna/Images/logo-120.jpg | Bin 0 -> 6745 bytes MediaBrowser.Dlna/Images/logo-120.png | Bin 0 -> 4124 bytes MediaBrowser.Dlna/Images/logo-48.jpg | Bin 0 -> 2484 bytes MediaBrowser.Dlna/Images/logo-48.png | Bin 0 -> 1661 bytes MediaBrowser.Dlna/MediaBrowser.Dlna.csproj | 21 +- MediaBrowser.Dlna/PlayTo/Argument.cs | 29 -- MediaBrowser.Dlna/PlayTo/Device.cs | 18 +- MediaBrowser.Dlna/PlayTo/DeviceInfo.cs | 4 +- MediaBrowser.Dlna/PlayTo/ServiceAction.cs | 34 -- MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs | 1 + MediaBrowser.Dlna/PlayTo/StateVariable.cs | 52 -- MediaBrowser.Dlna/PlayTo/TransportCommands.cs | 61 ++- .../Server/ContentDirectoryXmlBuilder.cs | 235 +++++++++ MediaBrowser.Dlna/Server/ControlHandler.cs | 190 ++++++++ MediaBrowser.Dlna/Server/Datagram.cs | 65 +++ .../Server/DescriptionXmlBuilder.cs | 179 +++++++ .../Server/DlnaServerEntryPoint.cs | 27 +- .../Server/ServiceActionListBuilder.cs | 209 ++++++++ MediaBrowser.Dlna/Server/SsdpHandler.cs | 169 +++++-- MediaBrowser.Dlna/Server/UpnpDevice.cs | 6 +- .../MediaBrowser.MediaEncoding.csproj | 6 +- MediaBrowser.Model/Dlna/DeviceProfile.cs | 1 + MediaBrowser.Mono.sln | 26 +- MediaBrowser.Mono.userprefs | 2 +- .../Music/LastfmArtistProvider.cs | 5 +- .../Library/SearchEngine.cs | 16 +- .../Localization/JavaScript/ar.json | 31 +- .../Localization/JavaScript/ca.json | 30 ++ .../Localization/JavaScript/cs.json | 31 +- .../Localization/JavaScript/de.json | 31 +- .../Localization/JavaScript/el.json | 31 +- .../Localization/JavaScript/en_US.json | 31 +- .../Localization/JavaScript/es.json | 31 +- .../Localization/JavaScript/es_MX.json | 31 +- .../Localization/JavaScript/fr.json | 31 +- .../Localization/JavaScript/he.json | 31 +- .../Localization/JavaScript/it.json | 31 +- .../Localization/JavaScript/ms.json | 30 ++ .../Localization/JavaScript/nb.json | 31 +- .../Localization/JavaScript/nl.json | 31 +- .../Localization/JavaScript/pt_BR.json | 31 +- .../Localization/JavaScript/pt_PT.json | 31 +- .../Localization/JavaScript/ru.json | 31 +- .../Localization/JavaScript/sv.json | 31 +- .../Localization/JavaScript/zh_TW.json | 31 +- .../Localization/Server/ar.json | 452 +++++++++++++++++- .../Localization/Server/ca.json | 451 +++++++++++++++++ .../Localization/Server/cs.json | 452 +++++++++++++++++- .../Localization/Server/de.json | 452 +++++++++++++++++- .../Localization/Server/el.json | 452 +++++++++++++++++- .../Localization/Server/en_GB.json | 452 +++++++++++++++++- .../Localization/Server/en_US.json | 452 +++++++++++++++++- .../Localization/Server/es.json | 452 +++++++++++++++++- .../Localization/Server/es_MX.json | 452 +++++++++++++++++- .../Localization/Server/fr.json | 452 +++++++++++++++++- .../Localization/Server/he.json | 452 +++++++++++++++++- .../Localization/Server/it.json | 452 +++++++++++++++++- .../Localization/Server/ms.json | 451 +++++++++++++++++ .../Localization/Server/nb.json | 452 +++++++++++++++++- .../Localization/Server/nl.json | 452 +++++++++++++++++- .../Localization/Server/pt_BR.json | 452 +++++++++++++++++- .../Localization/Server/pt_PT.json | 452 +++++++++++++++++- .../Localization/Server/ru.json | 452 +++++++++++++++++- .../Localization/Server/sv.json | 452 +++++++++++++++++- .../Localization/Server/zh_TW.json | 452 +++++++++++++++++- ...MediaBrowser.Server.Implementations.csproj | 4 + .../Udp/UdpServer.cs | 3 +- .../MediaBrowser.Server.Mono.csproj | 6 +- MediaBrowser.Server.Mono/Program.cs | 17 +- 85 files changed, 11092 insertions(+), 246 deletions(-) create mode 100644 MediaBrowser.Api/Dlna/DlnaServerService.cs rename MediaBrowser.Api/{ => Dlna}/DlnaService.cs (98%) create mode 100644 MediaBrowser.Controller/Dlna/ControlRequest.cs create mode 100644 MediaBrowser.Dlna/Common/Argument.cs rename MediaBrowser.Dlna/{PlayTo => Common}/DeviceIcon.cs (91%) rename MediaBrowser.Dlna/{PlayTo => Common}/DeviceService.cs (52%) create mode 100644 MediaBrowser.Dlna/Common/ServiceAction.cs create mode 100644 MediaBrowser.Dlna/Common/StateVariable.cs create mode 100644 MediaBrowser.Dlna/Images/logo-120.jpg create mode 100644 MediaBrowser.Dlna/Images/logo-120.png create mode 100644 MediaBrowser.Dlna/Images/logo-48.jpg create mode 100644 MediaBrowser.Dlna/Images/logo-48.png delete mode 100644 MediaBrowser.Dlna/PlayTo/Argument.cs delete mode 100644 MediaBrowser.Dlna/PlayTo/ServiceAction.cs delete mode 100644 MediaBrowser.Dlna/PlayTo/StateVariable.cs create mode 100644 MediaBrowser.Dlna/Server/ContentDirectoryXmlBuilder.cs create mode 100644 MediaBrowser.Dlna/Server/ControlHandler.cs create mode 100644 MediaBrowser.Dlna/Server/Datagram.cs create mode 100644 MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs create mode 100644 MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs create mode 100644 MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json create mode 100644 MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json create mode 100644 MediaBrowser.Server.Implementations/Localization/Server/ca.json create mode 100644 MediaBrowser.Server.Implementations/Localization/Server/ms.json diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs new file mode 100644 index 0000000000..922c67aa2d --- /dev/null +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -0,0 +1,89 @@ +using MediaBrowser.Controller.Dlna; +using ServiceStack; +using ServiceStack.Web; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace MediaBrowser.Api.Dlna +{ + [Route("/Dlna/{UuId}/description.xml", "GET", Summary = "Gets dlna server info")] + [Route("/Dlna/{UuId}/description", "GET", Summary = "Gets dlna server info")] + public class GetDescriptionXml + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + } + + [Route("/Dlna/{UuId}/contentdirectory.xml", "GET", Summary = "Gets dlna content directory xml")] + [Route("/Dlna/{UuId}/contentdirectory", "GET", Summary = "Gets the content directory xml")] + public class GetContentDirectory + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + } + + [Route("/Dlna/{UuId}/control", "POST", Summary = "Processes a control request")] + public class ProcessControlRequest : IRequiresRequestStream + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + + public Stream RequestStream { get; set; } + } + + public class DlnaServerService : BaseApiService + { + private readonly IDlnaManager _dlnaManager; + + public DlnaServerService(IDlnaManager dlnaManager) + { + _dlnaManager = dlnaManager; + } + + public object Get(GetDescriptionXml request) + { + var xml = _dlnaManager.GetServerDescriptionXml(GetRequestHeaders(), request.UuId); + + return ResultFactory.GetResult(xml, "text/xml"); + } + + public object Get(GetContentDirectory request) + { + var xml = _dlnaManager.GetContentDirectoryXml(GetRequestHeaders()); + + return ResultFactory.GetResult(xml, "text/xml"); + } + + public object Post(ProcessControlRequest request) + { + var response = PostAsync(request).Result; + + return ResultFactory.GetResult(response.Xml, "text/xml"); + } + + private async Task PostAsync(ProcessControlRequest request) + { + using (var reader = new StreamReader(request.RequestStream)) + { + return _dlnaManager.ProcessControlRequest(new ControlRequest + { + Headers = GetRequestHeaders(), + InputXml = await reader.ReadToEndAsync().ConfigureAwait(false) + }); + } + } + + private IDictionary GetRequestHeaders() + { + var headers = new Dictionary(); + + foreach (var key in Request.Headers.AllKeys) + { + headers[key] = Request.Headers[key]; + } + + return headers; + } + } +} diff --git a/MediaBrowser.Api/DlnaService.cs b/MediaBrowser.Api/Dlna/DlnaService.cs similarity index 98% rename from MediaBrowser.Api/DlnaService.cs rename to MediaBrowser.Api/Dlna/DlnaService.cs index 792a7ff43f..9e6ca3aea9 100644 --- a/MediaBrowser.Api/DlnaService.cs +++ b/MediaBrowser.Api/Dlna/DlnaService.cs @@ -4,7 +4,7 @@ using ServiceStack; using System.Collections.Generic; using System.Linq; -namespace MediaBrowser.Api +namespace MediaBrowser.Api.Dlna { [Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")] public class GetProfileInfos : IReturn> diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index c03eddf99e..edbae3903e 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -66,7 +66,8 @@ Properties\SharedVersion.cs - + + diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bb55b893a2..4b0406cde8 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1341,6 +1341,12 @@ namespace MediaBrowser.Api.Playback RequestedUrl = url }; + if (!string.IsNullOrWhiteSpace(request.AudioCodec)) + { + state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(); + } + var item = string.IsNullOrEmpty(request.MediaSourceId) ? DtoService.GetItemByDtoId(request.Id) : DtoService.GetItemByDtoId(request.MediaSourceId); @@ -1492,10 +1498,10 @@ namespace MediaBrowser.Api.Playback videoRequest.VideoCodec = "copy"; } - //if (state.AudioStream != null && CanStreamCopyAudio(request, state.AudioStream)) - //{ - // request.AudioCodec = "copy"; - //} + if (state.AudioStream != null && CanStreamCopyAudio(request, state.AudioStream, state.SupportedAudioCodecs)) + { + request.AudioCodec = "copy"; + } } return state; @@ -1587,10 +1593,10 @@ namespace MediaBrowser.Api.Playback return SupportsAutomaticVideoStreamCopy; } - private bool CanStreamCopyAudio(StreamRequest request, MediaStream audioStream) + private bool CanStreamCopyAudio(StreamRequest request, MediaStream audioStream, List supportedAudioCodecs) { // Source and target codecs must match - if (string.IsNullOrEmpty(request.AudioCodec) || !string.Equals(request.AudioCodec, audioStream.Codec, StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) { return false; } @@ -1623,7 +1629,7 @@ namespace MediaBrowser.Api.Playback } } - return SupportsAutomaticVideoStreamCopy; + return true; } protected virtual bool SupportsAutomaticVideoStreamCopy diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index ce7d79917a..e41f296638 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -67,10 +67,13 @@ namespace MediaBrowser.Api.Playback public string AudioSync = "1"; public string VideoSync = "vfr"; + public List SupportedAudioCodecs { get; set; } + public StreamState(ILiveTvManager liveTvManager, ILogger logger) { _liveTvManager = liveTvManager; _logger = logger; + SupportedAudioCodecs = new List(); } public string InputAudioSync { get; set; } diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs index ac6b9290ef..e15c32518e 100644 --- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs +++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs @@ -15,6 +15,44 @@ namespace MediaBrowser.Common.Implementations.Networking /// /// IPAddress. public IEnumerable GetLocalIpAddresses() + { + var list = GetIPsDefault().Where(i => !IPAddress.IsLoopback(i)).Select(i => i.ToString()).ToList(); + + if (list.Count > 0) + { + return list; + } + + return GetLocalIpAddressesFallback(); + } + + private IEnumerable GetIPsDefault() + { + foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces()) + { + var props = adapter.GetIPProperties(); + var gateways = from ga in props.GatewayAddresses + where !ga.Address.Equals(IPAddress.Any) + select true; + + if (!gateways.Any()) + { + continue; + } + + foreach (var uni in props.UnicastAddresses) + { + var address = uni.Address; + if (address.AddressFamily != AddressFamily.InterNetwork) + { + continue; + } + yield return address; + } + } + } + + private IEnumerable GetLocalIpAddressesFallback() { var host = Dns.GetHostEntry(Dns.GetHostName()); @@ -25,7 +63,7 @@ namespace MediaBrowser.Common.Implementations.Networking .Select(i => i.ToString()) .Reverse(); } - + /// /// Gets a random port number that is currently available /// @@ -50,6 +88,7 @@ namespace MediaBrowser.Common.Implementations.Networking .Select(i => BitConverter.ToString(i.GetPhysicalAddress().GetAddressBytes())) .FirstOrDefault(); } + /// /// Parses the specified endpointstring. /// diff --git a/MediaBrowser.Controller/Dlna/ControlRequest.cs b/MediaBrowser.Controller/Dlna/ControlRequest.cs new file mode 100644 index 0000000000..74e68b7d01 --- /dev/null +++ b/MediaBrowser.Controller/Dlna/ControlRequest.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Dlna +{ + public class ControlRequest + { + public IDictionary Headers { get; set; } + + public string InputXml { get; set; } + + public ControlRequest() + { + Headers = new Dictionary(); + } + } + + public class ControlResponse + { + public IDictionary Headers { get; set; } + + public string Xml { get; set; } + + public ControlResponse() + { + Headers = new Dictionary(); + } + } +} diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 521d17e01f..bcccaaa2e9 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -55,5 +55,27 @@ namespace MediaBrowser.Controller.Dlna /// The device information. /// DeviceProfile. DeviceProfile GetProfile(DeviceIdentification deviceInfo); + + /// + /// Gets the server description XML. + /// + /// The headers. + /// The server uu identifier. + /// System.String. + string GetServerDescriptionXml(IDictionary headers, string serverUuId); + + /// + /// Gets the content directory XML. + /// + /// The headers. + /// System.String. + string GetContentDirectoryXml(IDictionary headers); + + /// + /// Processes the control request. + /// + /// The request. + /// ControlResponse. + ControlResponse ProcessControlRequest(ControlRequest request); } } diff --git a/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs b/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs index 8e1f94178d..019c9d31a5 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs @@ -1,4 +1,6 @@ - +using MediaBrowser.Model.Entities; +using System.Collections.Generic; + namespace MediaBrowser.Controller.LiveTv { public class LiveStreamInfo @@ -20,5 +22,22 @@ namespace MediaBrowser.Controller.LiveTv /// /// The identifier. public string Id { get; set; } + + /// + /// Gets or sets the media container. + /// + /// The media container. + public string MediaContainer { get; set; } + + /// + /// Gets or sets the media streams. + /// + /// The media streams. + public List MediaStreams { get; set; } + + public LiveStreamInfo() + { + MediaStreams = new List(); + } } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 3082d12ca5..692a7a92eb 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -78,6 +78,7 @@ + diff --git a/MediaBrowser.Dlna/Common/Argument.cs b/MediaBrowser.Dlna/Common/Argument.cs new file mode 100644 index 0000000000..a3ff8ecc88 --- /dev/null +++ b/MediaBrowser.Dlna/Common/Argument.cs @@ -0,0 +1,12 @@ + +namespace MediaBrowser.Dlna.Common +{ + public class Argument + { + public string Name { get; set; } + + public string Direction { get; set; } + + public string RelatedStateVariable { get; set; } + } +} diff --git a/MediaBrowser.Dlna/PlayTo/DeviceIcon.cs b/MediaBrowser.Dlna/Common/DeviceIcon.cs similarity index 91% rename from MediaBrowser.Dlna/PlayTo/DeviceIcon.cs rename to MediaBrowser.Dlna/Common/DeviceIcon.cs index a46abdd745..bec10dcc5a 100644 --- a/MediaBrowser.Dlna/PlayTo/DeviceIcon.cs +++ b/MediaBrowser.Dlna/Common/DeviceIcon.cs @@ -1,5 +1,5 @@  -namespace MediaBrowser.Dlna.PlayTo +namespace MediaBrowser.Dlna.Common { public class DeviceIcon { diff --git a/MediaBrowser.Dlna/PlayTo/DeviceService.cs b/MediaBrowser.Dlna/Common/DeviceService.cs similarity index 52% rename from MediaBrowser.Dlna/PlayTo/DeviceService.cs rename to MediaBrowser.Dlna/Common/DeviceService.cs index 082128b225..8f8b175a42 100644 --- a/MediaBrowser.Dlna/PlayTo/DeviceService.cs +++ b/MediaBrowser.Dlna/Common/DeviceService.cs @@ -1,5 +1,5 @@  -namespace MediaBrowser.Dlna.PlayTo +namespace MediaBrowser.Dlna.Common { public class DeviceService { @@ -13,15 +13,6 @@ namespace MediaBrowser.Dlna.PlayTo public string EventSubUrl { get; set; } - public DeviceService(string serviceType, string serviceId, string scpdUrl, string controlUrl, string eventSubUrl) - { - ServiceType = serviceType; - ServiceId = serviceId; - ScpdUrl = scpdUrl; - ControlUrl = controlUrl; - EventSubUrl = eventSubUrl; - } - public override string ToString() { return string.Format("{0}", ServiceId); diff --git a/MediaBrowser.Dlna/Common/ServiceAction.cs b/MediaBrowser.Dlna/Common/ServiceAction.cs new file mode 100644 index 0000000000..7685e217e8 --- /dev/null +++ b/MediaBrowser.Dlna/Common/ServiceAction.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.Common +{ + public class ServiceAction + { + public string Name { get; set; } + + public List ArgumentList { get; set; } + + public override string ToString() + { + return Name; + } + + public ServiceAction() + { + ArgumentList = new List(); + } + } +} diff --git a/MediaBrowser.Dlna/Common/StateVariable.cs b/MediaBrowser.Dlna/Common/StateVariable.cs new file mode 100644 index 0000000000..21771e7b8e --- /dev/null +++ b/MediaBrowser.Dlna/Common/StateVariable.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.Common +{ + public class StateVariable + { + public string Name { get; set; } + + public string DataType { get; set; } + + public bool SendsEvents { get; set; } + + public List AllowedValues { get; set; } + + public override string ToString() + { + return Name; + } + + public StateVariable() + { + AllowedValues = new List(); + } + } +} diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 7a8fd41830..624f23f7f2 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -1,9 +1,9 @@ -using System.Text; -using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dlna; using MediaBrowser.Dlna.Profiles; +using MediaBrowser.Dlna.Server; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Text.RegularExpressions; namespace MediaBrowser.Dlna @@ -476,5 +477,26 @@ namespace MediaBrowser.Dlna internal DeviceProfileInfo Info { get; set; } internal string Path { get; set; } } + + public string GetServerDescriptionXml(IDictionary headers, string serverUuId) + { + var profile = GetProfile(headers) ?? + GetDefaultProfile(); + + return new DescriptionXmlBuilder(profile, serverUuId).GetXml(); + } + + public string GetContentDirectoryXml(IDictionary headers) + { + var profile = GetProfile(headers) ?? + GetDefaultProfile(); + + return new ContentDirectoryXmlBuilder(profile).GetXml(); + } + + public ControlResponse ProcessControlRequest(ControlRequest request) + { + return new ControlHandler(_logger).ProcessControlRequest(request); + } } } \ No newline at end of file diff --git a/MediaBrowser.Dlna/Images/logo-120.jpg b/MediaBrowser.Dlna/Images/logo-120.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1de803c8fad9750c75ec994c27ac580f9514c277 GIT binary patch literal 6745 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 z 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 UEEodDe+VX&5B^_;!25;&0v-EG?f?J) literal 0 HcmV?d00001 diff --git a/MediaBrowser.Dlna/Images/logo-120.png b/MediaBrowser.Dlna/Images/logo-120.png new file mode 100644 index 0000000000000000000000000000000000000000..2dd04d46818eefc3ec7f569975e7f1ca8fb7b0a1 GIT binary patch literal 4124 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 Hu0mjf!VC7t literal 0 HcmV?d00001 diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index d1fed45729..0980ee81db 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -52,13 +52,13 @@ Properties\SharedVersion.cs - + Code - + @@ -68,20 +68,25 @@ - + + + + + + - + - + @@ -141,6 +146,12 @@ + + + + + +