diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 4217cd6abe..90767b135b 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -19,6 +19,7 @@ using System.Threading.Tasks; using CommonIO; using MediaBrowser.Api.Playback.Progressive; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Server.Implementations.LiveTv.EmbyTV; namespace MediaBrowser.Api.LiveTv @@ -390,6 +391,7 @@ namespace MediaBrowser.Api.LiveTv public bool? EnableUserData { get; set; } public string SeriesTimerId { get; set; } + public string LibrarySeriesId { get; set; } /// /// Fields to return within the items, in addition to basic information @@ -990,6 +992,17 @@ namespace MediaBrowser.Api.LiveTv query.SeriesTimerId = request.SeriesTimerId; query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + if (!string.IsNullOrWhiteSpace(request.LibrarySeriesId)) + { + query.IsSeries = true; + + var series = _libraryManager.GetItemById(request.LibrarySeriesId) as Series; + if (series != null) + { + query.Name = series.Name; + } + } + var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false); return ToOptimizedResult(result); diff --git a/MediaBrowser.Controller/Dlna/ISsdpHandler.cs b/MediaBrowser.Controller/Dlna/ISsdpHandler.cs deleted file mode 100644 index ec3a00aad7..0000000000 --- a/MediaBrowser.Controller/Dlna/ISsdpHandler.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace MediaBrowser.Controller.Dlna -{ - public interface ISsdpHandler - { - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index a8062af19f..36d59d3e44 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -111,7 +111,6 @@ - diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 1330c54c2c..a5091bf01e 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -696,16 +696,36 @@ namespace MediaBrowser.Dlna.Didl private void AddPeople(BaseItem item, XmlElement element) { - var types = new[] { PersonType.Director, PersonType.Writer, PersonType.Producer, PersonType.Composer, "Creator" }; + var types = new[] + { + PersonType.Director, + PersonType.Writer, + PersonType.Producer, + PersonType.Composer, + "Creator" + }; var people = _libraryManager.GetPeople(item); + var index = 0; + + // Seeing some LG models locking up due content with large lists of people + // The actual issue might just be due to processing a more metadata than it can handle + var limit = 10; + foreach (var actor in people) { var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase)) ?? PersonType.Actor; AddValue(element, "upnp", type.ToLower(), actor.Name, NS_UPNP); + + index++; + + if (index >= limit) + { + break; + } } } diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs index a8aedaed87..f1eeb0a0a3 100644 --- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs +++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs @@ -19,6 +19,7 @@ using System.Net; using System.Threading.Tasks; using MediaBrowser.Controller.MediaEncoding; using Rssdp; +using Rssdp.Infrastructure; namespace MediaBrowser.Dlna.Main { @@ -154,8 +155,14 @@ namespace MediaBrowser.Dlna.Main } } + private void LogMessage(string msg) + { + //_logger.Debug(msg); + } + private void StartPublishing() { + SsdpDevicePublisherBase.LogFunction = LogMessage; _Publisher = new SsdpDevicePublisher(); } @@ -237,46 +244,64 @@ namespace MediaBrowser.Dlna.Main var udn = (addressString).GetMD5().ToString("N"); - var services = new List + var fullService = "urn:schemas-upnp-org:device:MediaServer:1"; + + _logger.Info("Registering publisher for {0} on {1}", fullService, addressString); + + var descriptorUri = "/dlna/" + udn + "/description.xml"; + var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri); + + var device = new SsdpRootDevice + { + CacheLifetime = TimeSpan.FromSeconds(cacheLength), //How long SSDP clients can cache this info. + Location = uri, // Must point to the URL that serves your devices UPnP description document. + FriendlyName = "Emby Server", + Manufacturer = "Emby", + ModelName = "Emby Server", + Uuid = udn + // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc. + }; + + SetProperies(device, fullService); + _Publisher.AddDevice(device); + + var embeddedDevices = new List { - "urn:schemas-upnp-org:device:MediaServer:1", "urn:schemas-upnp-org:service:ContentDirectory:1", "urn:schemas-upnp-org:service:ConnectionManager:1", "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1" }; - foreach (var fullService in services) + foreach (var subDevice in embeddedDevices) { - _logger.Info("Registering publisher for {0} on {1}", fullService, addressString); - - var descriptorURI = "/dlna/" + udn + "/description.xml"; - var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorURI); - - var service = fullService.Replace("urn:", string.Empty).Replace(":1", string.Empty); - - var serviceParts = service.Split(':'); - - var deviceTypeNamespace = serviceParts[0].Replace('.', '-'); - - var device = new SsdpRootDevice + var embeddedDevice = new SsdpEmbeddedDevice { - CacheLifetime = TimeSpan.FromSeconds(cacheLength), //How long SSDP clients can cache this info. - Location = uri, // Must point to the URL that serves your devices UPnP description document. - DeviceTypeNamespace = deviceTypeNamespace, - DeviceClass = serviceParts[1], - DeviceType = serviceParts[2], - FriendlyName = "Emby Server", - Manufacturer = "Emby", - ModelName = "Emby Server", + FriendlyName = device.FriendlyName, + Manufacturer = device.Manufacturer, + ModelName = device.ModelName, Uuid = udn // This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc. }; - _Publisher.AddDevice(device); + SetProperies(embeddedDevice, subDevice); + device.AddDevice(embeddedDevice); } } } + private void SetProperies(SsdpDevice device, string fullDeviceType) + { + var service = fullDeviceType.Replace("urn:", string.Empty).Replace(":1", string.Empty); + + var serviceParts = service.Split(':'); + + var deviceTypeNamespace = serviceParts[0].Replace('.', '-'); + + device.DeviceTypeNamespace = deviceTypeNamespace; + device.DeviceClass = serviceParts[1]; + device.DeviceType = serviceParts[2]; + } + private readonly object _syncLock = new object(); private void StartPlayToManager() { diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index ef60be227f..ebffe6c575 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -108,7 +108,6 @@ - @@ -130,7 +129,6 @@ - @@ -160,8 +158,6 @@ - - diff --git a/MediaBrowser.Dlna/Ssdp/Datagram.cs b/MediaBrowser.Dlna/Ssdp/Datagram.cs deleted file mode 100644 index 5901945344..0000000000 --- a/MediaBrowser.Dlna/Ssdp/Datagram.cs +++ /dev/null @@ -1,126 +0,0 @@ -using MediaBrowser.Model.Logging; -using System; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace MediaBrowser.Dlna.Ssdp -{ - public class Datagram - { - public EndPoint ToEndPoint { get; private set; } - public EndPoint FromEndPoint { get; private set; } - public string Message { get; private set; } - public bool IsBroadcast { get; private set; } - public bool EnableDebugLogging { get; private set; } - - private readonly ILogger _logger; - - public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool isBroadcast, bool enableDebugLogging) - { - Message = message; - _logger = logger; - EnableDebugLogging = enableDebugLogging; - IsBroadcast = isBroadcast; - FromEndPoint = fromEndPoint; - ToEndPoint = toEndPoint; - } - - public void Send() - { - var msg = Encoding.ASCII.GetBytes(Message); - - var socket = CreateSocket(); - - if (socket == null) - { - return; - } - - if (FromEndPoint != null) - { - try - { - socket.Bind(FromEndPoint); - } - catch (Exception ex) - { - if (EnableDebugLogging) - { - _logger.ErrorException("Error binding datagram socket", ex); - } - - if (IsBroadcast) - { - CloseSocket(socket, false); - return; - } - } - } - - try - { - socket.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result => - { - try - { - socket.EndSend(result); - } - catch (Exception ex) - { - if (EnableDebugLogging) - { - _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString()); - } - } - finally - { - CloseSocket(socket, true); - } - }, null); - } - catch (Exception ex) - { - _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString()); - CloseSocket(socket, false); - } - } - - private void CloseSocket(Socket socket, bool logError) - { - try - { - socket.Close(); - } - catch (Exception ex) - { - if (logError && EnableDebugLogging) - { - _logger.ErrorException("Error closing datagram socket", ex); - } - } - } - - private Socket CreateSocket() - { - try - { - var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4); - - if (IsBroadcast) - { - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - } - - return socket; - } - catch (Exception ex) - { - _logger.ErrorException("Error creating socket", ex); - return null; - } - } - } -} diff --git a/MediaBrowser.Dlna/Ssdp/DeviceDiscoveryInfo.cs b/MediaBrowser.Dlna/Ssdp/DeviceDiscoveryInfo.cs deleted file mode 100644 index e9de45522b..0000000000 --- a/MediaBrowser.Dlna/Ssdp/DeviceDiscoveryInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -using MediaBrowser.Dlna.PlayTo; -using System; -using System.Net; - -namespace MediaBrowser.Dlna.Ssdp -{ - public class DeviceDiscoveryInfo - { - public Device Device { get; set; } - - /// - /// The server's ip address that the device responded to - /// - public IPAddress LocalIpAddress { get; set; } - - public Uri Uri { get; set; } - - public string Usn { get; set; } - public string Nt { get; set; } - } -} diff --git a/MediaBrowser.Dlna/Ssdp/Extensions.cs b/MediaBrowser.Dlna/Ssdp/Extensions.cs index 12589e80fe..17ebcc7ead 100644 --- a/MediaBrowser.Dlna/Ssdp/Extensions.cs +++ b/MediaBrowser.Dlna/Ssdp/Extensions.cs @@ -9,30 +9,6 @@ namespace MediaBrowser.Dlna.Ssdp { public static class Extensions { - public static Task ReceiveAsync(this Socket socket, byte[] buffer, int offset, int size) - { - var tcs = new TaskCompletionSource(socket); - var remoteip = new IPEndPoint(IPAddress.Any, 0); - var endpoint = (EndPoint)remoteip; - - socket.BeginReceiveFrom(buffer, offset, size, SocketFlags.None, ref endpoint, iar => - { - var result = (TaskCompletionSource)iar.AsyncState; - var iarSocket = (Socket)result.Task.AsyncState; - - try - { - result.TrySetResult(iarSocket.EndReceive(iar)); - } - catch (Exception exc) - { - result.TrySetException(exc); - } - }, tcs); - - return tcs.Task; - } - public static string GetValue(this XElement container, XName name) { var node = container.Element(name); diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs deleted file mode 100644 index 0d0ca98a28..0000000000 --- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs +++ /dev/null @@ -1,328 +0,0 @@ -using MediaBrowser.Common; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Events; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Dlna; -using MediaBrowser.Dlna.Server; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Win32; - -namespace MediaBrowser.Dlna.Ssdp -{ - public class SsdpHandler : IDisposable, ISsdpHandler - { - private Socket _multicastSocket; - - private readonly ILogger _logger; - private readonly IServerConfigurationManager _config; - - const string SSDPAddr = "239.255.255.250"; - const int SSDPPort = 1900; - private readonly string _serverSignature; - - private readonly IPAddress _ssdpIp = IPAddress.Parse(SSDPAddr); - private readonly IPEndPoint _ssdpEndp = new IPEndPoint(IPAddress.Parse(SSDPAddr), SSDPPort); - - private Timer _notificationTimer; - - private bool _isDisposed; - private readonly Dictionary> _devices = new Dictionary>(); - - private readonly IApplicationHost _appHost; - - private readonly int _unicastPort = 1901; - private UdpClient _unicastClient; - - public SsdpHandler(ILogger logger, IServerConfigurationManager config, IApplicationHost appHost) - { - _logger = logger; - _config = config; - _appHost = appHost; - - _config.NamedConfigurationUpdated += _config_ConfigurationUpdated; - _serverSignature = GenerateServerSignature(); - } - - private string GenerateServerSignature() - { - var os = Environment.OSVersion; - var pstring = os.Platform.ToString(); - switch (os.Platform) - { - case PlatformID.Win32NT: - case PlatformID.Win32S: - case PlatformID.Win32Windows: - pstring = "WIN"; - break; - } - - return String.Format( - "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 Emby/{4}", - pstring, - IntPtr.Size * 8, - os.Version.Major, - os.Version.Minor, - _appHost.ApplicationVersion - ); - } - - void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) - { - if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase)) - { - ReloadAliveNotifier(); - } - } - - public IEnumerable RegisteredDevices - { - get - { - lock (_devices) - { - var devices = _devices.ToList(); - - return devices.SelectMany(i => i.Value).ToList(); - } - } - } - - public void Start() - { - DisposeSocket(); - StopAliveNotifier(); - - RestartSocketListener(); - ReloadAliveNotifier(); - - SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged; - SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; - } - - void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) - { - if (e.Mode == PowerModes.Resume) - { - Start(); - } - } - - public async void SendDatagram(string msg, - EndPoint endpoint, - EndPoint localAddress, - bool isBroadcast, - int sendCount = 3) - { - var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog; - - for (var i = 0; i < sendCount; i++) - { - if (i > 0) - { - await Task.Delay(500).ConfigureAwait(false); - } - - var dgram = new Datagram(endpoint, localAddress, _logger, msg, isBroadcast, enableDebugLogging); - dgram.Send(); - } - } - - private void RestartSocketListener() - { - if (_isDisposed) - { - return; - } - - try - { - _multicastSocket = CreateMulticastSocket(); - - _logger.Info("MultiCast socket created"); - } - catch (Exception ex) - { - _logger.ErrorException("Error creating MultiCast socket", ex); - //StartSocketRetryTimer(); - } - } - - public void Dispose() - { - _config.NamedConfigurationUpdated -= _config_ConfigurationUpdated; - SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged; - - _isDisposed = true; - - DisposeSocket(); - StopAliveNotifier(); - } - - private void DisposeSocket() - { - if (_multicastSocket != null) - { - _multicastSocket.Close(); - _multicastSocket.Dispose(); - _multicastSocket = null; - } - } - - private Socket CreateMulticastSocket() - { - var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4); - socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(_ssdpIp, 0)); - - socket.Bind(new IPEndPoint(IPAddress.Any, SSDPPort)); - - return socket; - } - - private void NotifyAll() - { - var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog; - - if (enableDebugLogging) - { - _logger.Debug("Sending alive notifications"); - } - foreach (var d in RegisteredDevices) - { - NotifyDevice(d, "alive", enableDebugLogging); - } - } - - private void NotifyDevice(UpnpDevice dev, string type, bool logMessage) - { - const string header = "NOTIFY * HTTP/1.1"; - - var values = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // If needed later for non-server devices, these headers will need to be dynamic - values["HOST"] = "239.255.255.250:1900"; - values["CACHE-CONTROL"] = "max-age = 600"; - values["LOCATION"] = dev.Descriptor.ToString(); - values["SERVER"] = _serverSignature; - values["NTS"] = "ssdp:" + type; - values["NT"] = dev.Type; - values["USN"] = dev.USN; - - if (logMessage) - { - _logger.Debug("{0} said {1}", dev.USN, type); - } - - var msg = new SsdpMessageBuilder().BuildMessage(header, values); - - SendDatagram(msg, _ssdpEndp, new IPEndPoint(dev.Address, 0), true, 2); - //SendUnicastRequest(msg, 1); - } - - public void RegisterNotification(string uuid, Uri descriptionUri, IPAddress address, IEnumerable services) - { - lock (_devices) - { - List list; - List dl; - if (_devices.TryGetValue(uuid, out dl)) - { - list = dl; - } - else - { - list = new List(); - _devices[uuid] = list; - } - - list.AddRange(services.Select(i => new UpnpDevice(uuid, i, descriptionUri, address))); - - NotifyAll(); - _logger.Debug("Registered mount {0} at {1}", uuid, descriptionUri); - } - } - - public void UnregisterNotification(string uuid) - { - lock (_devices) - { - List dl; - if (_devices.TryGetValue(uuid, out dl)) - { - _devices.Remove(uuid); - foreach (var d in dl.ToList()) - { - NotifyDevice(d, "byebye", true); - } - - _logger.Debug("Unregistered mount {0}", uuid); - } - } - } - - private readonly object _notificationTimerSyncLock = new object(); - private int _aliveNotifierIntervalMs; - private void ReloadAliveNotifier() - { - var config = _config.GetDlnaConfiguration(); - - if (!config.BlastAliveMessages) - { - StopAliveNotifier(); - return; - } - - var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000; - - if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs) - { - lock (_notificationTimerSyncLock) - { - if (_notificationTimer == null) - { - _logger.Debug("Starting alive notifier"); - const int initialDelayMs = 3000; - _notificationTimer = new Timer(state => NotifyAll(), null, initialDelayMs, intervalMs); - } - else - { - _logger.Debug("Updating alive notifier"); - _notificationTimer.Change(intervalMs, intervalMs); - } - - _aliveNotifierIntervalMs = intervalMs; - } - } - } - - private void StopAliveNotifier() - { - lock (_notificationTimerSyncLock) - { - if (_notificationTimer != null) - { - _logger.Debug("Stopping alive notifier"); - _notificationTimer.Dispose(); - _notificationTimer = null; - } - } - } - - public class UdpState - { - public UdpClient UdpClient; - public IPEndPoint EndPoint; - } - } -} diff --git a/MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs b/MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs deleted file mode 100644 index e479ca19a5..0000000000 --- a/MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Generic; -using System.Text; - -namespace MediaBrowser.Dlna.Ssdp -{ - public class SsdpMessageBuilder - { - public string BuildMessage(string header, Dictionary values) - { - var builder = new StringBuilder(); - - const string argFormat = "{0}: {1}\r\n"; - - builder.AppendFormat("{0}\r\n", header); - - foreach (var pair in values) - { - builder.AppendFormat(argFormat, pair.Key, pair.Value); - } - - builder.Append("\r\n"); - - return builder.ToString(); - } - } -} diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index ee7dd8b985..e19bddeee4 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -16,6 +16,7 @@ namespace MediaBrowser.Model.LiveTv public string RecordingEncodingFormat { get; set; } public bool EnableRecordingSubfolders { get; set; } public bool EnableOriginalAudioWithEncodedRecordings { get; set; } + public bool EnableOriginalVideoWithEncodedRecordings { get; set; } public List TunerHosts { get; set; } public List ListingProviders { get; set; } diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs index ad57d14732..1fd9957600 100644 --- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs +++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs @@ -42,6 +42,7 @@ namespace MediaBrowser.Model.LiveTv /// The user identifier. public string UserId { get; set; } public string SeriesTimerId { get; set; } + public string Name { get; set; } /// /// The earliest date for which a program starts to return diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs index 8bf0703be9..2c059c8600 100644 --- a/MediaBrowser.Model/Net/MimeTypes.cs +++ b/MediaBrowser.Model/Net/MimeTypes.cs @@ -100,6 +100,7 @@ namespace MediaBrowser.Model.Net .ToDictionary(x => x.Key, x => x.First().Key, StringComparer.OrdinalIgnoreCase); dict["image/jpg"] = ".jpg"; + dict["image/x-png"] = ".png"; return dict; } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 7e1fa89847..767c034ee6 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -356,6 +356,11 @@ namespace MediaBrowser.Providers.Manager var season = item as Season; var extension = MimeTypes.ToExtension(mimeType); + if (string.IsNullOrWhiteSpace(extension)) + { + throw new ArgumentException(string.Format("Unable to determine image file extension from mime type {0}", mimeType)); + } + if (type == ImageType.Thumb && saveLocally) { if (season != null && season.IndexNumber.HasValue) diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index a45d7ae5f1..64abcc0440 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -2840,7 +2840,11 @@ namespace MediaBrowser.Server.Implementations.Library { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - return Directory.Exists(path); + // We can't validate protocol-based paths, so just allow them + if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1) + { + return Directory.Exists(path); + } } // Without native support for unc, we cannot validate this when running under mono diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 716d627a93..e7bfe56f2e 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -360,7 +360,6 @@ namespace MediaBrowser.Server.Implementations.Library public async Task OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken) { - enableAutoClose = false; await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 3e9d186e3f..cdf8e75974 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV { var format = _liveTvOptions.RecordingEncodingFormat; - if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase) || _liveTvOptions.EnableOriginalVideoWithEncodedRecordings) { return "mkv"; } @@ -204,6 +204,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private bool EncodeVideo(MediaSourceInfo mediaSource) { + if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings) + { + return false; + } + var mediaStreams = mediaSource.MediaStreams ?? new List(); return !mediaStreams.Any(i => i.Type == MediaStreamType.Video && string.Equals(i.Codec, "h264", StringComparison.OrdinalIgnoreCase) && !i.IsInterlaced); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index aa404b37ca..7c72363b0d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -877,6 +877,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv SortOrder = query.SortOrder ?? SortOrder.Ascending, EnableTotalRecordCount = query.EnableTotalRecordCount, TopParentIds = new[] { topFolder.Id.ToString("N") }, + Name = query.Name, DtoOptions = options }; @@ -2304,7 +2305,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false); - info.RecordAnyChannel = true; info.RecordAnyTime = true; info.Days = new List { diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index cedaf7ad86..48117f2251 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -13,6 +13,7 @@ using System.Threading; using System.Threading.Tasks; using CommonIO; using MediaBrowser.Common.Net; +using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Serialization; @@ -24,12 +25,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { private readonly IFileSystem _fileSystem; private readonly IHttpClient _httpClient; + private readonly IServerApplicationHost _appHost; - public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient) + public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost) : base(config, logger, jsonSerializer, mediaEncoder) { _fileSystem = fileSystem; _httpClient = httpClient; + _appHost = appHost; } public override string Type @@ -46,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts protected override async Task> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken) { - return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(info.Url, ChannelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false); + return await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).Parse(info.Url, ChannelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false); } public Task> GetTunerInfos(CancellationToken cancellationToken) @@ -75,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts public async Task Validate(TunerHostInfo info) { - using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false)) + using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false)) { } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 38eb9bdd11..454abddddb 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using CommonIO; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; +using MediaBrowser.Controller; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Logging; @@ -18,12 +19,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly IHttpClient _httpClient; + private readonly IServerApplicationHost _appHost; - public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient) + public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost) { _logger = logger; _fileSystem = fileSystem; _httpClient = httpClient; + _appHost = appHost; } public async Task> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken) @@ -41,7 +44,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts { if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { - return _httpClient.Get(url, cancellationToken); + return _httpClient.Get(new HttpRequestOptions + { + Url = url, + CancellationToken = cancellationToken, + // Some data providers will require a user agent + UserAgent = _appHost.FriendlyName + "/" + _appHost.ApplicationVersion + }); } return Task.FromResult(_fileSystem.OpenRead(url)); } @@ -111,15 +120,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts channel.Number = "0"; } - channel.ImageUrl = FindProperty("tvg-logo", extInf, null); - channel.Number = FindProperty("channel-id", extInf, channel.Number); - channel.Number = FindProperty("tvg-id", extInf, channel.Number); - channel.Name = FindProperty("tvg-id", extInf, channel.Name); - channel.Name = FindProperty("tvg-name", extInf, channel.Name); + channel.ImageUrl = FindProperty("tvg-logo", extInf); + + var name = FindProperty("tvg-name", extInf); + if (string.IsNullOrWhiteSpace(name)) + { + name = FindProperty("tvg-id", extInf); + } + + channel.Name = name; + + var numberString = FindProperty("tvg-id", extInf); + if (string.IsNullOrWhiteSpace(numberString)) + { + numberString = FindProperty("channel-id", extInf); + } + + if (!string.IsNullOrWhiteSpace(numberString)) + { + channel.Number = numberString; + } + return channel; } - private string FindProperty(string property, string properties, string defaultResult = "") + private string FindProperty(string property, string properties) { var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase); var matches = reg.Matches(properties); @@ -130,7 +155,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts return match.Groups[2].Value; } } - return defaultResult; + return null; } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs index 81deb29959..1fe767e521 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/SatIpHost.cs @@ -8,6 +8,7 @@ using CommonIO; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; +using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; @@ -25,12 +26,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp { private readonly IFileSystem _fileSystem; private readonly IHttpClient _httpClient; + private readonly IServerApplicationHost _appHost; - public SatIpHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient) + public SatIpHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost) : base(config, logger, jsonSerializer, mediaEncoder) { _fileSystem = fileSystem; _httpClient = httpClient; + _appHost = appHost; } private const string ChannelIdPrefix = "sat_"; @@ -39,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp { if (!string.IsNullOrWhiteSpace(tuner.M3UUrl)) { - return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(tuner.M3UUrl, ChannelIdPrefix, tuner.Id, cancellationToken).ConfigureAwait(false); + return await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).Parse(tuner.M3UUrl, ChannelIdPrefix, tuner.Id, cancellationToken).ConfigureAwait(false); } var channels = await new ChannelScan(Logger).Scan(tuner, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index d1972a938b..b2c7445e23 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -71,7 +71,7 @@ namespace MediaBrowser.ServerApplication if (_isRunningAsService) { - _canRestartService = CanRestartWindowsService(); + //_canRestartService = CanRestartWindowsService(); } var currentProcess = Process.GetCurrentProcess(); diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 36dd12651c..a561a48afc 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -986,9 +986,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -1034,9 +1031,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 31d946691b..176de73058 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.663 + 3.0.664 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption. Copyright © Emby 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 86524c2b66..4208424182 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.663 + 3.0.664 MediaBrowser.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 860a19436b..f9f5c29568 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.663 + 3.0.664 Media Browser.Server.Core Emby Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Emby Server. Copyright © Emby 2013 - +