From 1f004c978a902afbd691da20197fb30a3547690f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Feb 2016 22:07:15 -0500 Subject: [PATCH 001/111] add path to ListingsProviderInfo --- MediaBrowser.Model/LiveTv/LiveTvOptions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 838325d68..095fa95e1 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -47,5 +47,6 @@ namespace MediaBrowser.Model.LiveTv public string ListingsId { get; set; } public string ZipCode { get; set; } public string Country { get; set; } + public string Path { get; set; } } } \ No newline at end of file From ffbe92e51ef8553b91a81f2a57317c51605abea3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 16 Feb 2016 23:44:31 -0500 Subject: [PATCH 002/111] activate unicast listener --- MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs | 6 +- MediaBrowser.Dlna/Ssdp/SsdpHandler.cs | 154 ++++++++++++++-------- 2 files changed, 100 insertions(+), 60 deletions(-) diff --git a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs index 4f7dffdd9..ff936346c 100644 --- a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs +++ b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs @@ -127,10 +127,12 @@ namespace MediaBrowser.Dlna.Ssdp args.EndPoint = endPoint; args.LocalEndPoint = new IPEndPoint(localIp, 0); - if (!_ssdpHandler.IsSelfNotification(args)) + if (_ssdpHandler.IgnoreMessage(args, true)) { - TryCreateDevice(args); + return; } + + TryCreateDevice(args); } } diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs index 881f70165..c2918aed5 100644 --- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs @@ -86,8 +86,25 @@ namespace MediaBrowser.Dlna.Ssdp public event EventHandler MessageReceived; - private async void OnMessageReceived(SsdpMessageEventArgs args) + private async void OnMessageReceived(SsdpMessageEventArgs args, bool isMulticast) { + if (IgnoreMessage(args, isMulticast)) + { + return; + } + + var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog; + + if (enableDebugLogging) + { + var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); + var headerText = string.Join(",", headerTexts.ToArray()); + + var protocol = isMulticast ? "Multicast" : "Unicast"; + var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString(); + _logger.Debug("{0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol); + } + var headers = args.Headers; string st; @@ -108,6 +125,44 @@ namespace MediaBrowser.Dlna.Ssdp EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger); } + internal bool IgnoreMessage(SsdpMessageEventArgs args, bool isMulticast) + { + string usn; + if (args.Headers.TryGetValue("USN", out usn)) + { + // USN=uuid:b67df29b5c379445fde78c3774ab518d::urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1 + if (RegisteredDevices.Select(i => i.USN).Contains(usn, StringComparer.OrdinalIgnoreCase)) + { + //var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); + //var headerText = string.Join(",", headerTexts.ToArray()); + + //var protocol = isMulticast ? "Multicast" : "Unicast"; + //var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString(); + //_logger.Debug("IGNORING {0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol); + + return true; + } + } + + string serverId; + if (args.Headers.TryGetValue("X-EMBY-SERVERID", out serverId)) + { + if (string.Equals(serverId, _appHost.SystemId, StringComparison.OrdinalIgnoreCase)) + { + //var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); + //var headerText = string.Join(",", headerTexts.ToArray()); + + //var protocol = isMulticast ? "Multicast" : "Unicast"; + //var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString(); + //_logger.Debug("IGNORING {0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol); + + return true; + } + } + + return false; + } + public IEnumerable RegisteredDevices { get @@ -126,7 +181,7 @@ namespace MediaBrowser.Dlna.Ssdp RestartSocketListener(); ReloadAliveNotifier(); - //CreateUnicastClient(); + CreateUnicastClient(); SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged; SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; @@ -146,6 +201,7 @@ namespace MediaBrowser.Dlna.Ssdp values["HOST"] = "239.255.255.250:1900"; values["USER-AGENT"] = "UPnP/1.0 DLNADOC/1.50 Platinum/1.0.4.2"; + values["X-EMBY-SERVERID"] = _appHost.SystemId; values["MAN"] = "\"ssdp:discover\""; @@ -162,7 +218,7 @@ namespace MediaBrowser.Dlna.Ssdp // UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2) SendDatagram(msg, _ssdpEndp, localIp, true); - //SendUnicastRequest(msg); + SendUnicastRequest(msg); } public async void SendDatagram(string msg, @@ -324,20 +380,7 @@ namespace MediaBrowser.Dlna.Ssdp var args = SsdpHelper.ParseSsdpResponse(received); args.EndPoint = endpoint; - if (IsSelfNotification(args)) - { - return; - } - - if (enableDebugLogging) - { - var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); - var headerText = string.Join(",", headerTexts.ToArray()); - - _logger.Debug("{0} message received from {1} on {3}. Headers: {2}", args.Method, args.EndPoint, headerText, _multicastSocket.LocalEndPoint); - } - - OnMessageReceived(args); + OnMessageReceived(args, true); } catch (ObjectDisposedException) { @@ -357,26 +400,6 @@ namespace MediaBrowser.Dlna.Ssdp } } - internal bool IsSelfNotification(SsdpMessageEventArgs args) - { - // Avoid responding to self search messages - //string serverId; - //if (args.Headers.TryGetValue("X-EMBYSERVERID", out serverId) && - // string.Equals(serverId, _appHost.SystemId, StringComparison.OrdinalIgnoreCase)) - //{ - // return true; - //} - - string server; - args.Headers.TryGetValue("SERVER", out server); - - if (string.Equals(server, _serverSignature, StringComparison.OrdinalIgnoreCase)) - { - //return true; - } - return false; - } - public void Dispose() { _config.NamedConfigurationUpdated -= _config_ConfigurationUpdated; @@ -440,6 +463,7 @@ namespace MediaBrowser.Dlna.Ssdp values["NTS"] = "ssdp:" + type; values["NT"] = dev.Type; values["USN"] = dev.USN; + values["X-EMBY-SERVERID"] = _appHost.SystemId; if (logMessage) { @@ -489,14 +513,7 @@ namespace MediaBrowser.Dlna.Ssdp _logger.ErrorException("Error creating unicast client", ex); } - try - { - UnicastSetBeginReceive(); - } - catch (Exception ex) - { - _logger.ErrorException("Error in UnicastSetBeginReceive", ex); - } + UnicastSetBeginReceive(); } } @@ -522,11 +539,18 @@ namespace MediaBrowser.Dlna.Ssdp /// private void UnicastSetBeginReceive() { - var ipRxEnd = new IPEndPoint(IPAddress.Any, _unicastPort); - var udpListener = new UdpState { EndPoint = ipRxEnd }; + try + { + var ipRxEnd = new IPEndPoint(IPAddress.Any, _unicastPort); + var udpListener = new UdpState { EndPoint = ipRxEnd }; - udpListener.UdpClient = _unicastClient; - _unicastClient.BeginReceive(UnicastReceiveCallback, udpListener); + udpListener.UdpClient = _unicastClient; + _unicastClient.BeginReceive(UnicastReceiveCallback, udpListener); + } + catch (Exception ex) + { + _logger.ErrorException("Error in UnicastSetBeginReceive", ex); + } } /// @@ -540,14 +564,21 @@ namespace MediaBrowser.Dlna.Ssdp var endpoint = ((UdpState)(ar.AsyncState)).EndPoint; if (udpClient.Client != null) { - var responseBytes = udpClient.EndReceive(ar, ref endpoint); - var args = SsdpHelper.ParseSsdpResponse(responseBytes); + try + { + var responseBytes = udpClient.EndReceive(ar, ref endpoint); + var args = SsdpHelper.ParseSsdpResponse(responseBytes); - args.EndPoint = endpoint; + args.EndPoint = endpoint; - OnMessageReceived(args); + OnMessageReceived(args, false); - UnicastSetBeginReceive(); + UnicastSetBeginReceive(); + } + catch (ObjectDisposedException) + { + + } } } @@ -564,13 +595,20 @@ namespace MediaBrowser.Dlna.Ssdp var ipSsdp = IPAddress.Parse(SSDPAddr); var ipTxEnd = new IPEndPoint(ipSsdp, SSDPPort); - for (var i = 0; i < 3; i++) + try { - if (i > 0) + for (var i = 0; i < 3; i++) { - await Task.Delay(50).ConfigureAwait(false); + if (i > 0) + { + await Task.Delay(50).ConfigureAwait(false); + } + _unicastClient.Send(req, req.Length, ipTxEnd); } - _unicastClient.Send(req, req.Length, ipTxEnd); + } + catch (Exception ex) + { + _logger.ErrorException("Error in SendUnicastRequest", ex); } } From 3eb1f47da05ce7708ee10a65b2b4f2a6de31055a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tavares=20Andr=C3=A9?= Date: Wed, 17 Feb 2016 07:58:07 +0100 Subject: [PATCH 003/111] Update voice components --- .../MediaBrowser.WebDashboard.csproj | 23 +++++++++++-------- MediaBrowser.sln | 7 ++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 9de20cb39..099a47d40 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -460,12 +460,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - PreserveNewest @@ -544,9 +538,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -1396,6 +1387,17 @@ PreserveNewest + + + + + + + + + + + PreserveNewest @@ -2226,6 +2228,9 @@ + + + diff --git a/MediaBrowser.sln b/MediaBrowser.sln index a9b5020ec..a55ae200a 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F0E0E64C-2A6F-4E35-9533-D53AC07C2CD1}" EndProject @@ -521,7 +521,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection EndGlobal From f13ca8f343c3e7b782facbaa4e42b7f8a26246b5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Feb 2016 16:24:01 -0500 Subject: [PATCH 004/111] update device discovery --- MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs | 10 ++---- MediaBrowser.Dlna/Ssdp/SsdpHandler.cs | 36 +++++++++++-------- .../LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs | 7 +++- ...MediaBrowser.Server.Implementations.csproj | 4 +-- .../packages.config | 2 +- 5 files changed, 32 insertions(+), 27 deletions(-) diff --git a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs index ff936346c..70f6d0e53 100644 --- a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs +++ b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs @@ -132,6 +132,8 @@ namespace MediaBrowser.Dlna.Ssdp return; } + _ssdpHandler.LogMessageReceived(args, true); + TryCreateDevice(args); } } @@ -219,14 +221,6 @@ namespace MediaBrowser.Dlna.Ssdp return; } - if (_config.GetDlnaConfiguration().EnableDebugLog) - { - var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); - var headerText = string.Join(",", headerTexts.ToArray()); - - _logger.Debug("{0} Device message received from {1}. Headers: {2}", args.Method, args.EndPoint, headerText); - } - EventHelper.FireEventIfNotNull(DeviceDiscovered, this, args, _logger); } diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs index c2918aed5..6e85918f4 100644 --- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs @@ -93,17 +93,7 @@ namespace MediaBrowser.Dlna.Ssdp return; } - var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog; - - if (enableDebugLogging) - { - var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); - var headerText = string.Join(",", headerTexts.ToArray()); - - var protocol = isMulticast ? "Multicast" : "Unicast"; - var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString(); - _logger.Debug("{0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol); - } + LogMessageReceived(args, isMulticast); var headers = args.Headers; string st; @@ -125,6 +115,21 @@ namespace MediaBrowser.Dlna.Ssdp EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger); } + internal void LogMessageReceived(SsdpMessageEventArgs args, bool isMulticast) + { + var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog; + + if (enableDebugLogging) + { + var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); + var headerText = string.Join(",", headerTexts.ToArray()); + + var protocol = isMulticast ? "Multicast" : "Unicast"; + var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString(); + _logger.Debug("{0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol); + } + } + internal bool IgnoreMessage(SsdpMessageEventArgs args, bool isMulticast) { string usn; @@ -298,8 +303,8 @@ namespace MediaBrowser.Dlna.Ssdp var msg = new SsdpMessageBuilder().BuildMessage(header, values); - SendDatagram(msg, endpoint, null, false, 1); - SendDatagram(msg, endpoint, new IPEndPoint(d.Address, 0), false, 1); + SendDatagram(msg, endpoint, null, false, 2); + SendDatagram(msg, endpoint, new IPEndPoint(d.Address, 0), false, 2); //SendDatagram(header, values, endpoint, null, true); if (enableDebugLogging) @@ -473,6 +478,7 @@ namespace MediaBrowser.Dlna.Ssdp var msg = new SsdpMessageBuilder().BuildMessage(header, values); SendDatagram(msg, _ssdpEndp, new IPEndPoint(dev.Address, 0), true); + //SendUnicastRequest(msg, 1); } public void RegisterNotification(string uuid, Uri descriptionUri, IPAddress address, IEnumerable services) @@ -582,7 +588,7 @@ namespace MediaBrowser.Dlna.Ssdp } } - private async void SendUnicastRequest(string request) + private async void SendUnicastRequest(string request, int sendCount = 3) { if (_unicastClient == null) { @@ -597,7 +603,7 @@ namespace MediaBrowser.Dlna.Ssdp try { - for (var i = 0; i < 3; i++) + for (var i = 0; i < sendCount; i++) { if (i > 0) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs index 08c42bb46..852b86467 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs @@ -42,7 +42,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e) { string st = null; - if (e.Headers.TryGetValue("ST", out st) && string.Equals(st, "urn:ses-com:device:SatIPServer:1", StringComparison.OrdinalIgnoreCase)) + string nt = null; + e.Headers.TryGetValue("ST", out st); + e.Headers.TryGetValue("NT", out nt); + + if (string.Equals(st, "urn:ses-com:device:SatIPServer:1", StringComparison.OrdinalIgnoreCase) || + string.Equals(nt, "urn:ses-com:device:SatIPServer:1", StringComparison.OrdinalIgnoreCase)) { string location; if (e.Headers.TryGetValue("Location", out location) && !string.IsNullOrWhiteSpace(location)) diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 5f2fab457..80592c724 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -52,9 +52,9 @@ ..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll - + False - ..\packages\MediaBrowser.Naming.1.0.0.47\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll + ..\packages\MediaBrowser.Naming.1.0.0.48\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index 816f85b42..4f163f8a4 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -3,7 +3,7 @@ - + From bfa1b30cab05577844a9d34e4519c89ebc84aa91 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Feb 2016 16:40:17 -0500 Subject: [PATCH 005/111] update RespondToSearch --- MediaBrowser.Dlna/Ssdp/SsdpHandler.cs | 41 ++++++++++++++++++++------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs index 6e85918f4..278c34275 100644 --- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs @@ -144,7 +144,7 @@ namespace MediaBrowser.Dlna.Ssdp //var protocol = isMulticast ? "Multicast" : "Unicast"; //var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString(); //_logger.Debug("IGNORING {0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol); - + return true; } } @@ -164,7 +164,7 @@ namespace MediaBrowser.Dlna.Ssdp return true; } } - + return false; } @@ -303,9 +303,17 @@ namespace MediaBrowser.Dlna.Ssdp var msg = new SsdpMessageBuilder().BuildMessage(header, values); - SendDatagram(msg, endpoint, null, false, 2); - SendDatagram(msg, endpoint, new IPEndPoint(d.Address, 0), false, 2); - //SendDatagram(header, values, endpoint, null, true); + var ipEndPoint = endpoint as IPEndPoint; + if (ipEndPoint != null) + { + SendUnicastRequest(msg, ipEndPoint); + } + else + { + SendDatagram(msg, endpoint, null, false, 2); + SendDatagram(msg, endpoint, new IPEndPoint(d.Address, 0), false, 2); + //SendDatagram(header, values, endpoint, null, true); + } if (enableDebugLogging) { @@ -583,12 +591,27 @@ namespace MediaBrowser.Dlna.Ssdp } catch (ObjectDisposedException) { - + } } } - private async void SendUnicastRequest(string request, int sendCount = 3) + private void SendUnicastRequest(string request, int sendCount = 3) + { + if (_unicastClient == null) + { + return; + } + + _logger.Debug("Sending unicast search request"); + + var ipSsdp = IPAddress.Parse(SSDPAddr); + var ipTxEnd = new IPEndPoint(ipSsdp, SSDPPort); + + SendUnicastRequest(request, ipTxEnd, sendCount); + } + + private async void SendUnicastRequest(string request, IPEndPoint toEndPoint, int sendCount = 3) { if (_unicastClient == null) { @@ -598,8 +621,6 @@ namespace MediaBrowser.Dlna.Ssdp _logger.Debug("Sending unicast search request"); byte[] req = Encoding.ASCII.GetBytes(request); - var ipSsdp = IPAddress.Parse(SSDPAddr); - var ipTxEnd = new IPEndPoint(ipSsdp, SSDPPort); try { @@ -609,7 +630,7 @@ namespace MediaBrowser.Dlna.Ssdp { await Task.Delay(50).ConfigureAwait(false); } - _unicastClient.Send(req, req.Length, ipTxEnd); + _unicastClient.Send(req, req.Length, toEndPoint); } } catch (Exception ex) From 76eb1c46e3a2488d954d8981e3f35f5739ec0d4e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Feb 2016 21:55:15 -0500 Subject: [PATCH 006/111] support more embedded video metadata --- .../Encoder/MediaEncoder.cs | 4 +- .../Probing/ProbeResultNormalizer.cs | 129 +++++++++++------- MediaBrowser.Model/MediaInfo/MediaInfo.cs | 10 +- .../MediaInfo/FFProbeAudioInfo.cs | 4 +- .../MediaInfo/FFProbeVideoInfo.cs | 12 ++ .../MediaBrowser.WebDashboard.csproj | 6 +- 6 files changed, 103 insertions(+), 62 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 30e50fecd..ced36f3aa 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -129,7 +129,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// The request. /// The cancellation token. /// Task. - public Task GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken) + public Task GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken) { var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters; @@ -175,7 +175,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// The cancellation token. /// Task{MediaInfoResult}. /// ffprobe failed - streams and format are both null. - private async Task GetMediaInfoInternal(string inputPath, + private async Task GetMediaInfoInternal(string inputPath, string primaryPath, MediaProtocol protocol, bool extractChapters, diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 31f6af181..db6278bd4 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -27,7 +27,7 @@ namespace MediaBrowser.MediaEncoding.Probing public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol) { - var info = new Model.MediaInfo.MediaInfo + var info = new MediaInfo { Path = path, Protocol = protocol @@ -56,40 +56,81 @@ namespace MediaBrowser.MediaEncoding.Probing } } - if (isAudio) + var tags = new Dictionary(StringComparer.OrdinalIgnoreCase); + var tagStreamType = isAudio ? "audio" : "video"; + + if (data.streams != null) { - SetAudioRuntimeTicks(data, info); + var tagStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, tagStreamType, StringComparison.OrdinalIgnoreCase)); - var tags = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // tags are normally located under data.format, but we've seen some cases with ogg where they're part of the audio stream - // so let's create a combined list of both - - if (data.streams != null) + if (tagStream != null && tagStream.tags != null) { - var audioStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, "audio", StringComparison.OrdinalIgnoreCase)); - - if (audioStream != null && audioStream.tags != null) - { - foreach (var pair in audioStream.tags) - { - tags[pair.Key] = pair.Value; - } - } - } - - if (data.format != null && data.format.tags != null) - { - foreach (var pair in data.format.tags) + foreach (var pair in tagStream.tags) { tags[pair.Key] = pair.Value; } } + } + + if (data.format != null && data.format.tags != null) + { + foreach (var pair in data.format.tags) + { + tags[pair.Key] = pair.Value; + } + } + + FetchGenres(info, tags); + var overview = FFProbeHelpers.GetDictionaryValue(tags, "description"); + if (!string.IsNullOrWhiteSpace(overview)) + { + info.Overview = overview; + } + + var title = FFProbeHelpers.GetDictionaryValue(tags, "title"); + if (!string.IsNullOrWhiteSpace(title)) + { + info.Name = title; + } + + info.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date"); + + // Several different forms of retaildate + info.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ?? + FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ?? + FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ?? + FFProbeHelpers.GetDictionaryDateTime(tags, "date"); + + if (isAudio) + { + SetAudioRuntimeTicks(data, info); + + // tags are normally located under data.format, but we've seen some cases with ogg where they're part of the audio stream + // so let's create a combined list of both SetAudioInfoFromTags(info, tags); } else { + var iTunEXTC = FFProbeHelpers.GetDictionaryValue(tags, "iTunEXTC"); + if (!string.IsNullOrWhiteSpace(iTunEXTC)) + { + var parts = iTunEXTC.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + // Example + // mpaa|G|100|For crude humor + if (parts.Length == 4) + { + info.OfficialRating = parts[1]; + info.OfficialRatingDescription = parts[3]; + } + } + + var itunesXml = FFProbeHelpers.GetDictionaryValue(tags, "iTunMOVI"); + if (!string.IsNullOrWhiteSpace(itunesXml)) + { + FetchFromItunesInfo(itunesXml, info); + } + if (data.format != null && !string.IsNullOrEmpty(data.format.duration)) { info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks; @@ -108,6 +149,11 @@ namespace MediaBrowser.MediaEncoding.Probing return info; } + private void FetchFromItunesInfo(string xml, MediaInfo info) + { + + } + /// /// Converts ffprobe stream info to our MediaStream class /// @@ -430,16 +476,8 @@ namespace MediaBrowser.MediaEncoding.Probing } } - private void SetAudioInfoFromTags(Model.MediaInfo.MediaInfo audio, Dictionary tags) + private void SetAudioInfoFromTags(MediaInfo audio, Dictionary tags) { - var title = FFProbeHelpers.GetDictionaryValue(tags, "title"); - - // Only set Name if title was found in the dictionary - if (!string.IsNullOrEmpty(title)) - { - audio.Title = title; - } - var composer = FFProbeHelpers.GetDictionaryValue(tags, "composer"); if (!string.IsNullOrWhiteSpace(composer)) { @@ -511,22 +549,12 @@ namespace MediaBrowser.MediaEncoding.Probing // Disc number audio.ParentIndexNumber = GetDictionaryDiscValue(tags, "disc"); - audio.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date"); - - // Several different forms of retaildate - audio.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ?? - FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ?? - FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ?? - FFProbeHelpers.GetDictionaryDateTime(tags, "date"); - // If we don't have a ProductionYear try and get it from PremiereDate if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue) { audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year; } - FetchGenres(audio, tags); - // There's several values in tags may or may not be present FetchStudios(audio, tags, "organization"); FetchStudios(audio, tags, "ensemble"); @@ -693,7 +721,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// /// The information. /// The tags. - private void FetchGenres(Model.MediaInfo.MediaInfo info, Dictionary tags) + private void FetchGenres(MediaInfo info, Dictionary tags) { var val = FFProbeHelpers.GetDictionaryValue(tags, "genre"); @@ -764,7 +792,7 @@ namespace MediaBrowser.MediaEncoding.Probing private const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames) - private void FetchWtvInfo(Model.MediaInfo.MediaInfo video, InternalMediaInfoResult data) + private void FetchWtvInfo(MediaInfo video, InternalMediaInfoResult data) { if (data.format == null || data.format.tags == null) { @@ -775,15 +803,16 @@ namespace MediaBrowser.MediaEncoding.Probing if (!string.IsNullOrWhiteSpace(genres)) { - //genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "genre"); - } - - if (!string.IsNullOrWhiteSpace(genres)) - { - video.Genres = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries) + var genreList = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries) .Where(i => !string.IsNullOrWhiteSpace(i)) .Select(i => i.Trim()) .ToList(); + + // If this is empty then don't overwrite genres that might have been fetched earlier + if (genreList.Count > 0) + { + video.Genres = genreList; + } } var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating"); diff --git a/MediaBrowser.Model/MediaInfo/MediaInfo.cs b/MediaBrowser.Model/MediaInfo/MediaInfo.cs index 21f258693..126710197 100644 --- a/MediaBrowser.Model/MediaInfo/MediaInfo.cs +++ b/MediaBrowser.Model/MediaInfo/MediaInfo.cs @@ -9,11 +9,6 @@ namespace MediaBrowser.Model.MediaInfo { public List Chapters { get; set; } - /// - /// Gets or sets the title. - /// - /// The title. - public string Title { get; set; } /// /// Gets or sets the album. /// @@ -47,6 +42,11 @@ namespace MediaBrowser.Model.MediaInfo /// The official rating. public string OfficialRating { get; set; } /// + /// Gets or sets the official rating description. + /// + /// The official rating description. + public string OfficialRatingDescription { get; set; } + /// /// Gets or sets the overview. /// /// The overview. diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index 4cf507d15..78906fa85 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -125,9 +125,9 @@ namespace MediaBrowser.Providers.MediaInfo private async Task FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data) { // Only set Name if title was found in the dictionary - if (!string.IsNullOrEmpty(data.Title)) + if (!string.IsNullOrEmpty(data.Name)) { - audio.Name = data.Title; + audio.Name = data.Name; } if (!audio.LockedFields.Contains(MetadataFields.Cast)) diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index ebbc045ab..fb8e25892 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -383,6 +383,11 @@ namespace MediaBrowser.Providers.MediaInfo } } + if (!string.IsNullOrWhiteSpace(data.OfficialRatingDescription) || isFullRefresh) + { + video.OfficialRatingDescription = data.OfficialRatingDescription; + } + if (!video.LockedFields.Contains(MetadataFields.Genres)) { if (video.Genres.Count == 0 || isFullRefresh) @@ -437,6 +442,13 @@ namespace MediaBrowser.Providers.MediaInfo video.ParentIndexNumber = data.ParentIndexNumber; } } + if (!string.IsNullOrWhiteSpace(data.Name)) + { + if (string.IsNullOrWhiteSpace(video.Name) || string.Equals(video.Name, Path.GetFileNameWithoutExtension(video.Path), StringComparison.OrdinalIgnoreCase)) + { + video.Name = data.Name; + } + } // If we don't have a ProductionYear try and get it from PremiereDate if (video.PremiereDate.HasValue && !video.ProductionYear.HasValue) diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 9de20cb39..d4d8be7f1 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -140,6 +140,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -254,9 +257,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest From f1745245bac82ad7a6e2b0a647f1ff9092610d9a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 17 Feb 2016 22:18:35 -0500 Subject: [PATCH 007/111] add comment --- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index db6278bd4..ec51bc967 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -151,7 +151,7 @@ namespace MediaBrowser.MediaEncoding.Probing private void FetchFromItunesInfo(string xml, MediaInfo info) { - + // \n\n\n\n\tcast\n\t\n\t\t\n\t\t\tname\n\t\t\tBlender Foundation\n\t\t\n\t\t\n\t\t\tname\n\t\t\tJanus Bager Kristensen\n\t\t\n\t\n\tdirectors\n\t\n\t\t\n\t\t\tname\n\t\t\tSacha Goedegebure\n\t\t\n\t\n\tstudio\n\tBlender Foundation\n\n\n } /// From 1bfde59af4ed6ea181c44582f3c716c32c141eca Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Feb 2016 13:21:53 -0500 Subject: [PATCH 008/111] 3.0.5881 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 033efbbd7..716319839 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5871")] +[assembly: AssemblyVersion("3.0.5881")] From eea19c3adcdc47e894d8e557cfc5db42032302b2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Feb 2016 13:27:46 -0500 Subject: [PATCH 009/111] update authentication --- MediaBrowser.Model/Configuration/ServerConfiguration.cs | 7 ------- .../HttpServer/Security/AuthService.cs | 9 +++------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 3cb543e5d..bc102bd40 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -182,8 +182,6 @@ namespace MediaBrowser.Model.Configuration public PeopleMetadataOptions PeopleMetadataOptions { get; set; } public bool FindInternetTrailers { get; set; } - public string[] InsecureApps9 { get; set; } - public bool SaveMetadataHidden { get; set; } public NameValuePair[] ContentTypes { get; set; } @@ -256,11 +254,6 @@ namespace MediaBrowser.Model.Configuration PeopleMetadataOptions = new PeopleMetadataOptions(); - InsecureApps9 = new[] - { - "Windows Phone" - }; - MetadataOptions = new[] { new MetadataOptions(1, 1280) {ItemType = "Book"}, diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs index f6b14fcab..d8f7d889c 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs @@ -134,20 +134,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues) { - if (!_config.Configuration.IsStartupWizardCompleted && - authAttribtues.AllowBeforeStartupWizard) + if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) { return true; } - return _config.Configuration.InsecureApps9.Contains(auth.Client ?? string.Empty, - StringComparer.OrdinalIgnoreCase); + return false; } private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, AuthenticationInfo tokenInfo) { - if (!_config.Configuration.IsStartupWizardCompleted && - authAttribtues.AllowBeforeStartupWizard) + if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) { return true; } From bc6e47c30a456a2cb461ced0598675acfc5a6f62 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Feb 2016 14:15:26 -0500 Subject: [PATCH 010/111] removed dead code --- MediaBrowser.Api/ConnectService.cs | 55 +----------- .../Connect/IConnectManager.cs | 20 ----- .../Connect/ConnectManager.cs | 88 +------------------ 3 files changed, 3 insertions(+), 160 deletions(-) diff --git a/MediaBrowser.Api/ConnectService.cs b/MediaBrowser.Api/ConnectService.cs index bdd2eeaad..4bcd33d9e 100644 --- a/MediaBrowser.Api/ConnectService.cs +++ b/MediaBrowser.Api/ConnectService.cs @@ -1,10 +1,8 @@ -using System; -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Connect; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Connect; -using MediaBrowser.Model.Dto; using ServiceStack; using System.Collections.Generic; using System.Linq; @@ -75,28 +73,6 @@ namespace MediaBrowser.Api public string ConnectUserId { get; set; } } - [Route("/Connect/Supporters", "GET")] - [Authenticated(Roles = "Admin")] - public class GetConnectSupporterSummary : IReturn - { - } - - [Route("/Connect/Supporters", "DELETE")] - [Authenticated(Roles = "Admin")] - public class RemoveConnectSupporter : IReturnVoid - { - [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")] - public string Id { get; set; } - } - - [Route("/Connect/Supporters", "POST")] - [Authenticated(Roles = "Admin")] - public class AddConnectSupporter : IReturnVoid - { - [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Id { get; set; } - } - public class ConnectService : BaseApiService { private readonly IConnectManager _connectManager; @@ -108,35 +84,6 @@ namespace MediaBrowser.Api _userManager = userManager; } - public async Task Get(GetConnectSupporterSummary request) - { - var result = await _connectManager.GetConnectSupporterSummary().ConfigureAwait(false); - var existingConnectUserIds = result.Users.Select(i => i.Id).ToList(); - - result.EligibleUsers = _userManager.Users - .Where(i => !string.IsNullOrWhiteSpace(i.ConnectUserId)) - .Where(i => !existingConnectUserIds.Contains(i.ConnectUserId, StringComparer.OrdinalIgnoreCase)) - .OrderBy(i => i.Name) - .Select(i => _userManager.GetUserDto(i)) - .ToList(); - - return ToOptimizedResult(result); - } - - public void Delete(RemoveConnectSupporter request) - { - var task = _connectManager.RemoveConnectSupporter(request.Id); - - Task.WaitAll(task); - } - - public void Post(AddConnectSupporter request) - { - var task = _connectManager.AddConnectSupporter(request.Id); - - Task.WaitAll(task); - } - public object Post(CreateConnectLink request) { return _connectManager.LinkUser(request.Id, request.ConnectUsername); diff --git a/MediaBrowser.Controller/Connect/IConnectManager.cs b/MediaBrowser.Controller/Connect/IConnectManager.cs index 1f7652221..e004eaccf 100644 --- a/MediaBrowser.Controller/Connect/IConnectManager.cs +++ b/MediaBrowser.Controller/Connect/IConnectManager.cs @@ -76,25 +76,5 @@ namespace MediaBrowser.Controller.Connect /// The token. /// true if [is authorization token valid] [the specified token]; otherwise, false. bool IsAuthorizationTokenValid(string token); - - /// - /// Gets the connect supporter summary. - /// - /// Task<ConnectSupporterSummary>. - Task GetConnectSupporterSummary(); - - /// - /// Removes the connect supporter. - /// - /// The identifier. - /// Task. - Task RemoveConnectSupporter(string id); - - /// - /// Adds the connect supporter. - /// - /// The identifier. - /// Task. - Task AddConnectSupporter(string id); } } diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index fdc7e9ee2..cff95b184 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -1071,90 +1071,6 @@ namespace MediaBrowser.Server.Implementations.Connect } } - public async Task GetConnectSupporterSummary() - { - var url = GetConnectUrl("keyAssociation"); - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None - }; - - var postData = new Dictionary - { - {"serverId", ConnectServerId}, - {"supporterKey", _securityManager.SupporterKey} - }; - - options.SetPostData(postData); - - SetServerAccessToken(options); - SetApplicationHeader(options); - - // No need to examine the response - using (var stream = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content) - { - return _json.DeserializeFromStream(stream); - } - } - - public async Task AddConnectSupporter(string id) - { - var url = GetConnectUrl("keyAssociation"); - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None - }; - - var postData = new Dictionary - { - {"serverId", ConnectServerId}, - {"supporterKey", _securityManager.SupporterKey}, - {"userId", id} - }; - - options.SetPostData(postData); - - SetServerAccessToken(options); - SetApplicationHeader(options); - - // No need to examine the response - using (var stream = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content) - { - } - } - - public async Task RemoveConnectSupporter(string id) - { - var url = GetConnectUrl("keyAssociation"); - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = CancellationToken.None - }; - - var postData = new Dictionary - { - {"serverId", ConnectServerId}, - {"supporterKey", _securityManager.SupporterKey}, - {"userId", id} - }; - - options.SetPostData(postData); - - SetServerAccessToken(options); - SetApplicationHeader(options); - - // No need to examine the response - using (var stream = (await _httpClient.SendAsync(options, "DELETE").ConfigureAwait(false)).Content) - { - } - } - public async Task Authenticate(string username, string passwordMd5) { if (string.IsNullOrWhiteSpace(username)) @@ -1188,9 +1104,9 @@ namespace MediaBrowser.Server.Implementations.Connect async void _userManager_UserConfigurationUpdated(object sender, GenericEventArgs e) { - var user = e.Argument; + //var user = e.Argument; - await TryUploadUserPreferences(user, CancellationToken.None).ConfigureAwait(false); + //await TryUploadUserPreferences(user, CancellationToken.None).ConfigureAwait(false); } private async Task TryUploadUserPreferences(User user, CancellationToken cancellationToken) From e096a400cd6b5aa4105a008ada82834a5afd7d16 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Feb 2016 01:20:18 -0500 Subject: [PATCH 011/111] update sat discovery --- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 3 + .../LiveTv/LiveTvManager.cs | 6 +- .../LiveTv/TunerHosts/BaseTunerHost.cs | 2 +- .../TunerHosts/HdHomerun/HdHomerunHost.cs | 2 +- .../LiveTv/TunerHosts/M3UTunerHost.cs | 81 +------- .../LiveTv/TunerHosts/M3uParser.cs | 102 ++++++++++ .../LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs | 192 +++++++++++++----- .../LiveTv/TunerHosts/SatIp/SatIpHost.cs | 175 +++++++++++++--- ...MediaBrowser.Server.Implementations.csproj | 1 + 9 files changed, 399 insertions(+), 165 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 2e3a71f70..498602ddf 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -46,6 +46,9 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// Task<List<MediaSourceInfo>>. Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); + } + public interface IConfigurableTunerHost + { /// /// Validates the specified information. /// diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 14bfcba27..7c26f5675 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -2343,7 +2343,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv throw new ResourceNotFoundException(); } - await provider.Validate(info).ConfigureAwait(false); + var configurable = provider as IConfigurableTunerHost; + if (configurable != null) + { + await configurable.Validate(info).ConfigureAwait(false); + } var config = GetConfiguration(); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 4ebc173b5..fb27631e5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -64,7 +64,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return list; } - private List GetTunerHosts() + protected virtual List GetTunerHosts() { return GetConfiguration().TunerHosts .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 0671a9b56..013dabe26 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -20,7 +20,7 @@ using MediaBrowser.Model.Dlna; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun { - public class HdHomerunHost : BaseTunerHost, ITunerHost + public class HdHomerunHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost { private readonly IHttpClient _httpClient; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index f87d4f43f..17e52fb8e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -8,19 +8,17 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; -using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Serialization; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { - public class M3UTunerHost : BaseTunerHost, ITunerHost + public class M3UTunerHost : BaseTunerHost, ITunerHost, IConfigurableTunerHost { private readonly IFileSystem _fileSystem; private readonly IHttpClient _httpClient; @@ -46,65 +44,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts protected override async Task> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken) { - var urlHash = info.Url.GetMD5().ToString("N"); - - // Read the file and display it line by line. - using (var reader = new StreamReader(await GetListingsStream(info, cancellationToken).ConfigureAwait(false))) - { - return GetChannels(reader, urlHash); - } - } - - private List GetChannels(StreamReader reader, string urlHash) - { - var channels = new List(); - - string channnelName = null; - string channelNumber = null; - string line; - - while ((line = reader.ReadLine()) != null) - { - line = line.Trim(); - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - if (line.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - if (line.StartsWith("#EXTINF:", StringComparison.OrdinalIgnoreCase)) - { - line = line.Substring(8); - Logger.Info("Found m3u channel: {0}", line); - var parts = line.Split(new[] { ',' }, 2); - channelNumber = parts[0]; - channnelName = parts[1]; - } - else if (!string.IsNullOrWhiteSpace(channelNumber)) - { - channels.Add(new M3UChannel - { - Name = channnelName, - Number = channelNumber, - Id = ChannelIdPrefix + urlHash + line.GetMD5().ToString("N"), - Path = line - }); - - channelNumber = null; - channnelName = null; - } - } - return channels; + return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(info.Url, ChannelIdPrefix, cancellationToken).ConfigureAwait(false); } public Task> GetTunerInfos(CancellationToken cancellationToken) { - var list = GetConfiguration().TunerHosts - .Where(i => i.IsEnabled && string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)) + var list = GetTunerHosts() .Select(i => new LiveTvTunerInfo() { Name = Name, @@ -125,18 +70,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return sources.First(); } - class M3UChannel : ChannelInfo - { - public string Path { get; set; } - - public M3UChannel() - { - } - } - public async Task Validate(TunerHostInfo info) { - using (var stream = await GetListingsStream(info, CancellationToken.None).ConfigureAwait(false)) + using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false)) { } @@ -147,15 +83,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); } - private Task GetListingsStream(TunerHostInfo info, CancellationToken cancellationToken) - { - if (info.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - return _httpClient.Get(info.Url, cancellationToken); - } - return Task.FromResult(_fileSystem.OpenRead(info.Url)); - } - protected override async Task> GetChannelStreamMediaSources(TunerHostInfo info, string channelId, CancellationToken cancellationToken) { var urlHash = info.Url.GetMD5().ToString("N"); diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs new file mode 100644 index 000000000..8f5a4a095 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using CommonIO; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Logging; + +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts +{ + public class M3uParser + { + private readonly ILogger _logger; + private readonly IFileSystem _fileSystem; + private readonly IHttpClient _httpClient; + + public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient) + { + _logger = logger; + _fileSystem = fileSystem; + _httpClient = httpClient; + } + + public async Task> Parse(string url, string channelIdPrefix, CancellationToken cancellationToken) + { + var urlHash = url.GetMD5().ToString("N"); + + // Read the file and display it line by line. + using (var reader = new StreamReader(await GetListingsStream(url, cancellationToken).ConfigureAwait(false))) + { + return GetChannels(reader, urlHash, channelIdPrefix); + } + } + + public Task GetListingsStream(string url, CancellationToken cancellationToken) + { + if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + return _httpClient.Get(url, cancellationToken); + } + return Task.FromResult(_fileSystem.OpenRead(url)); + } + + private List GetChannels(StreamReader reader, string urlHash, string channelIdPrefix) + { + var channels = new List(); + + string channnelName = null; + string channelNumber = null; + string line; + + while ((line = reader.ReadLine()) != null) + { + line = line.Trim(); + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + if (line.StartsWith("#EXTM3U", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + if (line.StartsWith("#EXTINF:", StringComparison.OrdinalIgnoreCase)) + { + line = line.Substring(8); + _logger.Info("Found m3u channel: {0}", line); + var parts = line.Split(new[] { ',' }, 2); + channelNumber = parts[0]; + channnelName = parts[1]; + } + else if (!string.IsNullOrWhiteSpace(channelNumber)) + { + channels.Add(new M3UChannel + { + Name = channnelName, + Number = channelNumber, + Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N"), + Path = line + }); + + channelNumber = null; + channnelName = null; + } + } + return channels; + } + } + + public class M3UChannel : ChannelInfo + { + public string Path { get; set; } + + public M3UChannel() + { + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs index 852b86467..233b27c3d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Xml; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; @@ -13,6 +16,7 @@ using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp { @@ -24,14 +28,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp private readonly ILiveTvManager _liveTvManager; private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private readonly IHttpClient _httpClient; + private readonly IJsonSerializer _json; - public SatIpDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager, IHttpClient httpClient) + public static SatIpDiscovery Current; + + private readonly List _discoveredHosts = new List(); + + public List DiscoveredHosts + { + get { return _discoveredHosts.ToList(); } + } + + public SatIpDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager, IHttpClient httpClient, IJsonSerializer json) { _deviceDiscovery = deviceDiscovery; _config = config; _logger = logger; _liveTvManager = liveTvManager; _httpClient = httpClient; + _json = json; + Current = this; } public void Run() @@ -66,26 +82,23 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp try { - var options = GetConfiguration(); + if (_discoveredHosts.Any(i => string.Equals(i.Type, SatIpHost.DeviceType, StringComparison.OrdinalIgnoreCase) && string.Equals(location, i.Url, StringComparison.OrdinalIgnoreCase))) + { + return; + } - //if (options.TunerHosts.Any(i => - // string.Equals(i.Type, SatIpHost.DeviceType, StringComparison.OrdinalIgnoreCase) && - // UriEquals(i.Url, url))) - //{ - // return; - //} + _logger.Debug("Will attempt to add SAT device {0}", location); + var info = await GetInfo(location, CancellationToken.None).ConfigureAwait(false); - //// Strip off the port - //url = new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped).TrimEnd('/'); + _discoveredHosts.Add(info); + } + catch (OperationCanceledException) + { - //await TestUrl(url).ConfigureAwait(false); - - //await _liveTvManager.SaveTunerHost(new TunerHostInfo - //{ - // Type = SatIpHost.DeviceType, - // Url = url - - //}).ConfigureAwait(false); + } + catch (NotImplementedException) + { + } catch (Exception ex) { @@ -97,43 +110,116 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp } } - private async Task TestUrl(string url) - { - // Test it by pulling down the lineup - using (await _httpClient.Get(new HttpRequestOptions - { - Url = string.Format("{0}/lineup.json", url), - CancellationToken = CancellationToken.None - })) - { - } - } - - private bool UriEquals(string savedUri, string location) - { - return string.Equals(NormalizeUrl(location), NormalizeUrl(savedUri), StringComparison.OrdinalIgnoreCase); - } - - private string NormalizeUrl(string url) - { - if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) - { - url = "http://" + url; - } - - url = url.TrimEnd('/'); - - // Strip off the port - return new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped); - } - - private LiveTvOptions GetConfiguration() - { - return _config.GetConfiguration("livetv"); - } - public void Dispose() { } + + public async Task GetInfo(string url, CancellationToken cancellationToken) + { + var result = new SatIpTunerHostInfo + { + Url = url, + IsEnabled = true, + Type = SatIpHost.DeviceType, + Tuners = 1, + TunersAvailable = 1 + }; + + using (var stream = await _httpClient.Get(url, cancellationToken).ConfigureAwait(false)) + { + using (var streamReader = new StreamReader(stream)) + { + // Use XmlReader for best performance + using (var reader = XmlReader.Create(streamReader)) + { + reader.MoveToContent(); + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "device": + using (var subtree = reader.ReadSubtree()) + { + FillFromDeviceNode(result, subtree); + } + break; + default: + reader.Skip(); + break; + } + } + } + } + } + } + + if (string.IsNullOrWhiteSpace(result.Id)) + { + throw new NotImplementedException(); + } + + if (string.IsNullOrWhiteSpace(result.M3UUrl)) + { + throw new NotImplementedException(); + } + + if (!result.M3UUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + var fullM3uUrl = url.Substring(0, url.LastIndexOf('/')); + result.M3UUrl = fullM3uUrl + "/" + result.M3UUrl.TrimStart('/'); + } + + _logger.Debug("SAT device result: {0}", _json.SerializeToString(result)); + + return result; + } + + private void FillFromDeviceNode(SatIpTunerHostInfo info, XmlReader reader) + { + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "UDN": + { + info.Id = reader.ReadElementContentAsString(); + break; + } + + case "X_SATIPCAP": + { + var value = reader.ReadElementContentAsString(); + // TODO + break; + } + + case "X_SATIPM3U": + { + info.M3UUrl = reader.ReadElementContentAsString(); + break; + } + + default: + reader.Skip(); + break; + } + } + } + } + } + + public class SatIpTunerHostInfo : TunerHostInfo + { + public int Tuners { get; set; } + public int TunersAvailable { get; set; } + public string M3UUrl { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs index 205cdf74e..480f0edd0 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs @@ -1,45 +1,156 @@ -namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp -{ - public class SatIpHost /*: BaseTunerHost*/ - { - //public SatIpHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder) - // : base(config, logger, jsonSerializer, mediaEncoder) - //{ - //} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using CommonIO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; - //protected override Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken) - //{ - // throw new NotImplementedException(); - //} +namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp +{ + public class SatIpHost : BaseTunerHost, ITunerHost + { + private readonly IFileSystem _fileSystem; + private readonly IHttpClient _httpClient; + + public SatIpHost(IConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient) + : base(config, logger, jsonSerializer, mediaEncoder) + { + _fileSystem = fileSystem; + _httpClient = httpClient; + } + + private const string ChannelIdPrefix = "sat_"; + + protected override async Task> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken) + { + var satInfo = (SatIpTunerHostInfo) tuner; + + return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(satInfo.M3UUrl, ChannelIdPrefix, cancellationToken).ConfigureAwait(false); + } public static string DeviceType { get { return "satip"; } } - //public override string Type - //{ - // get { return DeviceType; } - //} + public override string Type + { + get { return DeviceType; } + } - //protected override Task> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) - //{ - // throw new NotImplementedException(); - //} + protected override async Task> GetChannelStreamMediaSources(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) + { + var urlHash = tuner.Url.GetMD5().ToString("N"); + var prefix = ChannelIdPrefix + urlHash; + if (!channelId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + { + return null; + } - //protected override Task GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken) - //{ - // throw new NotImplementedException(); - //} + var channels = await GetChannels(tuner, true, cancellationToken).ConfigureAwait(false); + var m3uchannels = channels.Cast(); + var channel = m3uchannels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase)); + if (channel != null) + { + var path = channel.Path; + MediaProtocol protocol = MediaProtocol.File; + if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + { + protocol = MediaProtocol.Http; + } + else if (path.StartsWith("rtmp", StringComparison.OrdinalIgnoreCase)) + { + protocol = MediaProtocol.Rtmp; + } + else if (path.StartsWith("rtsp", StringComparison.OrdinalIgnoreCase)) + { + protocol = MediaProtocol.Rtsp; + } - //protected override Task IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) - //{ - // throw new NotImplementedException(); - //} + var mediaSource = new MediaSourceInfo + { + Path = channel.Path, + Protocol = protocol, + MediaStreams = new List + { + new MediaStream + { + Type = MediaStreamType.Video, + // Set the index to -1 because we don't know the exact index of the video stream within the container + Index = -1, + IsInterlaced = true + }, + new MediaStream + { + Type = MediaStreamType.Audio, + // Set the index to -1 because we don't know the exact index of the audio stream within the container + Index = -1 - //protected override bool IsValidChannelId(string channelId) - //{ - // throw new NotImplementedException(); - //} + } + }, + RequiresOpening = false, + RequiresClosing = false + }; + + return new List { mediaSource }; + } + return new List { }; + } + + protected override async Task GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken) + { + var sources = await GetChannelStreamMediaSources(tuner, channelId, cancellationToken).ConfigureAwait(false); + + return sources.First(); + } + + protected override async Task IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) + { + var updatedInfo = await SatIpDiscovery.Current.GetInfo(tuner.Url, cancellationToken).ConfigureAwait(false); + + return updatedInfo.TunersAvailable > 0; + } + + protected override bool IsValidChannelId(string channelId) + { + return channelId.StartsWith(ChannelIdPrefix, StringComparison.OrdinalIgnoreCase); + } + + protected override List GetTunerHosts() + { + return SatIpDiscovery.Current.DiscoveredHosts; + } + + public string Name + { + get { return "Sat IP"; } + } + + public Task> GetTunerInfos(CancellationToken cancellationToken) + { + var list = GetTunerHosts() + .Select(i => new LiveTvTunerInfo() + { + Name = Name, + SourceType = Type, + Status = LiveTvTunerStatus.Available, + Id = i.Url.GetMD5().ToString("N"), + Url = i.Url + }) + .ToList(); + + return Task.FromResult(list); + } } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 80592c724..21066a9f4 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -234,6 +234,7 @@ + From 3c2cb7701f0885bb2209de0fc9eee4dde328750e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Feb 2016 01:23:59 -0500 Subject: [PATCH 012/111] comments --- .../LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs index 233b27c3d..2681ec4c4 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs @@ -196,6 +196,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp case "X_SATIPCAP": { + // DVBS2-2 var value = reader.ReadElementContentAsString(); // TODO break; @@ -203,6 +204,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp case "X_SATIPM3U": { + // /channellist.lua?select=m3u info.M3UUrl = reader.ReadElementContentAsString(); break; } From d2e62c5ba88ad46c7f6af21a8f338b95ed19381c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Feb 2016 12:14:42 -0500 Subject: [PATCH 013/111] update satip discovery --- .../Connect/ConnectManager.cs | 61 ------------------- .../Security/AuthorizationContext.cs | 5 -- .../LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs | 7 ++- 3 files changed, 5 insertions(+), 68 deletions(-) diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index cff95b184..d7477225c 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -10,7 +10,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Security; using MediaBrowser.Model.Connect; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; @@ -24,7 +23,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using CommonIO; -using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.Connect { @@ -121,7 +119,6 @@ namespace MediaBrowser.Server.Implementations.Connect _securityManager = securityManager; _fileSystem = fileSystem; - _userManager.UserConfigurationUpdated += _userManager_UserConfigurationUpdated; _config.ConfigurationUpdated += _config_ConfigurationUpdated; LoadCachedData(); @@ -1102,64 +1099,6 @@ namespace MediaBrowser.Server.Implementations.Connect } } - async void _userManager_UserConfigurationUpdated(object sender, GenericEventArgs e) - { - //var user = e.Argument; - - //await TryUploadUserPreferences(user, CancellationToken.None).ConfigureAwait(false); - } - - private async Task TryUploadUserPreferences(User user, CancellationToken cancellationToken) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - if (string.IsNullOrEmpty(user.ConnectUserId)) - { - return; - } - if (string.IsNullOrEmpty(ConnectAccessKey)) - { - return; - } - - var url = GetConnectUrl("user/preferences"); - url += "?userId=" + user.ConnectUserId; - url += "&key=userpreferences"; - - var options = new HttpRequestOptions - { - Url = url, - CancellationToken = cancellationToken - }; - - var postData = new Dictionary(); - postData["data"] = _json.SerializeToString(ConnectUserPreferences.FromUserConfiguration(user.Configuration)); - options.SetPostData(postData); - - SetServerAccessToken(options); - SetApplicationHeader(options); - - try - { - // No need to examine the response - using (var stream = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content) - { - } - } - catch (Exception ex) - { - _logger.ErrorException("Error uploading user preferences", ex); - } - } - - private async Task DownloadUserPreferences(User user, CancellationToken cancellationToken) - { - - } - public async Task GetLocalUser(string connectUserId) { var user = _userManager.Users diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index 75d54a80a..357f5c976 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -45,7 +45,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security { var auth = GetAuthorizationDictionary(httpReq); - string userId = null; string deviceId = null; string device = null; string client = null; @@ -53,9 +52,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security if (auth != null) { - // TODO: Remove this - auth.TryGetValue("UserId", out userId); - auth.TryGetValue("DeviceId", out deviceId); auth.TryGetValue("Device", out device); auth.TryGetValue("Client", out client); @@ -78,7 +74,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security Client = client, Device = device, DeviceId = deviceId, - UserId = userId, Version = version, Token = token }; diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs index 2681ec4c4..53f97f76f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs @@ -162,12 +162,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp throw new NotImplementedException(); } + // Device hasn't implemented an m3u list if (string.IsNullOrWhiteSpace(result.M3UUrl)) { - throw new NotImplementedException(); + result.IsEnabled = false; } - if (!result.M3UUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase)) + else if (!result.M3UUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { var fullM3uUrl = url.Substring(0, url.LastIndexOf('/')); result.M3UUrl = fullM3uUrl + "/" + result.M3UUrl.TrimStart('/'); @@ -194,6 +195,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp break; } + case "satip:X_SATIPCAP": case "X_SATIPCAP": { // DVBS2-2 @@ -202,6 +204,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp break; } + case "satip:X_SATIPM3U": case "X_SATIPM3U": { // /channellist.lua?select=m3u From 6dfebf40f32d31980d7a9c68a3bc0d6f86e14c8d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Feb 2016 12:20:35 -0500 Subject: [PATCH 014/111] 3.0.5882 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 716319839..e1c8f8995 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5881")] +[assembly: AssemblyVersion("3.0.5882")] From fe0f3e28a0d2ee330cdcbe77c244c59e0ec08e88 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Feb 2016 13:09:38 -0500 Subject: [PATCH 015/111] add audio sync to recordings --- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 5f4d32732..38f35f4cc 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -116,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV videoArgs = "-codec:v:0 copy"; } - var commandLineArgs = "-fflags +genpts -i \"{0}\" -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\""; + var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -i \"{0}\" -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\""; if (mediaSource.ReadAtNativeFramerate) { From 2002b0ef39d59184fd2d30aa4e5f409591ca8671 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 19 Feb 2016 21:45:12 -0500 Subject: [PATCH 016/111] update sat discovery --- .../LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs index 53f97f76f..48337b923 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs @@ -187,7 +187,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp { if (reader.NodeType == XmlNodeType.Element) { - switch (reader.Name) + switch (reader.LocalName) { case "UDN": { From dacdfd272a76ea46abaff1d649c8d936896bdab3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 20 Feb 2016 01:57:17 -0500 Subject: [PATCH 017/111] fix subtitle position after seek in chrome --- .../Playback/BaseStreamingService.cs | 16 ++++++++++++++-- .../Playback/Progressive/VideoService.cs | 4 ++-- MediaBrowser.Api/Playback/StreamRequest.cs | 3 +++ .../MediaEncoding/EncodingJobOptions.cs | 1 + .../Encoder/EncodingJobFactory.cs | 2 ++ MediaBrowser.Model/Dlna/StreamBuilder.cs | 1 + MediaBrowser.Model/Dlna/StreamInfo.cs | 5 ++++- MediaBrowser.Model/Dlna/TranscodingProfile.cs | 3 +++ 8 files changed, 30 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bae8074fd..33995bee3 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1462,6 +1462,13 @@ namespace MediaBrowser.Api.Playback { // Duplicating ItemId because of MediaMonkey } + else if (i == 24) + { + if (videoRequest != null) + { + videoRequest.CopyTimestamps = string.Equals("true", val, StringComparison.OrdinalIgnoreCase); + } + } } } @@ -2021,6 +2028,11 @@ namespace MediaBrowser.Api.Playback state.EstimateContentLength = transcodingProfile.EstimateContentLength; state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; + + if (state.VideoRequest != null) + { + state.VideoRequest.CopyTimestamps = transcodingProfile.CopyTimestamps; + } } } } @@ -2184,9 +2196,9 @@ namespace MediaBrowser.Api.Playback if (state.VideoRequest != null) { - if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase) && state.VideoRequest.CopyTimestamps) { - //inputModifier += " -noaccurate_seek"; + inputModifier += " -noaccurate_seek"; } } diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index eaf65bd6b..50aa2df19 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -137,9 +137,9 @@ namespace MediaBrowser.Api.Playback.Progressive var isOutputMkv = string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase); - if (state.RunTimeTicks.HasValue) + if (state.RunTimeTicks.HasValue && state.VideoRequest.CopyTimestamps) { - //args += " -copyts -avoid_negative_ts disabled -start_at_zero"; + args += " -copyts -avoid_negative_ts disabled -start_at_zero"; } if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index 69f8e6e04..1135a3a54 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/MediaBrowser.Api/Playback/StreamRequest.cs @@ -187,6 +187,9 @@ namespace MediaBrowser.Api.Playback [ApiMember(Name = "EnableAutoStreamCopy", Description = "Whether or not to allow automatic stream copy if requested values match the original source. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool EnableAutoStreamCopy { get; set; } + [ApiMember(Name = "CopyTimestamps", Description = "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] + public bool CopyTimestamps { get; set; } + [ApiMember(Name = "Cabac", Description = "Enable if cabac encoding is required", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? Cabac { get; set; } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index bb8841222..f8f4e9ec9 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -44,6 +44,7 @@ namespace MediaBrowser.Controller.MediaEncoding public int? CpuCoreLimit { get; set; } public bool ReadInputAtNativeFramerate { get; set; } public SubtitleDeliveryMethod SubtitleMethod { get; set; } + public bool CopyTimestamps { get; set; } /// /// Gets a value indicating whether this instance has fixed resolution. diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index 252386af0..c64b574a9 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -794,6 +794,8 @@ namespace MediaBrowser.MediaEncoding.Encoder state.EstimateContentLength = transcodingProfile.EstimateContentLength; state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; + + state.Options.CopyTimestamps = transcodingProfile.CopyTimestamps; } } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index c2713a6e7..d4ca379c0 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -425,6 +425,7 @@ namespace MediaBrowser.Model.Dlna playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',')[0]; playlistItem.VideoCodec = transcodingProfile.VideoCodec; + playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps; playlistItem.SubProtocol = transcodingProfile.Protocol; playlistItem.AudioStreamIndex = audioStreamIndex; diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index f5c54e160..79ee1b5c5 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -32,6 +32,7 @@ namespace MediaBrowser.Model.Dlna public string VideoProfile { get; set; } public bool? Cabac { get; set; } + public bool CopyTimestamps { get; set; } public string AudioCodec { get; set; } public int? AudioStreamIndex { get; set; } @@ -231,6 +232,8 @@ namespace MediaBrowser.Model.Dlna { list.Add(new NameValuePair("ItemId", item.ItemId)); } + + list.Add(new NameValuePair("CopyTimestamps", (item.CopyTimestamps).ToString().ToLower())); return list; } @@ -269,7 +272,7 @@ namespace MediaBrowser.Model.Dlna // HLS will preserve timestamps so we can just grab the full subtitle stream long startPositionTicks = StringHelper.EqualsIgnoreCase(SubProtocol, "hls") ? 0 - : (this.PlayMethod == PlayMethod.Transcode ? StartPositionTicks : 0); + : (PlayMethod == PlayMethod.Transcode && !CopyTimestamps ? StartPositionTicks : 0); // First add the selected track if (SubtitleStreamIndex.HasValue) diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs index d9963eb75..e59ee6d63 100644 --- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs @@ -29,6 +29,9 @@ namespace MediaBrowser.Model.Dlna [XmlAttribute("transcodeSeekInfo")] public TranscodeSeekInfo TranscodeSeekInfo { get; set; } + [XmlAttribute("copyTimestamps")] + public bool CopyTimestamps { get; set; } + [XmlAttribute("context")] public EncodingContext Context { get; set; } From 08c78a4f351f6d38199df639e0cfaa8ab4ea11f2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 20 Feb 2016 14:20:32 -0500 Subject: [PATCH 018/111] 3.0.5883 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index e1c8f8995..53fccc03a 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5882")] +[assembly: AssemblyVersion("3.0.5883")] From e700aff047816e26666856614b89c2ea4a014907 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 20 Feb 2016 18:06:57 -0500 Subject: [PATCH 019/111] remember user audio/subtitle selections --- .../Entities/IHasMediaSources.cs | 2 +- .../Entities/UserItemData.cs | 12 +++- .../Dto/DtoService.cs | 2 + .../Library/MediaSourceManager.cs | 60 +++++++++++++++---- .../Persistence/SqliteUserDataRepository.cs | 25 ++++++-- .../Session/SessionManager.cs | 14 ++++- .../ApplicationHost.cs | 2 +- 7 files changed, 97 insertions(+), 20 deletions(-) diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs index 85ce3c781..832b9f6c1 100644 --- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs +++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { - public interface IHasMediaSources : IHasId + public interface IHasMediaSources : IHasUserData { /// /// Gets the media sources. diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs index 5f0e62537..16c37e7d3 100644 --- a/MediaBrowser.Controller/Entities/UserItemData.cs +++ b/MediaBrowser.Controller/Entities/UserItemData.cs @@ -78,7 +78,17 @@ namespace MediaBrowser.Controller.Entities /// /// true if played; otherwise, false. public bool Played { get; set; } - + /// + /// Gets or sets the index of the audio stream. + /// + /// The index of the audio stream. + public int? AudioStreamIndex { get; set; } + /// + /// Gets or sets the index of the subtitle stream. + /// + /// The index of the subtitle stream. + public int? SubtitleStreamIndex { get; set; } + /// /// This is an interpreted property to indicate likes or dislikes /// This should never be serialized. diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 590c5fd3f..07686e91c 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -639,6 +639,8 @@ namespace MediaBrowser.Server.Implementations.Dto private IEnumerable GetCacheTags(BaseItem item, ImageType type, int limit) { return item.GetImages(type) + // Convert to a list now in case GetImageCacheTag is slow + .ToList() .Select(p => GetImageCacheTag(item, p)) .Where(i => i != null) .Take(limit) diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index b132eedec..caddeec0d 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -30,8 +30,9 @@ namespace MediaBrowser.Server.Implementations.Library private IMediaSourceProvider[] _providers; private readonly ILogger _logger; + private readonly IUserDataManager _userDataManager; - public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem) + public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger, IJsonSerializer jsonSerializer, IFileSystem fileSystem, IUserDataManager userDataManager) { _itemRepo = itemRepo; _userManager = userManager; @@ -39,6 +40,7 @@ namespace MediaBrowser.Server.Implementations.Library _logger = logger; _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; + _userDataManager = userDataManager; } public void AddParts(IEnumerable providers) @@ -140,7 +142,7 @@ namespace MediaBrowser.Server.Implementations.Library { if (user != null) { - SetUserProperties(source, user); + SetUserProperties(hasMediaSources, source, user); } if (source.Protocol == MediaProtocol.File) { @@ -257,25 +259,38 @@ namespace MediaBrowser.Server.Implementations.Library { foreach (var source in sources) { - SetUserProperties(source, user); + SetUserProperties(item, source, user); } } return sources; } - private void SetUserProperties(MediaSourceInfo source, User user) + private void SetUserProperties(IHasUserData item, MediaSourceInfo source, User user) { - var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference) - ? new string[] { } - : new[] { user.Configuration.AudioLanguagePreference }; + var userData = item == null ? new UserItemData() : _userDataManager.GetUserData(user.Id, item.GetUserDataKey()); + SetDefaultAudioStreamIndex(source, userData, user); + SetDefaultSubtitleStreamIndex(source, userData, user); + } + + private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user) + { + if (userData.SubtitleStreamIndex.HasValue) + { + var index = userData.SubtitleStreamIndex.Value; + // Make sure the saved index is still valid + if (index == -1 || source.MediaStreams.Any(i => i.Type == MediaStreamType.Subtitle && i.Index == index)) + { + source.DefaultSubtitleStreamIndex = index; + return; + } + } + var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference) ? new List { } : new List { user.Configuration.SubtitleLanguagePreference }; - source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack); - var defaultAudioIndex = source.DefaultAudioStreamIndex; var audioLangage = defaultAudioIndex == null ? null @@ -290,6 +305,26 @@ namespace MediaBrowser.Server.Implementations.Library user.Configuration.SubtitleMode, audioLangage); } + private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user) + { + if (userData.AudioStreamIndex.HasValue) + { + var index = userData.AudioStreamIndex.Value; + // Make sure the saved index is still valid + if (source.MediaStreams.Any(i => i.Type == MediaStreamType.Audio && i.Index == index)) + { + source.DefaultAudioStreamIndex = index; + return; + } + } + + var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference) + ? new string[] { } + : new[] { user.Configuration.AudioLanguagePreference }; + + source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack); + } + private IEnumerable SortMediaSources(IEnumerable sources) { return sources.OrderBy(i => @@ -349,11 +384,14 @@ namespace MediaBrowser.Server.Implementations.Library var json = _jsonSerializer.SerializeToString(mediaSource); _logger.Debug("Live stream opened: " + json); var clone = _jsonSerializer.DeserializeFromString(json); - + if (!string.IsNullOrWhiteSpace(request.UserId)) { var user = _userManager.GetUserById(request.UserId); - SetUserProperties(clone, user); + var item = string.IsNullOrWhiteSpace(request.ItemId) + ? null + : _libraryManager.GetItemById(request.ItemId); + SetUserProperties(item, clone, user); } return new LiveStreamResponse diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index 8b86d19a2..63c41c71f 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -56,6 +56,9 @@ namespace MediaBrowser.Server.Implementations.Persistence }; _connection.RunQueries(queries, Logger); + + _connection.AddColumn(Logger, "userdata", "AudioStreamIndex", "int"); + _connection.AddColumn(Logger, "userdata", "SubtitleStreamIndex", "int"); } /// @@ -127,7 +130,7 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate)"; + cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; @@ -137,6 +140,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userData.IsFavorite; cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userData.PlaybackPositionTicks; cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userData.LastPlayedDate; + cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userData.AudioStreamIndex; + cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userData.SubtitleStreamIndex; cmd.Transaction = transaction; @@ -199,7 +204,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate)"; + cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; cmd.Parameters.Add(cmd, "@key", DbType.String).Value = userItemData.Key; cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; @@ -209,6 +214,8 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userItemData.IsFavorite; cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userItemData.PlaybackPositionTicks; cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userItemData.LastPlayedDate; + cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userItemData.AudioStreamIndex; + cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userItemData.SubtitleStreamIndex; cmd.Transaction = transaction; @@ -275,7 +282,7 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate from userdata where key = @key and userId=@userId"; + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key = @key and userId=@userId"; cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; @@ -310,7 +317,7 @@ namespace MediaBrowser.Server.Implementations.Persistence using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate from userdata where userId=@userId"; + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId"; cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; @@ -350,6 +357,16 @@ namespace MediaBrowser.Server.Implementations.Persistence userData.LastPlayedDate = reader.GetDateTime(7).ToUniversalTime(); } + if (!reader.IsDBNull(8)) + { + userData.AudioStreamIndex = reader.GetInt32(8); + } + + if (!reader.IsDBNull(9)) + { + userData.SubtitleStreamIndex = reader.GetInt32(9); + } + return userData; } diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index a9ce5ba54..7e2f41ef9 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -680,7 +680,7 @@ namespace MediaBrowser.Server.Implementations.Session foreach (var user in users) { - await OnPlaybackProgress(user.Id, key, libraryItem, info.PositionTicks).ConfigureAwait(false); + await OnPlaybackProgress(user.Id, key, libraryItem, info).ConfigureAwait(false); } } @@ -712,18 +712,28 @@ namespace MediaBrowser.Server.Implementations.Session StartIdleCheckTimer(); } - private async Task OnPlaybackProgress(Guid userId, string userDataKey, BaseItem item, long? positionTicks) + private async Task OnPlaybackProgress(Guid userId, string userDataKey, BaseItem item, PlaybackProgressInfo info) { var data = _userDataRepository.GetUserData(userId, userDataKey); + var positionTicks = info.PositionTicks; + if (positionTicks.HasValue) { _userDataRepository.UpdatePlayState(item, data, positionTicks.Value); + UpdatePlaybackSettings(info, data); + await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false); } } + private void UpdatePlaybackSettings(PlaybackProgressInfo info, UserItemData data) + { + data.AudioStreamIndex = info.AudioStreamIndex; + data.SubtitleStreamIndex = info.SubtitleStreamIndex; + } + /// /// Used to report that playback has ended for an item /// diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index e61a64646..a54380850 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -490,7 +490,7 @@ namespace MediaBrowser.Server.Startup.Common ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager); RegisterSingleInstance(ChannelManager); - MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer, FileSystemManager); + MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer, FileSystemManager, UserDataManager); RegisterSingleInstance(MediaSourceManager); SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager); From ad8b43cc3d04ce17139976ec91a45f4a2004a0c3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Feb 2016 01:25:25 -0500 Subject: [PATCH 020/111] update local pin feature --- MediaBrowser.Api/PinLoginService.cs | 85 ++++++++++++++----- MediaBrowser.Api/UserService.cs | 17 ---- .../Session/ISessionManager.cs | 7 ++ .../HttpServer/HttpListenerHost.cs | 6 ++ .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../Session/SessionManager.cs | 28 ++++-- .../MediaBrowser.WebDashboard.csproj | 6 ++ 7 files changed, 104 insertions(+), 47 deletions(-) diff --git a/MediaBrowser.Api/PinLoginService.cs b/MediaBrowser.Api/PinLoginService.cs index 8b63de10a..a4957651f 100644 --- a/MediaBrowser.Api/PinLoginService.cs +++ b/MediaBrowser.Api/PinLoginService.cs @@ -1,9 +1,14 @@ using System; using System.Collections.Concurrent; using System.Globalization; +using System.Threading.Tasks; using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Session; using MediaBrowser.Model.Connect; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Session; using ServiceStack; namespace MediaBrowser.Api @@ -13,6 +18,8 @@ namespace MediaBrowser.Api { [ApiMember(Name = "DeviceId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] public string DeviceId { get; set; } + [ApiMember(Name = "AppName", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string AppName { get; set; } } [Route("/Auth/Pin", "GET", Summary = "Gets pin status")] @@ -35,7 +42,7 @@ namespace MediaBrowser.Api [Route("/Auth/Pin/Validate", "POST", Summary = "Validates a pin")] [Authenticated] - public class ValidatePinRequest : IReturnVoid + public class ValidatePinRequest : IReturn { [ApiMember(Name = "Pin", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] public string Pin { get; set; } @@ -43,10 +50,27 @@ namespace MediaBrowser.Api public class PinLoginService : BaseApiService { - private readonly ConcurrentDictionary _activeRequests = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly ConcurrentDictionary _activeRequests = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private readonly ISessionManager _sessionManager; + private readonly IUserManager _userManager; + + public PinLoginService(ISessionManager sessionManager, IUserManager userManager) + { + _sessionManager = sessionManager; + _userManager = userManager; + } public object Post(CreatePinRequest request) { + if (string.IsNullOrWhiteSpace(request.DeviceId)) + { + throw new ArgumentNullException("DeviceId"); + } + if (string.IsNullOrWhiteSpace(request.AppName)) + { + throw new ArgumentNullException("AppName"); + } + var pin = GetNewPin(); var value = new MyPinStatus @@ -55,7 +79,8 @@ namespace MediaBrowser.Api IsConfirmed = false, IsExpired = false, Pin = pin, - DeviceId = request.DeviceId + DeviceId = request.DeviceId, + AppName = request.AppName }; _activeRequests.AddOrUpdate(pin, value, (k, v) => value); @@ -75,6 +100,7 @@ namespace MediaBrowser.Api if (!_activeRequests.TryGetValue(request.Pin, out status)) { + Logger.Debug("Pin {0} not found.", request.Pin); throw new ResourceNotFoundException(); } @@ -88,12 +114,13 @@ namespace MediaBrowser.Api }); } - public object Post(ExchangePinRequest request) + public async Task Post(ExchangePinRequest request) { MyPinStatus status; if (!_activeRequests.TryGetValue(request.Pin, out status)) { + Logger.Debug("Pin {0} not found.", request.Pin); throw new ResourceNotFoundException(); } @@ -104,14 +131,24 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException(); } - return ToOptimizedResult(new PinExchangeResult + var auth = AuthorizationContext.GetAuthorizationInfo(Request); + var user = _userManager.GetUserById(status.UserId); + + var result = await _sessionManager.CreateNewSession(new AuthenticationRequest { - // TODO: Add access token - UserId = status.UserId - }); + App = auth.Client, + AppVersion = auth.Version, + DeviceId = auth.DeviceId, + DeviceName = auth.Device, + RemoteEndPoint = Request.RemoteIp, + Username = user.Name + + }).ConfigureAwait(false); + + return ToOptimizedResult(result); } - public void Post(ValidatePinRequest request) + public object Post(ValidatePinRequest request) { MyPinStatus status; @@ -124,12 +161,18 @@ namespace MediaBrowser.Api status.IsConfirmed = true; status.UserId = AuthorizationContext.GetAuthorizationInfo(Request).UserId; + + return ToOptimizedResult(new ValidatePinResult + { + AppName = status.AppName + }); } private void EnsureValid(string requestedDeviceId, MyPinStatus status) { if (!string.Equals(requestedDeviceId, status.DeviceId, StringComparison.OrdinalIgnoreCase)) { + Logger.Debug("Pin device Id's do not match. requestedDeviceId: {0}, status.DeviceId: {1}", requestedDeviceId, status.DeviceId); throw new ResourceNotFoundException(); } @@ -145,6 +188,7 @@ namespace MediaBrowser.Api if (status.IsExpired) { + Logger.Debug("Pin {0} is expired", status.Pin); throw new ResourceNotFoundException(); } } @@ -163,16 +207,7 @@ namespace MediaBrowser.Api private string GetNewPinInternal() { - var length = 5; - var pin = string.Empty; - - while (pin.Length < length) - { - var digit = new Random().Next(0, 9); - pin += digit.ToString(CultureInfo.InvariantCulture); - } - - return pin; + return new Random().Next(10000, 99999).ToString(CultureInfo.InvariantCulture); } private bool IsPinActive(string pin) @@ -181,15 +216,15 @@ namespace MediaBrowser.Api if (!_activeRequests.TryGetValue(pin, out status)) { - return true; + return false; } if (status.IsExpired) { - return true; + return false; } - return false; + return true; } public class MyPinStatus : PinStatusResult @@ -197,6 +232,12 @@ namespace MediaBrowser.Api public DateTime CreationTimeUtc { get; set; } public string DeviceId { get; set; } public string UserId { get; set; } + public string AppName { get; set; } } } + + public class ValidatePinResult + { + public string AppName { get; set; } + } } diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 3996a0311..a35a1c3a2 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -415,23 +415,6 @@ namespace MediaBrowser.Api { var auth = AuthorizationContext.GetAuthorizationInfo(Request); - if (string.IsNullOrWhiteSpace(auth.Client)) - { - auth.Client = "Unknown app"; - } - if (string.IsNullOrWhiteSpace(auth.Device)) - { - auth.Device = "Unknown device"; - } - if (string.IsNullOrWhiteSpace(auth.Version)) - { - auth.Version = "Unknown version"; - } - if (string.IsNullOrWhiteSpace(auth.DeviceId)) - { - auth.DeviceId = "Unknown device id"; - } - var result = await _sessionMananger.AuthenticateNewSession(new AuthenticationRequest { App = auth.Client, diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index dc9612c84..fa74c5749 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -250,6 +250,13 @@ namespace MediaBrowser.Controller.Session /// Task{SessionInfo}. Task AuthenticateNewSession(AuthenticationRequest request); + /// + /// Creates the new session. + /// + /// The request. + /// Task<AuthenticationResult>. + Task CreateNewSession(AuthenticationRequest request); + /// /// Reports the capabilities. /// diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index e69ff367a..c284007f7 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -348,6 +348,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer return Task.FromResult(true); } + if (string.Equals(localPath, "/emby/pin", StringComparison.OrdinalIgnoreCase)) + { + httpRes.RedirectToUrl("web/pin.html"); + return Task.FromResult(true); + } + if (!string.IsNullOrWhiteSpace(GlobalResponse)) { httpRes.StatusCode = 503; diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 38f35f4cc..ac5cda95e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -143,7 +143,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { audioChannels = audioStream.Channels ?? audioChannels; } - return "-codec:a:0 aac -strict experimental -ab 320000 -ac " + audioChannels.ToString(CultureInfo.InvariantCulture); + return "-codec:a:0 aac -strict experimental -ab 320000"; } private bool EncodeVideo(MediaSourceInfo mediaSource) diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 7e2f41ef9..70f60f31a 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1278,7 +1278,17 @@ namespace MediaBrowser.Server.Implementations.Session /// /// The request. /// Task{SessionInfo}. - public async Task AuthenticateNewSession(AuthenticationRequest request) + public Task AuthenticateNewSession(AuthenticationRequest request) + { + return AuthenticateNewSessionInternal(request, true); + } + + public Task CreateNewSession(AuthenticationRequest request) + { + return AuthenticateNewSessionInternal(request, false); + } + + private async Task AuthenticateNewSessionInternal(AuthenticationRequest request, bool enforcePassword) { var user = _userManager.Users .FirstOrDefault(i => string.Equals(request.Username, i.Name, StringComparison.OrdinalIgnoreCase)); @@ -1291,13 +1301,16 @@ namespace MediaBrowser.Server.Implementations.Session } } - var result = await _userManager.AuthenticateUser(request.Username, request.PasswordSha1, request.PasswordMd5, request.RemoteEndPoint).ConfigureAwait(false); - - if (!result) + if (enforcePassword) { - EventHelper.FireEventIfNotNull(AuthenticationFailed, this, new GenericEventArgs(request), _logger); + var result = await _userManager.AuthenticateUser(request.Username, request.PasswordSha1, request.PasswordMd5, request.RemoteEndPoint).ConfigureAwait(false); - throw new SecurityException("Invalid user or password entered."); + if (!result) + { + EventHelper.FireEventIfNotNull(AuthenticationFailed, this, new GenericEventArgs(request), _logger); + + throw new SecurityException("Invalid user or password entered."); + } } var token = await GetAuthorizationToken(user.Id.ToString("N"), request.DeviceId, request.App, request.AppVersion, request.DeviceName).ConfigureAwait(false); @@ -1320,7 +1333,8 @@ namespace MediaBrowser.Server.Implementations.Session ServerId = _appHost.SystemId }; } - + + private async Task GetAuthorizationToken(string userId, string deviceId, string app, string appVersion, string deviceName) { var existing = _authRepo.Get(new AuthenticationInfoQuery diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index d4d8be7f1..832944aad 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -275,6 +275,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -317,6 +320,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From 95366710b798d54477a8ffa95933d21abf35aba0 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Feb 2016 09:46:13 -0500 Subject: [PATCH 021/111] 3.0.5884 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 53fccc03a..c5246590a 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; //[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5883")] +[assembly: AssemblyVersion("3.0.5884")] From 147a4dc60281af30f1a4ac5ca5c39b3d8b77e2aa Mon Sep 17 00:00:00 2001 From: vicpa Date: Sun, 21 Feb 2016 11:42:56 -0500 Subject: [PATCH 022/111] music lyricist, writer --- .../Probing/ProbeResultNormalizer.cs | 20 +++++++++++++++++++ MediaBrowser.Model/Entities/PersonType.cs | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index ec51bc967..07f1d4578 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -496,6 +496,26 @@ namespace MediaBrowser.MediaEncoding.Probing } } + var lyricist = FFProbeHelpers.GetDictionaryValue(tags, "lyricist"); + + if (!string.IsNullOrWhiteSpace(lyricist)) + { + foreach (var person in Split(lyricist, false)) + { + audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Lyricist }); + } + } + // Check for writer some music is tagged that way as alternative to composer/lyricist + var writer = FFProbeHelpers.GetDictionaryValue(tags, "writer"); + + if (!string.IsNullOrWhiteSpace(writer)) + { + foreach (var person in Split(writer, false)) + { + audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Writer }); + } + } + audio.Album = FFProbeHelpers.GetDictionaryValue(tags, "album"); var artists = FFProbeHelpers.GetDictionaryValue(tags, "artists"); diff --git a/MediaBrowser.Model/Entities/PersonType.cs b/MediaBrowser.Model/Entities/PersonType.cs index bdf846095..bc274972d 100644 --- a/MediaBrowser.Model/Entities/PersonType.cs +++ b/MediaBrowser.Model/Entities/PersonType.cs @@ -34,5 +34,9 @@ namespace MediaBrowser.Model.Entities /// The conductor /// public const string Conductor = "Conductor"; + /// + /// The lyricist + /// + public const string Lyricist = "Lyricist"; } } From fd3c6f7eccec2c10cdbadedc979042949b58f9a7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Feb 2016 12:22:13 -0500 Subject: [PATCH 023/111] support additional m3u fields --- .../LiveTv/TunerHosts/M3uParser.cs | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 8f5a4a095..9ec5809a9 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using CommonIO; @@ -51,7 +52,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts string channnelName = null; string channelNumber = null; string line; - + string imageUrl = null; while ((line = reader.ReadLine()) != null) { line = line.Trim(); @@ -70,8 +71,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts line = line.Substring(8); _logger.Info("Found m3u channel: {0}", line); var parts = line.Split(new[] { ',' }, 2); - channelNumber = parts[0]; - channnelName = parts[1]; + channelNumber = parts[0].Trim().Split(' ')[0] ?? "0"; + channnelName = FindProperty("tvg-name", line, parts[1]); + imageUrl = FindProperty("tvg-logo", line, null); } else if (!string.IsNullOrWhiteSpace(channelNumber)) { @@ -80,23 +82,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts Name = channnelName, Number = channelNumber, Id = channelIdPrefix + urlHash + line.GetMD5().ToString("N"), - Path = line + ImageUrl = imageUrl }); + imageUrl = null; channelNumber = null; channnelName = null; } } return channels; } + public string FindProperty(string property, string properties, string defaultResult = "") + { + var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase); + var matches = reg.Matches(properties); + foreach (Match match in matches) + { + if (match.Groups[1].Value == property) + { + return match.Groups[2].Value; + } + } + return defaultResult; + } } + public class M3UChannel : ChannelInfo { public string Path { get; set; } - - public M3UChannel() - { - } } -} +} \ No newline at end of file From 119c4f143570958aae94f14adca1104a72dfb7ca Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Feb 2016 12:22:31 -0500 Subject: [PATCH 024/111] fix official rating description --- .../Encoder/MediaEncoder.cs | 8 ++++++- .../LiveTv/LiveTvManager.cs | 14 +++++++++++-- .../Persistence/SqliteItemRepository.cs | 2 +- .../Sync/SyncJobProcessor.cs | 21 +++++++++++++++++-- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index ced36f3aa..8d1b4057b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -934,7 +934,13 @@ namespace MediaBrowser.MediaEncoding.Encoder _mediaEncoder._runningProcesses.Remove(this); } - process.Dispose(); + try + { + process.Dispose(); + } + catch (Exception ex) + { + } } private bool _disposed; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 7c26f5675..cd21dc21a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -801,11 +801,21 @@ namespace MediaBrowser.Server.Implementations.LiveTv { if (!string.IsNullOrWhiteSpace(info.ImagePath)) { - item.SetImagePath(ImageType.Primary, info.ImagePath); + item.SetImage(new ItemImageInfo + { + Path = info.ImagePath, + Type = ImageType.Primary, + IsPlaceholder = true + }, 0); } else if (!string.IsNullOrWhiteSpace(info.ImageUrl)) { - item.SetImagePath(ImageType.Primary, info.ImageUrl); + item.SetImage(new ItemImageInfo + { + Path = info.ImageUrl, + Type = ImageType.Primary, + IsPlaceholder = true + }, 0); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index a85872951..697ec2271 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -1014,7 +1014,7 @@ namespace MediaBrowser.Server.Implementations.Persistence if (!reader.IsDBNull(31)) { - item.OfficialRating = reader.GetString(31); + item.OfficialRatingDescription = reader.GetString(31); } if (!reader.IsDBNull(32)) diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs index 95934908d..39779ecf2 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs @@ -19,6 +19,7 @@ using MediaBrowser.Model.Sync; using MoreLinq; using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Threading; @@ -125,7 +126,23 @@ namespace MediaBrowser.Server.Implementations.Sync private string GetSyncJobItemName(BaseItem item) { - return item.Name; + var name = item.Name; + var episode = item as Episode; + + if (episode != null) + { + if (episode.IndexNumber.HasValue) + { + name = "E" + episode.IndexNumber.Value.ToString(CultureInfo.InvariantCulture) + " - " + name; + } + + if (episode.ParentIndexNumber.HasValue) + { + name = "S" + episode.ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture) + ", " + name; + } + } + + return name; } public Task UpdateJobStatus(string id) @@ -699,7 +716,7 @@ namespace MediaBrowser.Server.Implementations.Sync var path = Path.Combine(temporaryPath, filename); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); using (var stream = await _subtitleEncoder.GetSubtitles(streamInfo.ItemId, streamInfo.MediaSourceId, subtitleStreamIndex, subtitleStreamInfo.Format, 0, null, cancellationToken).ConfigureAwait(false)) { From e22a1a7857b88285a129e7ab7bb03b4256a3d5db Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Feb 2016 12:37:57 -0500 Subject: [PATCH 025/111] grab more sat fields --- .../LiveTv/LiveTvTunerInfo.cs | 6 ++++ .../LiveTv/LiveTvTunerInfoDto.cs | 6 ++++ .../LiveTv/LiveTvDtoService.cs | 3 +- .../LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs | 27 ++++++++++++++-- .../LiveTv/TunerHosts/SatIp/SatIpHost.cs | 31 ++++++++++++++----- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs index 46cf4dd98..2b1e2f21d 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvTunerInfo.cs @@ -59,6 +59,12 @@ namespace MediaBrowser.Controller.LiveTv /// The clients. public List Clients { get; set; } + /// + /// Gets or sets a value indicating whether this instance can reset. + /// + /// true if this instance can reset; otherwise, false. + public bool CanReset { get; set; } + public LiveTvTunerInfo() { Clients = new List(); diff --git a/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs b/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs index fcb19427b..9af96df43 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvTunerInfoDto.cs @@ -64,6 +64,12 @@ namespace MediaBrowser.Model.LiveTv /// The clients. public List Clients { get; set; } + /// + /// Gets or sets a value indicating whether this instance can reset. + /// + /// true if this instance can reset; otherwise, false. + public bool CanReset { get; set; } + public LiveTvTunerInfoDto() { Clients = new List(); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 04f99cdce..81ad6a387 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -178,7 +178,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv SourceType = info.SourceType, Status = info.Status, ChannelName = channelName, - Url = info.Url + Url = info.Url, + CanReset = info.CanReset }; if (!string.IsNullOrEmpty(info.ChannelId)) diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs index 48337b923..6781e498a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpDiscovery.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Text; @@ -98,7 +99,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp } catch (NotImplementedException) { - + } catch (Exception ex) { @@ -195,12 +196,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp break; } + case "friendlyName": + { + info.FriendlyName = reader.ReadElementContentAsString(); + break; + } + case "satip:X_SATIPCAP": case "X_SATIPCAP": { // DVBS2-2 - var value = reader.ReadElementContentAsString(); - // TODO + var value = reader.ReadElementContentAsString() ?? string.Empty; + var parts = value.Split(new[] { '-' }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length == 2) + { + int intValue; + if (int.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out intValue)) + { + info.TunersAvailable = intValue; + } + + if (int.TryParse(parts[0].Substring(parts[0].Length - 1), NumberStyles.Any, CultureInfo.InvariantCulture, out intValue)) + { + info.Tuners = intValue; + } + } break; } @@ -226,5 +246,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp public int Tuners { get; set; } public int TunersAvailable { get; set; } public string M3UUrl { get; set; } + public string FriendlyName { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs index 480f0edd0..976041bcc 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -140,17 +141,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp public Task> GetTunerInfos(CancellationToken cancellationToken) { var list = GetTunerHosts() - .Select(i => new LiveTvTunerInfo() - { - Name = Name, - SourceType = Type, - Status = LiveTvTunerStatus.Available, - Id = i.Url.GetMD5().ToString("N"), - Url = i.Url - }) + .SelectMany(i => GetTunerInfos(i, cancellationToken)) .ToList(); return Task.FromResult(list); } + + public List GetTunerInfos(TunerHostInfo info, CancellationToken cancellationToken) + { + var satInfo = (SatIpTunerHostInfo) info; + + var list = new List(); + + for (var i = 0; i < satInfo.Tuners; i++) + { + list.Add(new LiveTvTunerInfo + { + Name = satInfo.FriendlyName ?? Name, + SourceType = Type, + Status = LiveTvTunerStatus.Available, + Id = info.Url.GetMD5().ToString("N") + i.ToString(CultureInfo.InvariantCulture), + Url = info.Url + }); + } + + return list; + } } } From 10c1225a8454ade971943bb3d7eb47b6d1f716a1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Feb 2016 16:09:38 -0500 Subject: [PATCH 026/111] update action sheet --- MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 832944aad..7b5d14431 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -281,9 +281,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest From 299ac388b3c6ef0c66c36b13e30ea9c16d394aff Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Feb 2016 16:15:36 -0500 Subject: [PATCH 027/111] stub out config setting to remember tracks --- .../Configuration/UserConfiguration.cs | 6 ++++ .../Library/MediaSourceManager.cs | 4 +-- .../Session/SessionManager.cs | 31 ++++++++++++++----- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index d59974a2e..57d9e0f1b 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -48,11 +48,17 @@ namespace MediaBrowser.Model.Configuration public bool HidePlayedInLatest { get; set; } public bool DisplayChannelsInline { get; set; } + public bool RememberAudioSelections { get; set; } + public bool RememberSubtitleSelections { get; set; } + /// /// Initializes a new instance of the class. /// public UserConfiguration() { + RememberAudioSelections = true; + RememberSubtitleSelections = true; + HidePlayedInLatest = true; PlayDefaultAudioTrack = true; diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index caddeec0d..e4a085f42 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -276,7 +276,7 @@ namespace MediaBrowser.Server.Implementations.Library private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user) { - if (userData.SubtitleStreamIndex.HasValue) + if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections) { var index = userData.SubtitleStreamIndex.Value; // Make sure the saved index is still valid @@ -307,7 +307,7 @@ namespace MediaBrowser.Server.Implementations.Library private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user) { - if (userData.AudioStreamIndex.HasValue) + if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections) { var index = userData.AudioStreamIndex.Value; // Make sure the saved index is still valid diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 70f60f31a..1074796c0 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -680,7 +680,7 @@ namespace MediaBrowser.Server.Implementations.Session foreach (var user in users) { - await OnPlaybackProgress(user.Id, key, libraryItem, info).ConfigureAwait(false); + await OnPlaybackProgress(user, key, libraryItem, info).ConfigureAwait(false); } } @@ -712,9 +712,9 @@ namespace MediaBrowser.Server.Implementations.Session StartIdleCheckTimer(); } - private async Task OnPlaybackProgress(Guid userId, string userDataKey, BaseItem item, PlaybackProgressInfo info) + private async Task OnPlaybackProgress(User user, string userDataKey, BaseItem item, PlaybackProgressInfo info) { - var data = _userDataRepository.GetUserData(userId, userDataKey); + var data = _userDataRepository.GetUserData(user.Id, userDataKey); var positionTicks = info.PositionTicks; @@ -722,16 +722,31 @@ namespace MediaBrowser.Server.Implementations.Session { _userDataRepository.UpdatePlayState(item, data, positionTicks.Value); - UpdatePlaybackSettings(info, data); + UpdatePlaybackSettings(user, info, data); - await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false); + await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false); } } - private void UpdatePlaybackSettings(PlaybackProgressInfo info, UserItemData data) + private void UpdatePlaybackSettings(User user, PlaybackProgressInfo info, UserItemData data) { - data.AudioStreamIndex = info.AudioStreamIndex; - data.SubtitleStreamIndex = info.SubtitleStreamIndex; + if (user.Configuration.RememberAudioSelections) + { + data.AudioStreamIndex = info.AudioStreamIndex; + } + else + { + data.AudioStreamIndex = null; + } + + if (user.Configuration.RememberSubtitleSelections) + { + data.SubtitleStreamIndex = info.SubtitleStreamIndex; + } + else + { + data.SubtitleStreamIndex = null; + } } /// From c3361458adfd9fcdbf1431de52826f05feaf1d11 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Feb 2016 17:31:50 -0500 Subject: [PATCH 028/111] remove defaulting of new series --- .../FileOrganization/EpisodeFileOrganizer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 9d43dabcd..51642cf5d 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -502,7 +502,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } } - return series ?? new Series(); + return series; } /// From 52d93c6ec9405c2b71c8e547d05f1b17754ddf7b Mon Sep 17 00:00:00 2001 From: Jose Alacan Date: Sun, 21 Feb 2016 19:20:08 -0500 Subject: [PATCH 029/111] Allow build in Visual 2015 Update Fody --- MediaBrowser.Model/MediaBrowser.Model.csproj | 21 +++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index a5191192c..5466fb493 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -11,7 +11,6 @@ MediaBrowser.Model 512 ..\ - ..\packages\Fody.1.19.1.0 v4.5 @@ -443,29 +442,37 @@ - + + Designer + - - - - + ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll False + + + - + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + - - - - - \ No newline at end of file diff --git a/MediaBrowser.Model.Portable/FodyWeavers.xml b/MediaBrowser.Model.Portable/FodyWeavers.xml index 736992810..bb0f322ee 100644 --- a/MediaBrowser.Model.Portable/FodyWeavers.xml +++ b/MediaBrowser.Model.Portable/FodyWeavers.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index cea13f86e..02a4d015c 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -37,6 +37,7 @@ false true true + 07483ba6 true @@ -58,15 +59,8 @@ - - - - ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\portable-net4+sl4+wp7+win8+MonoAndroid16+MonoTouch40\PropertyChanged.dll - False - - Activity\ActivityLogEntry.cs @@ -1249,12 +1243,24 @@ false + + + ..\packages\PropertyChanged.Fody.1.50.4\Lib\portable-net4+sl4+wp8+win8+wpa81+MonoAndroid16+MonoTouch40\PropertyChanged.dll + False + + - + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + - - - - - \ No newline at end of file diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 5466fb493..79b29daa4 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -14,6 +14,7 @@ v4.5 + e0c2388f true @@ -441,7 +442,6 @@ - Designer @@ -450,8 +450,9 @@ - - ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll + + False + ..\packages\PropertyChanged.Fody.1.50.4\Lib\portable-net4+sl4+wp8+win8+wpa81+MonoAndroid16+MonoTouch40\PropertyChanged.dll False @@ -466,13 +467,14 @@ - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/MediaBrowser.Model.Portable/FodyWeavers.xml b/MediaBrowser.Model.Portable/FodyWeavers.xml index bb0f322ee..736992810 100644 --- a/MediaBrowser.Model.Portable/FodyWeavers.xml +++ b/MediaBrowser.Model.Portable/FodyWeavers.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 02a4d015c..cea13f86e 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -37,7 +37,6 @@ false true true - 07483ba6 true @@ -59,8 +58,15 @@ + + + + ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\portable-net4+sl4+wp7+win8+MonoAndroid16+MonoTouch40\PropertyChanged.dll + False + + Activity\ActivityLogEntry.cs @@ -1243,24 +1249,12 @@ false - - - ..\packages\PropertyChanged.Fody.1.50.4\Lib\portable-net4+sl4+wp8+win8+wpa81+MonoAndroid16+MonoTouch40\PropertyChanged.dll - False - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + + + + \ No newline at end of file diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 79b29daa4..5466fb493 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -14,7 +14,6 @@ v4.5 - e0c2388f true @@ -442,6 +441,7 @@ + Designer @@ -450,9 +450,8 @@ - - False - ..\packages\PropertyChanged.Fody.1.50.4\Lib\portable-net4+sl4+wp8+win8+wpa81+MonoAndroid16+MonoTouch40\PropertyChanged.dll + + ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll False @@ -467,14 +466,13 @@ + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - \ No newline at end of file diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index cea13f86e..5dcfded6f 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -15,7 +15,6 @@ 512 {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} ..\ - ..\packages\Fody.1.19.1.0 @@ -58,14 +57,6 @@ - - - - - - ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\portable-net4+sl4+wp7+win8+MonoAndroid16+MonoTouch40\PropertyChanged.dll - False - @@ -1254,7 +1245,13 @@ - + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + - - - - - \ No newline at end of file diff --git a/MediaBrowser.Model/FodyWeavers.xml b/MediaBrowser.Model/FodyWeavers.xml index bb0f322ee..736992810 100644 --- a/MediaBrowser.Model/FodyWeavers.xml +++ b/MediaBrowser.Model/FodyWeavers.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index a5191192c..fda240249 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -11,7 +11,6 @@ MediaBrowser.Model 512 ..\ - ..\packages\Fody.1.19.1.0 v4.5 @@ -442,30 +441,30 @@ - - - - ..\packages\PropertyChanged.Fody.1.41.0.0\Lib\NET35\PropertyChanged.dll - False - - + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + +