mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-11-19 20:09:03 -07:00
commit
ca653f00e6
@ -28,11 +28,13 @@ using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using Emby.Common.Implementations.Cryptography;
|
||||
using Emby.Common.Implementations.Diagnostics;
|
||||
using Emby.Common.Implementations.Net;
|
||||
using Emby.Common.Implementations.Threading;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using MediaBrowser.Model.Diagnostics;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.System;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using MediaBrowser.Model.Threading;
|
||||
@ -153,6 +155,7 @@ namespace Emby.Common.Implementations
|
||||
|
||||
protected IProcessFactory ProcessFactory { get; private set; }
|
||||
protected ITimerFactory TimerFactory { get; private set; }
|
||||
protected ISocketFactory SocketFactory { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
@ -549,6 +552,9 @@ return null;
|
||||
TimerFactory = new TimerFactory();
|
||||
RegisterSingleInstance(TimerFactory);
|
||||
|
||||
SocketFactory = new SocketFactory(null);
|
||||
RegisterSingleInstance(SocketFactory);
|
||||
|
||||
RegisterSingleInstance(CryptographyProvider);
|
||||
|
||||
return Task.FromResult(true);
|
||||
|
@ -641,6 +641,16 @@ namespace Emby.Common.Implementations.IO
|
||||
}).Where(i => i != null);
|
||||
}
|
||||
|
||||
public string[] ReadAllLines(string path)
|
||||
{
|
||||
return File.ReadAllLines(path);
|
||||
}
|
||||
|
||||
public void WriteAllLines(string path, IEnumerable<string> lines)
|
||||
{
|
||||
File.WriteAllLines(path, lines);
|
||||
}
|
||||
|
||||
public Stream OpenRead(string path)
|
||||
{
|
||||
return File.OpenRead(path);
|
||||
|
@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Emby.Common.Implementations.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Correclty implements the <see cref="IDisposable"/> interface and pattern for an object containing only managed resources, and adds a few common niceities not on the interface such as an <see cref="IsDisposed"/> property.
|
||||
/// </summary>
|
||||
public abstract class DisposableManagedObjectBase : IDisposable
|
||||
{
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Override this method and dispose any objects you own the lifetime of if disposing is true;
|
||||
/// </summary>
|
||||
/// <param name="disposing">True if managed objects should be disposed, if false, only unmanaged resources should be released.</param>
|
||||
protected abstract void Dispose(bool disposing);
|
||||
|
||||
/// <summary>
|
||||
/// Throws and <see cref="System.ObjectDisposedException"/> if the <see cref="IsDisposed"/> property is true.
|
||||
/// </summary>
|
||||
/// <seealso cref="IsDisposed"/>
|
||||
/// <exception cref="System.ObjectDisposedException">Thrown if the <see cref="IsDisposed"/> property is true.</exception>
|
||||
/// <seealso cref="Dispose()"/>
|
||||
protected virtual void ThrowIfDisposed()
|
||||
{
|
||||
if (this.IsDisposed) throw new ObjectDisposedException(this.GetType().FullName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Sets or returns a boolean indicating whether or not this instance has been disposed.
|
||||
/// </summary>
|
||||
/// <seealso cref="Dispose()"/>
|
||||
public bool IsDisposed
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this object instance and all internally managed resources.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Sets the <see cref="IsDisposed"/> property to true. Does not explicitly throw an exception if called multiple times, but makes no promises about behaviour of derived classes.</para>
|
||||
/// </remarks>
|
||||
/// <seealso cref="IsDisposed"/>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsDisposed = true;
|
||||
|
||||
Dispose(true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
113
Emby.Common.Implementations/Net/SocketFactory.cs
Normal file
113
Emby.Common.Implementations/Net/SocketFactory.cs
Normal file
@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace Emby.Common.Implementations.Net
|
||||
{
|
||||
public class SocketFactory : ISocketFactory
|
||||
{
|
||||
// THIS IS A LINKED FILE - SHARED AMONGST MULTIPLE PLATFORMS
|
||||
// Be careful to check any changes compile and work for all platform projects it is shared in.
|
||||
|
||||
// Not entirely happy with this. Would have liked to have done something more generic/reusable,
|
||||
// but that wasn't really the point so kept to YAGNI principal for now, even if the
|
||||
// interfaces are a bit ugly, specific and make assumptions.
|
||||
|
||||
/// <summary>
|
||||
/// Used by RSSDP components to create implementations of the <see cref="IUdpSocket"/> interface, to perform platform agnostic socket communications.
|
||||
/// </summary>
|
||||
private IPAddress _LocalIP;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor.
|
||||
/// </summary>
|
||||
/// <param name="localIP">A string containing the IP address of the local network adapter to bind sockets to. Null or empty string will use <see cref="IPAddress.Any"/>.</param>
|
||||
public SocketFactory(string localIP)
|
||||
{
|
||||
if (String.IsNullOrEmpty(localIP))
|
||||
_LocalIP = IPAddress.Any;
|
||||
else
|
||||
_LocalIP = IPAddress.Parse(localIP);
|
||||
}
|
||||
|
||||
#region ISocketFactory Members
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new UDP socket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
|
||||
/// </summary>
|
||||
/// <param name="localPort">An integer specifying the local port to bind the socket to.</param>
|
||||
/// <returns>An implementation of the <see cref="IUdpSocket"/> interface used by RSSDP components to perform socket operations.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "The purpose of this method is to create and returns a disposable result, it is up to the caller to dispose it when they are done with it.")]
|
||||
public IUdpSocket CreateUdpSocket(int localPort)
|
||||
{
|
||||
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
|
||||
|
||||
var retVal = new Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
|
||||
try
|
||||
{
|
||||
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), _LocalIP));
|
||||
return new UdpSocket(retVal, localPort, _LocalIP.ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (retVal != null)
|
||||
retVal.Dispose();
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new UDP socket that is a member of the specified multicast IP address, and binds it to the specified local port.
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">The multicast IP address to make the socket a member of.</param>
|
||||
/// <param name="multicastTimeToLive">The multicast time to live value for the socket.</param>
|
||||
/// <param name="localPort">The number of the local port to bind to.</param>
|
||||
/// <returns></returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "ip"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "The purpose of this method is to create and returns a disposable result, it is up to the caller to dispose it when they are done with it.")]
|
||||
public IUdpSocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort)
|
||||
{
|
||||
if (ipAddress == null) throw new ArgumentNullException("ipAddress");
|
||||
if (ipAddress.Length == 0) throw new ArgumentException("ipAddress cannot be an empty string.", "ipAddress");
|
||||
if (multicastTimeToLive <= 0) throw new ArgumentException("multicastTimeToLive cannot be zero or less.", "multicastTimeToLive");
|
||||
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
|
||||
|
||||
var retVal = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
|
||||
try
|
||||
{
|
||||
#if NETSTANDARD1_3
|
||||
// The ExclusiveAddressUse socket option is a Windows-specific option that, when set to "true," tells Windows not to allow another socket to use the same local address as this socket
|
||||
// See https://github.com/dotnet/corefx/pull/11509 for more details
|
||||
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
|
||||
{
|
||||
retVal.ExclusiveAddressUse = false;
|
||||
}
|
||||
#else
|
||||
retVal.ExclusiveAddressUse = false;
|
||||
#endif
|
||||
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse(ipAddress), _LocalIP));
|
||||
retVal.MulticastLoopback = true;
|
||||
|
||||
return new UdpSocket(retVal, localPort, _LocalIP.ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (retVal != null)
|
||||
retVal.Dispose();
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Rssdp.Infrastructure;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace Rssdp
|
||||
namespace Emby.Common.Implementations.Net
|
||||
{
|
||||
// THIS IS A LINKED FILE - SHARED AMONGST MULTIPLE PLATFORMS
|
||||
// Be careful to check any changes compile and work for all platform projects it is shared in.
|
||||
@ -48,7 +46,7 @@ namespace Rssdp
|
||||
|
||||
#region IUdpSocket Members
|
||||
|
||||
public System.Threading.Tasks.Task<ReceivedUdpData> ReceiveAsync()
|
||||
public Task<ReceivedUdpData> ReceiveAsync()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
@ -76,7 +74,7 @@ namespace Rssdp
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
public Task SendTo(byte[] messageData, UdpEndPoint endPoint)
|
||||
public Task SendTo(byte[] messageData, IpEndPointInfo endPoint)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
|
||||
@ -84,14 +82,14 @@ namespace Rssdp
|
||||
if (endPoint == null) throw new ArgumentNullException("endPoint");
|
||||
|
||||
#if NETSTANDARD1_6
|
||||
_Socket.SendTo(messageData, new System.Net.IPEndPoint(IPAddress.Parse(endPoint.IPAddress), endPoint.Port));
|
||||
_Socket.SendTo(messageData, new System.Net.IPEndPoint(IPAddress.Parse(endPoint.IpAddress.ToString()), endPoint.Port));
|
||||
return Task.FromResult(true);
|
||||
#else
|
||||
var taskSource = new TaskCompletionSource<bool>();
|
||||
|
||||
try
|
||||
{
|
||||
_Socket.BeginSendTo(messageData, 0, messageData.Length, SocketFlags.None, new System.Net.IPEndPoint(IPAddress.Parse(endPoint.IPAddress), endPoint.Port), result =>
|
||||
_Socket.BeginSendTo(messageData, 0, messageData.Length, SocketFlags.None, new System.Net.IPEndPoint(IPAddress.Parse(endPoint.IpAddress.ToString()), endPoint.Port), result =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -166,11 +164,7 @@ namespace Rssdp
|
||||
{
|
||||
Buffer = state.Buffer,
|
||||
ReceivedBytes = bytesRead,
|
||||
ReceivedFrom = new UdpEndPoint()
|
||||
{
|
||||
IPAddress = ipEndPoint.Address.ToString(),
|
||||
Port = ipEndPoint.Port
|
||||
}
|
||||
ReceivedFrom = ToIpEndPointInfo(ipEndPoint)
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -191,6 +185,25 @@ namespace Rssdp
|
||||
}
|
||||
}
|
||||
|
||||
private static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint)
|
||||
{
|
||||
if (endpoint == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new IpEndPointInfo
|
||||
{
|
||||
IpAddress = new IpAddressInfo
|
||||
{
|
||||
Address = endpoint.Address.ToString(),
|
||||
IsIpv6 = endpoint.AddressFamily == AddressFamily.InterNetworkV6
|
||||
},
|
||||
|
||||
Port = endpoint.Port
|
||||
};
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions via task methods should be reported by task completion source, so this should be ok.")]
|
||||
private void ProcessResponse(IAsyncResult asyncResult)
|
||||
{
|
||||
@ -206,11 +219,7 @@ namespace Rssdp
|
||||
{
|
||||
Buffer = state.Buffer,
|
||||
ReceivedBytes = bytesRead,
|
||||
ReceivedFrom = new UdpEndPoint()
|
||||
{
|
||||
IPAddress = ipEndPoint.Address.ToString(),
|
||||
Port = ipEndPoint.Port
|
||||
}
|
||||
ReceivedFrom = ToIpEndPointInfo(ipEndPoint)
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -245,7 +254,7 @@ namespace Rssdp
|
||||
}
|
||||
|
||||
public EndPoint EndPoint;
|
||||
public byte[] Buffer = new byte[SsdpConstants.DefaultUdpSocketBufferSize];
|
||||
public byte[] Buffer = new byte[8192];
|
||||
|
||||
public System.Net.Sockets.Socket Socket { get; private set; }
|
||||
|
@ -14,5 +14,13 @@ namespace Emby.Common.Implementations.Reflection
|
||||
#endif
|
||||
return type.GetTypeInfo().Assembly.GetManifestResourceStream(resource);
|
||||
}
|
||||
|
||||
public string[] GetManifestResourceNames(Type type)
|
||||
{
|
||||
#if NET46
|
||||
return type.Assembly.GetManifestResourceNames();
|
||||
#endif
|
||||
return type.GetTypeInfo().Assembly.GetManifestResourceNames();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using MediaBrowser.Controller.Dlna;
|
||||
using Emby.Dlna.Service;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Xml;
|
||||
|
||||
namespace Emby.Dlna.ConnectionManager
|
||||
{
|
||||
@ -12,13 +13,15 @@ namespace Emby.Dlna.ConnectionManager
|
||||
private readonly IDlnaManager _dlna;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
|
||||
|
||||
public ConnectionManager(IDlnaManager dlna, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
|
||||
public ConnectionManager(IDlnaManager dlna, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
||||
: base(logger, httpClient)
|
||||
{
|
||||
_dlna = dlna;
|
||||
_config = config;
|
||||
_logger = logger;
|
||||
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
||||
}
|
||||
|
||||
public string GetServiceXml(IDictionary<string, string> headers)
|
||||
@ -31,7 +34,7 @@ namespace Emby.Dlna.ConnectionManager
|
||||
var profile = _dlna.GetProfile(request.Headers) ??
|
||||
_dlna.GetDefaultProfile();
|
||||
|
||||
return new ControlHandler(_logger, profile, _config).ProcessControlRequest(request);
|
||||
return new ControlHandler(_config, _logger, XmlReaderSettingsFactory, profile).ProcessControlRequest(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Xml;
|
||||
|
||||
namespace Emby.Dlna.ConnectionManager
|
||||
{
|
||||
@ -13,12 +14,6 @@ namespace Emby.Dlna.ConnectionManager
|
||||
{
|
||||
private readonly DeviceProfile _profile;
|
||||
|
||||
public ControlHandler(ILogger logger, DeviceProfile profile, IServerConfigurationManager config)
|
||||
: base(config, logger)
|
||||
{
|
||||
_profile = profile;
|
||||
}
|
||||
|
||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
||||
{
|
||||
if (string.Equals(methodName, "GetProtocolInfo", StringComparison.OrdinalIgnoreCase))
|
||||
@ -37,5 +32,10 @@ namespace Emby.Dlna.ConnectionManager
|
||||
{ "Sink", "" }
|
||||
};
|
||||
}
|
||||
|
||||
public ControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory, DeviceProfile profile) : base(config, logger, xmlReaderSettingsFactory)
|
||||
{
|
||||
_profile = profile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Xml;
|
||||
|
||||
namespace Emby.Dlna.ContentDirectory
|
||||
{
|
||||
@ -29,6 +30,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IUserViewManager _userViewManager;
|
||||
private readonly Func<IMediaEncoder> _mediaEncoder;
|
||||
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
|
||||
|
||||
public ContentDirectory(IDlnaManager dlna,
|
||||
IUserDataManager userDataManager,
|
||||
@ -37,7 +39,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
IServerConfigurationManager config,
|
||||
IUserManager userManager,
|
||||
ILogger logger,
|
||||
IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder)
|
||||
IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func<IMediaEncoder> mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
||||
: base(logger, httpClient)
|
||||
{
|
||||
_dlna = dlna;
|
||||
@ -51,6 +53,7 @@ namespace Emby.Dlna.ContentDirectory
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_userViewManager = userViewManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
||||
}
|
||||
|
||||
private int SystemUpdateId
|
||||
@ -93,7 +96,8 @@ namespace Emby.Dlna.ContentDirectory
|
||||
_channelManager,
|
||||
_mediaSourceManager,
|
||||
_userViewManager,
|
||||
_mediaEncoder())
|
||||
_mediaEncoder(),
|
||||
XmlReaderSettingsFactory)
|
||||
.ProcessControlRequest(request);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ using MediaBrowser.Model.Querying;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@ -24,6 +25,7 @@ using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Xml;
|
||||
|
||||
namespace Emby.Dlna.ContentDirectory
|
||||
{
|
||||
@ -35,7 +37,6 @@ namespace Emby.Dlna.ContentDirectory
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly User _user;
|
||||
private readonly IUserViewManager _userViewManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
|
||||
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
|
||||
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
|
||||
@ -49,8 +50,8 @@ namespace Emby.Dlna.ContentDirectory
|
||||
|
||||
private readonly DeviceProfile _profile;
|
||||
|
||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder)
|
||||
: base(config, logger)
|
||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
||||
: base(config, logger, xmlReaderSettingsFactory)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userDataManager = userDataManager;
|
||||
@ -58,11 +59,10 @@ namespace Emby.Dlna.ContentDirectory
|
||||
_systemUpdateId = systemUpdateId;
|
||||
_channelManager = channelManager;
|
||||
_userViewManager = userViewManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_profile = profile;
|
||||
_config = config;
|
||||
|
||||
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager, _mediaEncoder);
|
||||
_didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager, mediaEncoder);
|
||||
}
|
||||
|
||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
||||
@ -209,21 +209,37 @@ namespace Emby.Dlna.ContentDirectory
|
||||
start = startVal;
|
||||
}
|
||||
|
||||
//var root = GetItem(id) as IMediaFolder;
|
||||
var result = new XmlDocument();
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false,
|
||||
OmitXmlDeclaration = true,
|
||||
ConformanceLevel = ConformanceLevel.Fragment
|
||||
};
|
||||
|
||||
var didl = result.CreateElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
didl.SetAttribute("xmlns:dc", NS_DC);
|
||||
didl.SetAttribute("xmlns:dlna", NS_DLNA);
|
||||
didl.SetAttribute("xmlns:upnp", NS_UPNP);
|
||||
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
|
||||
|
||||
int totalCount;
|
||||
|
||||
using (XmlWriter writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
//writer.WriteStartDocument();
|
||||
|
||||
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
|
||||
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
|
||||
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
|
||||
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
||||
result.AppendChild(didl);
|
||||
|
||||
foreach (var att in _profile.XmlRootAttributes)
|
||||
{
|
||||
writer.WriteAttributeString(att.Name, att.Value);
|
||||
}
|
||||
|
||||
var serverItem = GetItemFromObjectId(id, user);
|
||||
var item = serverItem.Item;
|
||||
|
||||
int totalCount;
|
||||
|
||||
if (string.Equals(flag, "BrowseMetadata"))
|
||||
{
|
||||
totalCount = 1;
|
||||
@ -232,11 +248,11 @@ namespace Emby.Dlna.ContentDirectory
|
||||
{
|
||||
var childrenResult = (await GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount).ConfigureAwait(false));
|
||||
|
||||
result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id));
|
||||
_didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.DocumentElement.AppendChild(_didlBuilder.GetItemElement(_config.GetDlnaConfiguration(), result, item, null, null, deviceId, filter));
|
||||
_didlBuilder.WriteItemElement(_config.GetDlnaConfiguration(), writer, item, null, null, deviceId, filter);
|
||||
}
|
||||
|
||||
provided++;
|
||||
@ -258,16 +274,19 @@ namespace Emby.Dlna.ContentDirectory
|
||||
var childCount = (await GetUserItems(childItem, displayStubType, user, sortCriteria, null, 0).ConfigureAwait(false))
|
||||
.TotalRecordCount;
|
||||
|
||||
result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, childItem, displayStubType, item, childCount, filter));
|
||||
_didlBuilder.WriteFolderElement(writer, childItem, displayStubType, item, childCount, filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.DocumentElement.AppendChild(_didlBuilder.GetItemElement(_config.GetDlnaConfiguration(), result, childItem, item, serverItem.StubType, deviceId, filter));
|
||||
_didlBuilder.WriteItemElement(_config.GetDlnaConfiguration(), writer, childItem, item, serverItem.StubType, deviceId, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
//writer.WriteEndDocument();
|
||||
}
|
||||
|
||||
var resXML = result.OuterXml;
|
||||
var resXML = builder.ToString();
|
||||
|
||||
return new List<KeyValuePair<string, string>>
|
||||
{
|
||||
@ -303,30 +322,43 @@ namespace Emby.Dlna.ContentDirectory
|
||||
start = startVal;
|
||||
}
|
||||
|
||||
//var root = GetItem(id) as IMediaFolder;
|
||||
var result = new XmlDocument();
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false,
|
||||
OmitXmlDeclaration = true,
|
||||
ConformanceLevel = ConformanceLevel.Fragment
|
||||
};
|
||||
|
||||
var didl = result.CreateElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
didl.SetAttribute("xmlns:dc", NS_DC);
|
||||
didl.SetAttribute("xmlns:dlna", NS_DLNA);
|
||||
didl.SetAttribute("xmlns:upnp", NS_UPNP);
|
||||
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
|
||||
int totalCount = 0;
|
||||
int provided = 0;
|
||||
|
||||
using (XmlWriter writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
//writer.WriteStartDocument();
|
||||
|
||||
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
|
||||
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
|
||||
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
|
||||
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
||||
|
||||
foreach (var att in _profile.XmlRootAttributes)
|
||||
{
|
||||
didl.SetAttribute(att.Name, att.Value);
|
||||
writer.WriteAttributeString(att.Name, att.Value);
|
||||
}
|
||||
|
||||
result.AppendChild(didl);
|
||||
|
||||
var serverItem = GetItemFromObjectId(sparams["ContainerID"], user);
|
||||
|
||||
var item = serverItem.Item;
|
||||
|
||||
var childrenResult = (await GetChildrenSorted(item, user, searchCriteria, sortCriteria, start, requestedCount).ConfigureAwait(false));
|
||||
|
||||
var totalCount = childrenResult.TotalRecordCount;
|
||||
totalCount = childrenResult.TotalRecordCount;
|
||||
|
||||
var provided = childrenResult.Items.Length;
|
||||
provided = childrenResult.Items.Length;
|
||||
|
||||
foreach (var i in childrenResult.Items)
|
||||
{
|
||||
@ -335,15 +367,19 @@ namespace Emby.Dlna.ContentDirectory
|
||||
var childCount = (await GetChildrenSorted(i, user, searchCriteria, sortCriteria, null, 0).ConfigureAwait(false))
|
||||
.TotalRecordCount;
|
||||
|
||||
result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, i, null, item, childCount, filter));
|
||||
_didlBuilder.WriteFolderElement(writer, i, null, item, childCount, filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.DocumentElement.AppendChild(_didlBuilder.GetItemElement(_config.GetDlnaConfiguration(), result, i, item, serverItem.StubType, deviceId, filter));
|
||||
_didlBuilder.WriteItemElement(_config.GetDlnaConfiguration(), writer, i, item, serverItem.StubType, deviceId, filter);
|
||||
}
|
||||
}
|
||||
|
||||
var resXML = result.OuterXml;
|
||||
writer.WriteEndElement();
|
||||
//writer.WriteEndDocument();
|
||||
}
|
||||
|
||||
var resXML = builder.ToString();
|
||||
|
||||
return new List<KeyValuePair<string, string>>
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
@ -62,50 +63,66 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
public string GetItemDidl(DlnaOptions options, BaseItem item, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo)
|
||||
{
|
||||
var result = new XmlDocument();
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false,
|
||||
OmitXmlDeclaration = true,
|
||||
ConformanceLevel = ConformanceLevel.Fragment
|
||||
};
|
||||
|
||||
var didl = result.CreateElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
didl.SetAttribute("xmlns:dc", NS_DC);
|
||||
didl.SetAttribute("xmlns:dlna", NS_DLNA);
|
||||
didl.SetAttribute("xmlns:upnp", NS_UPNP);
|
||||
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
|
||||
|
||||
using (XmlWriter writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
//writer.WriteStartDocument();
|
||||
|
||||
writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
|
||||
writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
|
||||
writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
|
||||
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
||||
|
||||
foreach (var att in _profile.XmlRootAttributes)
|
||||
{
|
||||
didl.SetAttribute(att.Name, att.Value);
|
||||
writer.WriteAttributeString(att.Name, att.Value);
|
||||
}
|
||||
|
||||
result.AppendChild(didl);
|
||||
WriteItemElement(options, writer, item, context, null, deviceId, filter, streamInfo);
|
||||
|
||||
result.DocumentElement.AppendChild(GetItemElement(options, result, item, context, null, deviceId, filter, streamInfo));
|
||||
|
||||
return result.DocumentElement.OuterXml;
|
||||
writer.WriteEndElement();
|
||||
//writer.WriteEndDocument();
|
||||
}
|
||||
|
||||
public XmlElement GetItemElement(DlnaOptions options, XmlDocument doc, BaseItem item, BaseItem context, StubType? contextStubType, string deviceId, Filter filter, StreamInfo streamInfo = null)
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public void WriteItemElement(DlnaOptions options, XmlWriter writer, BaseItem item, BaseItem context, StubType? contextStubType, string deviceId, Filter filter, StreamInfo streamInfo = null)
|
||||
{
|
||||
var clientId = GetClientId(item, null);
|
||||
|
||||
var element = doc.CreateElement(string.Empty, "item", NS_DIDL);
|
||||
element.SetAttribute("restricted", "1");
|
||||
element.SetAttribute("id", clientId);
|
||||
writer.WriteStartElement(string.Empty, "item", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("restricted", "1");
|
||||
writer.WriteAttributeString("id", clientId);
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
element.SetAttribute("parentID", GetClientId(context, contextStubType));
|
||||
writer.WriteAttributeString("parentID", GetClientId(context, contextStubType));
|
||||
}
|
||||
else
|
||||
{
|
||||
var parent = item.DisplayParentId;
|
||||
if (parent.HasValue)
|
||||
{
|
||||
element.SetAttribute("parentID", GetClientId(parent.Value, null));
|
||||
writer.WriteAttributeString("parentID", GetClientId(parent.Value, null));
|
||||
}
|
||||
}
|
||||
|
||||
//AddBookmarkInfo(item, user, element);
|
||||
|
||||
AddGeneralProperties(item, null, context, element, filter);
|
||||
AddGeneralProperties(item, null, context, writer, filter);
|
||||
|
||||
// refID?
|
||||
// storeAttribute(itemNode, object, ClassProperties.REF_ID, false);
|
||||
@ -116,17 +133,16 @@ namespace Emby.Dlna.Didl
|
||||
{
|
||||
if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddAudioResource(options, element, hasMediaSources, deviceId, filter, streamInfo);
|
||||
AddAudioResource(options, writer, hasMediaSources, deviceId, filter, streamInfo);
|
||||
}
|
||||
else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddVideoResource(options, element, hasMediaSources, deviceId, filter, streamInfo);
|
||||
AddVideoResource(options, writer, hasMediaSources, deviceId, filter, streamInfo);
|
||||
}
|
||||
}
|
||||
|
||||
AddCover(item, context, null, element);
|
||||
|
||||
return element;
|
||||
AddCover(item, context, null, writer);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
private ILogger GetStreamBuilderLogger(DlnaOptions options)
|
||||
@ -139,7 +155,7 @@ namespace Emby.Dlna.Didl
|
||||
return new NullLogger();
|
||||
}
|
||||
|
||||
private void AddVideoResource(DlnaOptions options, XmlElement container, IHasMediaSources video, string deviceId, Filter filter, StreamInfo streamInfo = null)
|
||||
private void AddVideoResource(DlnaOptions options, XmlWriter writer, IHasMediaSources video, string deviceId, Filter filter, StreamInfo streamInfo = null)
|
||||
{
|
||||
if (streamInfo == null)
|
||||
{
|
||||
@ -182,14 +198,14 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
foreach (var contentFeature in contentFeatureList)
|
||||
{
|
||||
AddVideoResource(container, video, deviceId, filter, contentFeature, streamInfo);
|
||||
AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
|
||||
}
|
||||
|
||||
foreach (var subtitle in streamInfo.GetSubtitleProfiles(false, _serverAddress, _accessToken))
|
||||
{
|
||||
if (subtitle.DeliveryMethod == SubtitleDeliveryMethod.External)
|
||||
{
|
||||
var subtitleAdded = AddSubtitleElement(container, subtitle);
|
||||
var subtitleAdded = AddSubtitleElement(writer, subtitle);
|
||||
|
||||
if (subtitleAdded && _profile.EnableSingleSubtitleLimit)
|
||||
{
|
||||
@ -199,7 +215,7 @@ namespace Emby.Dlna.Didl
|
||||
}
|
||||
}
|
||||
|
||||
private bool AddSubtitleElement(XmlElement container, SubtitleStreamInfo info)
|
||||
private bool AddSubtitleElement(XmlWriter writer, SubtitleStreamInfo info)
|
||||
{
|
||||
var subtitleProfile = _profile.SubtitleProfiles
|
||||
.FirstOrDefault(i => string.Equals(info.Format, i.Format, StringComparison.OrdinalIgnoreCase) && i.Method == SubtitleDeliveryMethod.External);
|
||||
@ -216,52 +232,45 @@ namespace Emby.Dlna.Didl
|
||||
// <sec:CaptionInfoEx sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfoEx>
|
||||
// <sec:CaptionInfo sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfo>
|
||||
|
||||
var res = container.OwnerDocument.CreateElement("CaptionInfoEx", "sec");
|
||||
writer.WriteStartElement("sec", "CaptionInfoEx", null);
|
||||
writer.WriteAttributeString("sec", "type", null, info.Format.ToLower());
|
||||
|
||||
res.InnerText = info.Url;
|
||||
|
||||
//// TODO: attribute needs SEC:
|
||||
res.SetAttribute("type", "sec", info.Format.ToLower());
|
||||
container.AppendChild(res);
|
||||
writer.WriteString(info.Url);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
else if (string.Equals(subtitleMode, "smi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);
|
||||
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
|
||||
|
||||
res.InnerText = info.Url;
|
||||
writer.WriteAttributeString("protocolInfo", "http-get:*:smi/caption:*");
|
||||
|
||||
res.SetAttribute("protocolInfo", "http-get:*:smi/caption:*");
|
||||
|
||||
container.AppendChild(res);
|
||||
writer.WriteString(info.Url);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);
|
||||
|
||||
res.InnerText = info.Url;
|
||||
|
||||
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
|
||||
var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLower());
|
||||
res.SetAttribute("protocolInfo", protocolInfo);
|
||||
writer.WriteAttributeString("protocolInfo", protocolInfo);
|
||||
|
||||
container.AppendChild(res);
|
||||
writer.WriteString(info.Url);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AddVideoResource(XmlElement container, IHasMediaSources video, string deviceId, Filter filter, string contentFeatures, StreamInfo streamInfo)
|
||||
private void AddVideoResource(XmlWriter writer, IHasMediaSources video, string deviceId, Filter filter, string contentFeatures, StreamInfo streamInfo)
|
||||
{
|
||||
var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);
|
||||
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
|
||||
|
||||
var url = streamInfo.ToDlnaUrl(_serverAddress, _accessToken);
|
||||
|
||||
res.InnerText = url;
|
||||
|
||||
var mediaSource = streamInfo.MediaSource;
|
||||
|
||||
if (mediaSource.RunTimeTicks.HasValue)
|
||||
{
|
||||
res.SetAttribute("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
|
||||
writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
|
||||
}
|
||||
|
||||
if (filter.Contains("res@size"))
|
||||
@ -272,7 +281,7 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
if (size.HasValue)
|
||||
{
|
||||
res.SetAttribute("size", size.Value.ToString(_usCulture));
|
||||
writer.WriteAttributeString("size", size.Value.ToString(_usCulture));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -286,25 +295,25 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
if (targetChannels.HasValue)
|
||||
{
|
||||
res.SetAttribute("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
|
||||
writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
|
||||
}
|
||||
|
||||
if (filter.Contains("res@resolution"))
|
||||
{
|
||||
if (targetWidth.HasValue && targetHeight.HasValue)
|
||||
{
|
||||
res.SetAttribute("resolution", string.Format("{0}x{1}", targetWidth.Value, targetHeight.Value));
|
||||
writer.WriteAttributeString("resolution", string.Format("{0}x{1}", targetWidth.Value, targetHeight.Value));
|
||||
}
|
||||
}
|
||||
|
||||
if (targetSampleRate.HasValue)
|
||||
{
|
||||
res.SetAttribute("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
|
||||
writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
|
||||
}
|
||||
|
||||
if (totalBitrate.HasValue)
|
||||
{
|
||||
res.SetAttribute("bitrate", totalBitrate.Value.ToString(_usCulture));
|
||||
writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(_usCulture));
|
||||
}
|
||||
|
||||
var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
|
||||
@ -332,13 +341,15 @@ namespace Emby.Dlna.Didl
|
||||
? MimeTypes.GetMimeType(filename)
|
||||
: mediaProfile.MimeType;
|
||||
|
||||
res.SetAttribute("protocolInfo", String.Format(
|
||||
writer.WriteAttributeString("protocolInfo", String.Format(
|
||||
"http-get:*:{0}:{1}",
|
||||
mimeType,
|
||||
contentFeatures
|
||||
));
|
||||
|
||||
container.AppendChild(res);
|
||||
writer.WriteString(url);
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context)
|
||||
@ -382,9 +393,9 @@ namespace Emby.Dlna.Didl
|
||||
return item.Name;
|
||||
}
|
||||
|
||||
private void AddAudioResource(DlnaOptions options, XmlElement container, IHasMediaSources audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
|
||||
private void AddAudioResource(DlnaOptions options, XmlWriter writer, IHasMediaSources audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
|
||||
{
|
||||
var res = container.OwnerDocument.CreateElement(string.Empty, "res", NS_DIDL);
|
||||
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
|
||||
|
||||
if (streamInfo == null)
|
||||
{
|
||||
@ -401,13 +412,11 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
var url = streamInfo.ToDlnaUrl(_serverAddress, _accessToken);
|
||||
|
||||
res.InnerText = url;
|
||||
|
||||
var mediaSource = streamInfo.MediaSource;
|
||||
|
||||
if (mediaSource.RunTimeTicks.HasValue)
|
||||
{
|
||||
res.SetAttribute("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
|
||||
writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", _usCulture));
|
||||
}
|
||||
|
||||
if (filter.Contains("res@size"))
|
||||
@ -418,7 +427,7 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
if (size.HasValue)
|
||||
{
|
||||
res.SetAttribute("size", size.Value.ToString(_usCulture));
|
||||
writer.WriteAttributeString("size", size.Value.ToString(_usCulture));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -429,17 +438,17 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
if (targetChannels.HasValue)
|
||||
{
|
||||
res.SetAttribute("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
|
||||
writer.WriteAttributeString("nrAudioChannels", targetChannels.Value.ToString(_usCulture));
|
||||
}
|
||||
|
||||
if (targetSampleRate.HasValue)
|
||||
{
|
||||
res.SetAttribute("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
|
||||
writer.WriteAttributeString("sampleFrequency", targetSampleRate.Value.ToString(_usCulture));
|
||||
}
|
||||
|
||||
if (targetAudioBitrate.HasValue)
|
||||
{
|
||||
res.SetAttribute("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
|
||||
writer.WriteAttributeString("bitrate", targetAudioBitrate.Value.ToString(_usCulture));
|
||||
}
|
||||
|
||||
var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
|
||||
@ -462,13 +471,15 @@ namespace Emby.Dlna.Didl
|
||||
streamInfo.RunTimeTicks,
|
||||
streamInfo.TranscodeSeekInfo);
|
||||
|
||||
res.SetAttribute("protocolInfo", String.Format(
|
||||
writer.WriteAttributeString("protocolInfo", String.Format(
|
||||
"http-get:*:{0}:{1}",
|
||||
mimeType,
|
||||
contentFeatures
|
||||
));
|
||||
|
||||
container.AppendChild(res);
|
||||
writer.WriteString(url);
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
public static bool IsIdRoot(string id)
|
||||
@ -486,47 +497,48 @@ namespace Emby.Dlna.Didl
|
||||
return false;
|
||||
}
|
||||
|
||||
public XmlElement GetFolderElement(XmlDocument doc, BaseItem folder, StubType? stubType, BaseItem context, int childCount, Filter filter, string requestedId = null)
|
||||
public void WriteFolderElement(XmlWriter writer, BaseItem folder, StubType? stubType, BaseItem context, int childCount, Filter filter, string requestedId = null)
|
||||
{
|
||||
var container = doc.CreateElement(string.Empty, "container", NS_DIDL);
|
||||
container.SetAttribute("restricted", "0");
|
||||
container.SetAttribute("searchable", "1");
|
||||
container.SetAttribute("childCount", childCount.ToString(_usCulture));
|
||||
writer.WriteStartElement(string.Empty, "container", NS_DIDL);
|
||||
|
||||
writer.WriteAttributeString("restricted", "0");
|
||||
writer.WriteAttributeString("searchable", "1");
|
||||
writer.WriteAttributeString("childCount", childCount.ToString(_usCulture));
|
||||
|
||||
var clientId = GetClientId(folder, stubType);
|
||||
|
||||
if (string.Equals(requestedId, "0"))
|
||||
{
|
||||
container.SetAttribute("id", "0");
|
||||
container.SetAttribute("parentID", "-1");
|
||||
writer.WriteAttributeString("id", "0");
|
||||
writer.WriteAttributeString("parentID", "-1");
|
||||
}
|
||||
else
|
||||
{
|
||||
container.SetAttribute("id", clientId);
|
||||
writer.WriteAttributeString("id", clientId);
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
container.SetAttribute("parentID", GetClientId(context, null));
|
||||
writer.WriteAttributeString("parentID", GetClientId(context, null));
|
||||
}
|
||||
else
|
||||
{
|
||||
var parent = folder.DisplayParentId;
|
||||
if (!parent.HasValue)
|
||||
{
|
||||
container.SetAttribute("parentID", "0");
|
||||
writer.WriteAttributeString("parentID", "0");
|
||||
}
|
||||
else
|
||||
{
|
||||
container.SetAttribute("parentID", GetClientId(parent.Value, null));
|
||||
writer.WriteAttributeString("parentID", GetClientId(parent.Value, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddCommonFields(folder, stubType, null, container, filter);
|
||||
AddCommonFields(folder, stubType, null, writer, filter);
|
||||
|
||||
AddCover(folder, context, stubType, container);
|
||||
AddCover(folder, context, stubType, writer);
|
||||
|
||||
return container;
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
//private void AddBookmarkInfo(BaseItem item, User user, XmlElement element)
|
||||
@ -544,27 +556,22 @@ namespace Emby.Dlna.Didl
|
||||
/// <summary>
|
||||
/// Adds fields used by both items and folders
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="itemStubType">Type of the item stub.</param>
|
||||
/// <param name="context">The context.</param>
|
||||
/// <param name="element">The element.</param>
|
||||
/// <param name="filter">The filter.</param>
|
||||
private void AddCommonFields(BaseItem item, StubType? itemStubType, BaseItem context, XmlElement element, Filter filter)
|
||||
private void AddCommonFields(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter)
|
||||
{
|
||||
// Don't filter on dc:title because not all devices will include it in the filter
|
||||
// MediaMonkey for example won't display content without a title
|
||||
//if (filter.Contains("dc:title"))
|
||||
{
|
||||
AddValue(element, "dc", "title", GetDisplayName(item, itemStubType, context), NS_DC);
|
||||
AddValue(writer, "dc", "title", GetDisplayName(item, itemStubType, context), NS_DC);
|
||||
}
|
||||
|
||||
element.AppendChild(CreateObjectClass(element.OwnerDocument, item, itemStubType));
|
||||
WriteObjectClass(writer, item, itemStubType);
|
||||
|
||||
if (filter.Contains("dc:date"))
|
||||
{
|
||||
if (item.PremiereDate.HasValue)
|
||||
{
|
||||
AddValue(element, "dc", "date", item.PremiereDate.Value.ToString("o"), NS_DC);
|
||||
AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o"), NS_DC);
|
||||
}
|
||||
}
|
||||
|
||||
@ -572,13 +579,13 @@ namespace Emby.Dlna.Didl
|
||||
{
|
||||
foreach (var genre in item.Genres)
|
||||
{
|
||||
AddValue(element, "upnp", "genre", genre, NS_UPNP);
|
||||
AddValue(writer, "upnp", "genre", genre, NS_UPNP);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var studio in item.Studios)
|
||||
{
|
||||
AddValue(element, "upnp", "publisher", studio, NS_UPNP);
|
||||
AddValue(writer, "upnp", "publisher", studio, NS_UPNP);
|
||||
}
|
||||
|
||||
if (filter.Contains("dc:description"))
|
||||
@ -592,14 +599,14 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(desc))
|
||||
{
|
||||
AddValue(element, "dc", "description", desc, NS_DC);
|
||||
AddValue(writer, "dc", "description", desc, NS_DC);
|
||||
}
|
||||
}
|
||||
if (filter.Contains("upnp:longDescription"))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.Overview))
|
||||
{
|
||||
AddValue(element, "upnp", "longDescription", item.Overview, NS_UPNP);
|
||||
AddValue(writer, "upnp", "longDescription", item.Overview, NS_UPNP);
|
||||
}
|
||||
}
|
||||
|
||||
@ -607,23 +614,23 @@ namespace Emby.Dlna.Didl
|
||||
{
|
||||
if (filter.Contains("dc:rating"))
|
||||
{
|
||||
AddValue(element, "dc", "rating", item.OfficialRating, NS_DC);
|
||||
AddValue(writer, "dc", "rating", item.OfficialRating, NS_DC);
|
||||
}
|
||||
if (filter.Contains("upnp:rating"))
|
||||
{
|
||||
AddValue(element, "upnp", "rating", item.OfficialRating, NS_UPNP);
|
||||
AddValue(writer, "upnp", "rating", item.OfficialRating, NS_UPNP);
|
||||
}
|
||||
}
|
||||
|
||||
AddPeople(item, element);
|
||||
AddPeople(item, writer);
|
||||
}
|
||||
|
||||
private XmlElement CreateObjectClass(XmlDocument result, BaseItem item, StubType? stubType)
|
||||
private void WriteObjectClass(XmlWriter writer, BaseItem item, StubType? stubType)
|
||||
{
|
||||
// More types here
|
||||
// http://oss.linn.co.uk/repos/Public/LibUpnpCil/DidlLite/UpnpAv/Test/TestDidlLite.cs
|
||||
|
||||
var objectClass = result.CreateElement("upnp", "class", NS_UPNP);
|
||||
writer.WriteStartElement("upnp", "class", NS_UPNP);
|
||||
|
||||
if (item.IsFolder || stubType.HasValue)
|
||||
{
|
||||
@ -653,48 +660,48 @@ namespace Emby.Dlna.Didl
|
||||
}
|
||||
}
|
||||
|
||||
objectClass.InnerText = classType ?? "object.container.storageFolder";
|
||||
writer.WriteString(classType ?? "object.container.storageFolder");
|
||||
}
|
||||
else if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
objectClass.InnerText = "object.item.audioItem.musicTrack";
|
||||
writer.WriteString("object.item.audioItem.musicTrack");
|
||||
}
|
||||
else if (string.Equals(item.MediaType, MediaType.Photo, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
objectClass.InnerText = "object.item.imageItem.photo";
|
||||
writer.WriteString("object.item.imageItem.photo");
|
||||
}
|
||||
else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (!_profile.RequiresPlainVideoItems && item is Movie)
|
||||
{
|
||||
objectClass.InnerText = "object.item.videoItem.movie";
|
||||
writer.WriteString("object.item.videoItem.movie");
|
||||
}
|
||||
else if (!_profile.RequiresPlainVideoItems && item is MusicVideo)
|
||||
{
|
||||
objectClass.InnerText = "object.item.videoItem.musicVideoClip";
|
||||
writer.WriteString("object.item.videoItem.musicVideoClip");
|
||||
}
|
||||
else
|
||||
{
|
||||
objectClass.InnerText = "object.item.videoItem";
|
||||
writer.WriteString("object.item.videoItem");
|
||||
}
|
||||
}
|
||||
else if (item is MusicGenre)
|
||||
{
|
||||
objectClass.InnerText = _profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre.musicGenre";
|
||||
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre.musicGenre");
|
||||
}
|
||||
else if (item is Genre || item is GameGenre)
|
||||
{
|
||||
objectClass.InnerText = _profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre";
|
||||
writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre");
|
||||
}
|
||||
else
|
||||
{
|
||||
objectClass.InnerText = "object.item";
|
||||
writer.WriteString("object.item");
|
||||
}
|
||||
|
||||
return objectClass;
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
private void AddPeople(BaseItem item, XmlElement element)
|
||||
private void AddPeople(BaseItem item, XmlWriter writer)
|
||||
{
|
||||
var types = new[]
|
||||
{
|
||||
@ -718,7 +725,7 @@ namespace Emby.Dlna.Didl
|
||||
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);
|
||||
AddValue(writer, "upnp", type.ToLower(), actor.Name, NS_UPNP);
|
||||
|
||||
index++;
|
||||
|
||||
@ -729,9 +736,9 @@ namespace Emby.Dlna.Didl
|
||||
}
|
||||
}
|
||||
|
||||
private void AddGeneralProperties(BaseItem item, StubType? itemStubType, BaseItem context, XmlElement element, Filter filter)
|
||||
private void AddGeneralProperties(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter)
|
||||
{
|
||||
AddCommonFields(item, itemStubType, context, element, filter);
|
||||
AddCommonFields(item, itemStubType, context, writer, filter);
|
||||
|
||||
var audio = item as Audio;
|
||||
|
||||
@ -739,17 +746,17 @@ namespace Emby.Dlna.Didl
|
||||
{
|
||||
foreach (var artist in audio.Artists)
|
||||
{
|
||||
AddValue(element, "upnp", "artist", artist, NS_UPNP);
|
||||
AddValue(writer, "upnp", "artist", artist, NS_UPNP);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(audio.Album))
|
||||
{
|
||||
AddValue(element, "upnp", "album", audio.Album, NS_UPNP);
|
||||
AddValue(writer, "upnp", "album", audio.Album, NS_UPNP);
|
||||
}
|
||||
|
||||
foreach (var artist in audio.AlbumArtists)
|
||||
{
|
||||
AddAlbumArtist(element, artist);
|
||||
AddAlbumArtist(writer, artist);
|
||||
}
|
||||
}
|
||||
|
||||
@ -759,12 +766,12 @@ namespace Emby.Dlna.Didl
|
||||
{
|
||||
foreach (var artist in album.AlbumArtists)
|
||||
{
|
||||
AddAlbumArtist(element, artist);
|
||||
AddValue(element, "upnp", "artist", artist, NS_UPNP);
|
||||
AddAlbumArtist(writer, artist);
|
||||
AddValue(writer, "upnp", "artist", artist, NS_UPNP);
|
||||
}
|
||||
foreach (var artist in album.Artists)
|
||||
{
|
||||
AddValue(element, "upnp", "artist", artist, NS_UPNP);
|
||||
AddValue(writer, "upnp", "artist", artist, NS_UPNP);
|
||||
}
|
||||
}
|
||||
|
||||
@ -774,37 +781,37 @@ namespace Emby.Dlna.Didl
|
||||
{
|
||||
foreach (var artist in musicVideo.Artists)
|
||||
{
|
||||
AddValue(element, "upnp", "artist", artist, NS_UPNP);
|
||||
AddAlbumArtist(element, artist);
|
||||
AddValue(writer, "upnp", "artist", artist, NS_UPNP);
|
||||
AddAlbumArtist(writer, artist);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(musicVideo.Album))
|
||||
{
|
||||
AddValue(element, "upnp", "album", musicVideo.Album, NS_UPNP);
|
||||
AddValue(writer, "upnp", "album", musicVideo.Album, NS_UPNP);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.IndexNumber.HasValue)
|
||||
{
|
||||
AddValue(element, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(_usCulture), NS_UPNP);
|
||||
AddValue(writer, "upnp", "originalTrackNumber", item.IndexNumber.Value.ToString(_usCulture), NS_UPNP);
|
||||
|
||||
if (item is Episode)
|
||||
{
|
||||
AddValue(element, "upnp", "episodeNumber", item.IndexNumber.Value.ToString(_usCulture), NS_UPNP);
|
||||
AddValue(writer, "upnp", "episodeNumber", item.IndexNumber.Value.ToString(_usCulture), NS_UPNP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAlbumArtist(XmlElement elem, string name)
|
||||
private void AddAlbumArtist(XmlWriter writer, string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
var newNode = elem.OwnerDocument.CreateElement("upnp", "artist", NS_UPNP);
|
||||
newNode.InnerText = name;
|
||||
writer.WriteStartElement("upnp", "artist", NS_UPNP);
|
||||
writer.WriteAttributeString("role", "AlbumArtist");
|
||||
|
||||
newNode.SetAttribute("role", "AlbumArtist");
|
||||
writer.WriteString(name);
|
||||
|
||||
elem.AppendChild(newNode);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
@ -812,13 +819,11 @@ namespace Emby.Dlna.Didl
|
||||
}
|
||||
}
|
||||
|
||||
private void AddValue(XmlElement elem, string prefix, string name, string value, string namespaceUri)
|
||||
private void AddValue(XmlWriter writer, string prefix, string name, string value, string namespaceUri)
|
||||
{
|
||||
try
|
||||
{
|
||||
var date = elem.OwnerDocument.CreateElement(prefix, name, namespaceUri);
|
||||
date.InnerText = value;
|
||||
elem.AppendChild(date);
|
||||
writer.WriteElementString(prefix, name, namespaceUri, value);
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
@ -826,11 +831,11 @@ namespace Emby.Dlna.Didl
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlElement element)
|
||||
private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer)
|
||||
{
|
||||
if (stubType.HasValue && stubType.Value == StubType.People)
|
||||
{
|
||||
AddEmbeddedImageAsCover("people", element);
|
||||
AddEmbeddedImageAsCover("people", writer);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -860,8 +865,6 @@ namespace Emby.Dlna.Didl
|
||||
return;
|
||||
}
|
||||
|
||||
var result = element.OwnerDocument;
|
||||
|
||||
var playbackPercentage = 0;
|
||||
var unplayedCount = 0;
|
||||
|
||||
@ -891,18 +894,14 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
var albumartUrlInfo = GetImageUrl(imageInfo, _profile.MaxAlbumArtWidth, _profile.MaxAlbumArtHeight, playbackPercentage, unplayedCount, "jpg");
|
||||
|
||||
var icon = result.CreateElement("upnp", "albumArtURI", NS_UPNP);
|
||||
var profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
|
||||
profile.InnerText = _profile.AlbumArtPn;
|
||||
icon.SetAttributeNode(profile);
|
||||
icon.InnerText = albumartUrlInfo.Url;
|
||||
element.AppendChild(icon);
|
||||
writer.WriteStartElement("upnp", "albumArtURI", NS_UPNP);
|
||||
writer.WriteAttributeString("dlna", "profileID", NS_DLNA, _profile.AlbumArtPn);
|
||||
writer.WriteString(albumartUrlInfo.Url);
|
||||
writer.WriteEndElement();
|
||||
|
||||
// TOOD: Remove these default values
|
||||
var iconUrlInfo = GetImageUrl(imageInfo, _profile.MaxIconWidth ?? 48, _profile.MaxIconHeight ?? 48, playbackPercentage, unplayedCount, "jpg");
|
||||
icon = result.CreateElement("upnp", "icon", NS_UPNP);
|
||||
icon.InnerText = iconUrlInfo.Url;
|
||||
element.AppendChild(icon);
|
||||
writer.WriteElementString("upnp", "icon", NS_UPNP, iconUrlInfo.Url);
|
||||
|
||||
if (!_profile.EnableAlbumArtInDidl)
|
||||
{
|
||||
@ -916,36 +915,30 @@ namespace Emby.Dlna.Didl
|
||||
}
|
||||
}
|
||||
|
||||
AddImageResElement(item, element, 160, 160, playbackPercentage, unplayedCount, "jpg", "JPEG_TN");
|
||||
AddImageResElement(item, writer, 160, 160, playbackPercentage, unplayedCount, "jpg", "JPEG_TN");
|
||||
|
||||
if (!_profile.EnableSingleAlbumArtLimit)
|
||||
{
|
||||
AddImageResElement(item, element, 4096, 4096, playbackPercentage, unplayedCount, "jpg", "JPEG_LRG");
|
||||
AddImageResElement(item, element, 1024, 768, playbackPercentage, unplayedCount, "jpg", "JPEG_MED");
|
||||
AddImageResElement(item, element, 640, 480, playbackPercentage, unplayedCount, "jpg", "JPEG_SM");
|
||||
AddImageResElement(item, element, 4096, 4096, playbackPercentage, unplayedCount, "png", "PNG_LRG");
|
||||
AddImageResElement(item, element, 160, 160, playbackPercentage, unplayedCount, "png", "PNG_TN");
|
||||
AddImageResElement(item, writer, 4096, 4096, playbackPercentage, unplayedCount, "jpg", "JPEG_LRG");
|
||||
AddImageResElement(item, writer, 1024, 768, playbackPercentage, unplayedCount, "jpg", "JPEG_MED");
|
||||
AddImageResElement(item, writer, 640, 480, playbackPercentage, unplayedCount, "jpg", "JPEG_SM");
|
||||
AddImageResElement(item, writer, 4096, 4096, playbackPercentage, unplayedCount, "png", "PNG_LRG");
|
||||
AddImageResElement(item, writer, 160, 160, playbackPercentage, unplayedCount, "png", "PNG_TN");
|
||||
}
|
||||
}
|
||||
|
||||
private void AddEmbeddedImageAsCover(string name, XmlElement element)
|
||||
private void AddEmbeddedImageAsCover(string name, XmlWriter writer)
|
||||
{
|
||||
var result = element.OwnerDocument;
|
||||
writer.WriteStartElement("upnp", "albumArtURI", NS_UPNP);
|
||||
writer.WriteAttributeString("dlna", "profileID", NS_DLNA, _profile.AlbumArtPn);
|
||||
writer.WriteString(_serverAddress + "/Dlna/icons/people480.jpg");
|
||||
writer.WriteEndElement();
|
||||
|
||||
var icon = result.CreateElement("upnp", "albumArtURI", NS_UPNP);
|
||||
var profile = result.CreateAttribute("dlna", "profileID", NS_DLNA);
|
||||
profile.InnerText = _profile.AlbumArtPn;
|
||||
icon.SetAttributeNode(profile);
|
||||
icon.InnerText = _serverAddress + "/Dlna/icons/people480.jpg";
|
||||
element.AppendChild(icon);
|
||||
|
||||
icon = result.CreateElement("upnp", "icon", NS_UPNP);
|
||||
icon.InnerText = _serverAddress + "/Dlna/icons/people48.jpg";
|
||||
element.AppendChild(icon);
|
||||
writer.WriteElementString("upnp", "icon", NS_UPNP, _serverAddress + "/Dlna/icons/people48.jpg");
|
||||
}
|
||||
|
||||
private void AddImageResElement(BaseItem item,
|
||||
XmlElement element,
|
||||
XmlWriter writer,
|
||||
int maxWidth,
|
||||
int maxHeight,
|
||||
int playbackPercentage,
|
||||
@ -960,13 +953,9 @@ namespace Emby.Dlna.Didl
|
||||
return;
|
||||
}
|
||||
|
||||
var result = element.OwnerDocument;
|
||||
|
||||
var albumartUrlInfo = GetImageUrl(imageInfo, maxWidth, maxHeight, playbackPercentage, unplayedCount, format);
|
||||
|
||||
var res = result.CreateElement(string.Empty, "res", NS_DIDL);
|
||||
|
||||
res.InnerText = albumartUrlInfo.Url;
|
||||
writer.WriteStartElement(string.Empty, "res", NS_DIDL);
|
||||
|
||||
var width = albumartUrlInfo.Width;
|
||||
var height = albumartUrlInfo.Height;
|
||||
@ -974,7 +963,7 @@ namespace Emby.Dlna.Didl
|
||||
var contentFeatures = new ContentFeatureBuilder(_profile)
|
||||
.BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);
|
||||
|
||||
res.SetAttribute("protocolInfo", String.Format(
|
||||
writer.WriteAttributeString("protocolInfo", String.Format(
|
||||
"http-get:*:{0}:{1}",
|
||||
MimeTypes.GetMimeType("file." + format),
|
||||
contentFeatures
|
||||
@ -982,10 +971,12 @@ namespace Emby.Dlna.Didl
|
||||
|
||||
if (width.HasValue && height.HasValue)
|
||||
{
|
||||
res.SetAttribute("resolution", string.Format("{0}x{1}", width.Value, height.Value));
|
||||
writer.WriteAttributeString("resolution", string.Format("{0}x{1}", width.Value, height.Value));
|
||||
}
|
||||
|
||||
element.AppendChild(res);
|
||||
writer.WriteString(albumartUrlInfo.Url);
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
private ImageDownloadInfo GetImageInfo(BaseItem item)
|
||||
|
62
Emby.Dlna/Didl/StringWriterWithEncoding.cs
Normal file
62
Emby.Dlna/Didl/StringWriterWithEncoding.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Emby.Dlna.Didl
|
||||
{
|
||||
public class StringWriterWithEncoding : StringWriter
|
||||
{
|
||||
private readonly Encoding _encoding;
|
||||
|
||||
public StringWriterWithEncoding()
|
||||
{
|
||||
}
|
||||
|
||||
public StringWriterWithEncoding(IFormatProvider formatProvider)
|
||||
: base(formatProvider)
|
||||
{
|
||||
}
|
||||
|
||||
public StringWriterWithEncoding(StringBuilder sb)
|
||||
: base(sb)
|
||||
{
|
||||
}
|
||||
|
||||
public StringWriterWithEncoding(StringBuilder sb, IFormatProvider formatProvider)
|
||||
: base(sb, formatProvider)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public StringWriterWithEncoding(Encoding encoding)
|
||||
{
|
||||
_encoding = encoding;
|
||||
}
|
||||
|
||||
public StringWriterWithEncoding(IFormatProvider formatProvider, Encoding encoding)
|
||||
: base(formatProvider)
|
||||
{
|
||||
_encoding = encoding;
|
||||
}
|
||||
|
||||
public StringWriterWithEncoding(StringBuilder sb, Encoding encoding)
|
||||
: base(sb)
|
||||
{
|
||||
_encoding = encoding;
|
||||
}
|
||||
|
||||
public StringWriterWithEncoding(StringBuilder sb, IFormatProvider formatProvider, Encoding encoding)
|
||||
: base(sb, formatProvider)
|
||||
{
|
||||
_encoding = encoding;
|
||||
}
|
||||
|
||||
public override Encoding Encoding
|
||||
{
|
||||
get { return (null == _encoding) ? base.Encoding : _encoding; }
|
||||
}
|
||||
}
|
||||
}
|
@ -16,12 +16,8 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Model.IO;
|
||||
#if NETSTANDARD1_6
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using MediaBrowser.Model.Reflection;
|
||||
|
||||
namespace Emby.Dlna
|
||||
{
|
||||
@ -33,6 +29,7 @@ namespace Emby.Dlna
|
||||
private readonly ILogger _logger;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly IAssemblyInfo _assemblyInfo;
|
||||
|
||||
private readonly Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>> _profiles = new Dictionary<string, Tuple<InternalProfileInfo, DeviceProfile>>(StringComparer.Ordinal);
|
||||
|
||||
@ -40,7 +37,7 @@ namespace Emby.Dlna
|
||||
IFileSystem fileSystem,
|
||||
IApplicationPaths appPaths,
|
||||
ILogger logger,
|
||||
IJsonSerializer jsonSerializer, IServerApplicationHost appHost)
|
||||
IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IAssemblyInfo assemblyInfo)
|
||||
{
|
||||
_xmlSerializer = xmlSerializer;
|
||||
_fileSystem = fileSystem;
|
||||
@ -48,6 +45,7 @@ namespace Emby.Dlna
|
||||
_logger = logger;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_appHost = appHost;
|
||||
_assemblyInfo = assemblyInfo;
|
||||
}
|
||||
|
||||
public void InitProfiles()
|
||||
@ -306,7 +304,7 @@ namespace Emby.Dlna
|
||||
.Where(i => i != null)
|
||||
.ToList();
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
catch (IOException)
|
||||
{
|
||||
return new List<DeviceProfile>();
|
||||
}
|
||||
@ -400,17 +398,11 @@ namespace Emby.Dlna
|
||||
|
||||
private void ExtractSystemProfiles()
|
||||
{
|
||||
#if NET46
|
||||
var assembly = GetType().Assembly;
|
||||
var namespaceName = GetType().Namespace + ".Profiles.Json.";
|
||||
#elif NETSTANDARD1_6
|
||||
var assembly = GetType().GetTypeInfo().Assembly;
|
||||
var namespaceName = GetType().GetTypeInfo().Namespace + ".Profiles.Json.";
|
||||
#endif
|
||||
|
||||
var systemProfilesPath = SystemProfilesPath;
|
||||
|
||||
foreach (var name in assembly.GetManifestResourceNames()
|
||||
foreach (var name in _assemblyInfo.GetManifestResourceNames(GetType())
|
||||
.Where(i => i.StartsWith(namespaceName))
|
||||
.ToList())
|
||||
{
|
||||
@ -418,9 +410,9 @@ namespace Emby.Dlna
|
||||
|
||||
var path = Path.Combine(systemProfilesPath, filename);
|
||||
|
||||
using (var stream = assembly.GetManifestResourceStream(name))
|
||||
using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), name))
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
var fileInfo = _fileSystem.GetFileInfo(path);
|
||||
|
||||
if (!fileInfo.Exists || fileInfo.Length != stream.Length)
|
||||
{
|
||||
@ -512,7 +504,7 @@ namespace Emby.Dlna
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(Path.ChangeExtension(path, ".xml"));
|
||||
_fileSystem.DeleteFile(Path.ChangeExtension(path, ".xml"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -562,20 +554,11 @@ namespace Emby.Dlna
|
||||
|
||||
var resource = GetType().Namespace + ".Images." + filename.ToLower();
|
||||
|
||||
#if NET46
|
||||
return new ImageStream
|
||||
{
|
||||
Format = format,
|
||||
Stream = GetType().Assembly.GetManifestResourceStream(resource)
|
||||
Stream = _assemblyInfo.GetManifestResourceStream(GetType(), resource)
|
||||
};
|
||||
#elif NETSTANDARD1_6
|
||||
return new ImageStream
|
||||
{
|
||||
Format = format,
|
||||
Stream = GetType().GetTypeInfo().Assembly.GetManifestResourceStream(resource)
|
||||
};
|
||||
#endif
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
|
202
Emby.Dlna/Emby.Dlna.csproj
Normal file
202
Emby.Dlna/Emby.Dlna.csproj
Normal file
@ -0,0 +1,202 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{805844AB-E92F-45E6-9D99-4F6D48D129A5}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Emby.Dlna</RootNamespace>
|
||||
<AssemblyName>Emby.Dlna</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- A reference to the entire .NET Framework is automatically included -->
|
||||
<EmbeddedResource Include="Profiles\Json\BubbleUPnp.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Default.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Denon AVR.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\DirecTV HD-DVR.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Dish Hopper-Joey.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\foobar2000.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Kodi.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\LG Smart TV.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Linksys DMA2100.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\MediaMonkey.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Panasonic Viera.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Popcorn Hour.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Samsung Smart TV.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Blu-ray Player 2013.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Blu-ray Player 2014.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Blu-ray Player 2015.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Blu-ray Player 2016.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Blu-ray Player.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Bravia %282010%29.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Bravia %282011%29.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Bravia %282012%29.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Bravia %282013%29.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony Bravia %282014%29.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony PlayStation 3.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Sony PlayStation 4.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Vlc.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\WDTV Live.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Xbox 360.json" />
|
||||
<EmbeddedResource Include="Profiles\Json\Xbox One.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Common\Argument.cs" />
|
||||
<Compile Include="Common\DeviceIcon.cs" />
|
||||
<Compile Include="Common\DeviceService.cs" />
|
||||
<Compile Include="Common\ServiceAction.cs" />
|
||||
<Compile Include="Common\StateVariable.cs" />
|
||||
<Compile Include="ConfigurationExtension.cs" />
|
||||
<Compile Include="ConnectionManager\ConnectionManager.cs" />
|
||||
<Compile Include="ConnectionManager\ConnectionManagerXmlBuilder.cs" />
|
||||
<Compile Include="ConnectionManager\ControlHandler.cs" />
|
||||
<Compile Include="ConnectionManager\ServiceActionListBuilder.cs" />
|
||||
<Compile Include="ContentDirectory\ContentDirectory.cs" />
|
||||
<Compile Include="ContentDirectory\ContentDirectoryBrowser.cs" />
|
||||
<Compile Include="ContentDirectory\ContentDirectoryXmlBuilder.cs" />
|
||||
<Compile Include="ContentDirectory\ControlHandler.cs" />
|
||||
<Compile Include="ContentDirectory\ServiceActionListBuilder.cs" />
|
||||
<Compile Include="Didl\DidlBuilder.cs" />
|
||||
<Compile Include="Didl\Filter.cs" />
|
||||
<Compile Include="Didl\StringWriterWithEncoding.cs" />
|
||||
<Compile Include="DlnaManager.cs" />
|
||||
<Compile Include="Eventing\EventManager.cs" />
|
||||
<Compile Include="Eventing\EventSubscription.cs" />
|
||||
<Compile Include="Main\DlnaEntryPoint.cs" />
|
||||
<Compile Include="MediaReceiverRegistrar\ControlHandler.cs" />
|
||||
<Compile Include="MediaReceiverRegistrar\MediaReceiverRegistrar.cs" />
|
||||
<Compile Include="MediaReceiverRegistrar\MediaReceiverRegistrarXmlBuilder.cs" />
|
||||
<Compile Include="MediaReceiverRegistrar\ServiceActionListBuilder.cs" />
|
||||
<Compile Include="PlayTo\CurrentIdEventArgs.cs" />
|
||||
<Compile Include="PlayTo\Device.cs" />
|
||||
<Compile Include="PlayTo\DeviceInfo.cs" />
|
||||
<Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
|
||||
<Compile Include="PlayTo\PlaybackStartEventArgs.cs" />
|
||||
<Compile Include="PlayTo\PlaybackStoppedEventArgs.cs" />
|
||||
<Compile Include="PlayTo\PlaylistItem.cs" />
|
||||
<Compile Include="PlayTo\PlaylistItemFactory.cs" />
|
||||
<Compile Include="PlayTo\PlayToController.cs" />
|
||||
<Compile Include="PlayTo\PlayToManager.cs" />
|
||||
<Compile Include="PlayTo\SsdpHttpClient.cs" />
|
||||
<Compile Include="PlayTo\TransportCommands.cs" />
|
||||
<Compile Include="PlayTo\TRANSPORTSTATE.cs" />
|
||||
<Compile Include="PlayTo\TransportStateEventArgs.cs" />
|
||||
<Compile Include="PlayTo\uBaseObject.cs" />
|
||||
<Compile Include="PlayTo\uParser.cs" />
|
||||
<Compile Include="PlayTo\uParserObject.cs" />
|
||||
<Compile Include="PlayTo\UpnpContainer.cs" />
|
||||
<Compile Include="PlayTo\uPnpNamespaces.cs" />
|
||||
<Compile Include="ProfileSerialization\CodecProfile.cs" />
|
||||
<Compile Include="ProfileSerialization\ContainerProfile.cs" />
|
||||
<Compile Include="ProfileSerialization\DeviceProfile.cs" />
|
||||
<Compile Include="ProfileSerialization\DirectPlayProfile.cs" />
|
||||
<Compile Include="ProfileSerialization\HttpHeaderInfo.cs" />
|
||||
<Compile Include="ProfileSerialization\ProfileCondition.cs" />
|
||||
<Compile Include="ProfileSerialization\ResponseProfile.cs" />
|
||||
<Compile Include="ProfileSerialization\SubtitleProfile.cs" />
|
||||
<Compile Include="ProfileSerialization\TranscodingProfile.cs" />
|
||||
<Compile Include="ProfileSerialization\XmlAttribute.cs" />
|
||||
<Compile Include="Profiles\BubbleUpnpProfile.cs" />
|
||||
<Compile Include="Profiles\DefaultProfile.cs" />
|
||||
<Compile Include="Profiles\DenonAvrProfile.cs" />
|
||||
<Compile Include="Profiles\DirectTvProfile.cs" />
|
||||
<Compile Include="Profiles\DishHopperJoeyProfile.cs" />
|
||||
<Compile Include="Profiles\Foobar2000Profile.cs" />
|
||||
<Compile Include="Profiles\KodiProfile.cs" />
|
||||
<Compile Include="Profiles\LgTvProfile.cs" />
|
||||
<Compile Include="Profiles\LinksysDMA2100Profile.cs" />
|
||||
<Compile Include="Profiles\MediaMonkeyProfile.cs" />
|
||||
<Compile Include="Profiles\PanasonicVieraProfile.cs" />
|
||||
<Compile Include="Profiles\PopcornHourProfile.cs" />
|
||||
<Compile Include="Profiles\SamsungSmartTvProfile.cs" />
|
||||
<Compile Include="Profiles\SonyBlurayPlayer2013.cs" />
|
||||
<Compile Include="Profiles\SonyBlurayPlayer2014.cs" />
|
||||
<Compile Include="Profiles\SonyBlurayPlayer2015.cs" />
|
||||
<Compile Include="Profiles\SonyBlurayPlayer2016.cs" />
|
||||
<Compile Include="Profiles\SonyBlurayPlayerProfile.cs" />
|
||||
<Compile Include="Profiles\SonyBravia2010Profile.cs" />
|
||||
<Compile Include="Profiles\SonyBravia2011Profile.cs" />
|
||||
<Compile Include="Profiles\SonyBravia2012Profile.cs" />
|
||||
<Compile Include="Profiles\SonyBravia2013Profile.cs" />
|
||||
<Compile Include="Profiles\SonyBravia2014Profile.cs" />
|
||||
<Compile Include="Profiles\SonyPs3Profile.cs" />
|
||||
<Compile Include="Profiles\SonyPs4Profile.cs" />
|
||||
<Compile Include="Profiles\VlcProfile.cs" />
|
||||
<Compile Include="Profiles\WdtvLiveProfile.cs" />
|
||||
<Compile Include="Profiles\Xbox360Profile.cs" />
|
||||
<Compile Include="Profiles\XboxOneProfile.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Server\DescriptionXmlBuilder.cs" />
|
||||
<Compile Include="Server\Headers.cs" />
|
||||
<Compile Include="Server\UpnpDevice.cs" />
|
||||
<Compile Include="Service\BaseControlHandler.cs" />
|
||||
<Compile Include="Service\BaseService.cs" />
|
||||
<Compile Include="Service\ControlErrorHandler.cs" />
|
||||
<Compile Include="Service\ServiceXmlBuilder.cs" />
|
||||
<Compile Include="Ssdp\DeviceDiscovery.cs" />
|
||||
<Compile Include="Ssdp\Extensions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Images\logo120.jpg" />
|
||||
<EmbeddedResource Include="Images\logo120.png" />
|
||||
<EmbeddedResource Include="Images\logo240.jpg" />
|
||||
<EmbeddedResource Include="Images\logo240.png" />
|
||||
<EmbeddedResource Include="Images\logo48.jpg" />
|
||||
<EmbeddedResource Include="Images\logo48.png" />
|
||||
<EmbeddedResource Include="Images\people48.jpg" />
|
||||
<EmbeddedResource Include="Images\people48.png" />
|
||||
<EmbeddedResource Include="Images\people480.jpg" />
|
||||
<EmbeddedResource Include="Images\people480.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">
|
||||
<Project>{9142eefa-7570-41e1-bfcc-468bb571af2f}</Project>
|
||||
<Name>MediaBrowser.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj">
|
||||
<Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
|
||||
<Name>MediaBrowser.Controller</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\RSSDP\RSSDP.csproj">
|
||||
<Project>{21002819-c39a-4d3e-be83-2a276a77fb1f}</Project>
|
||||
<Name>RSSDP</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>f40e364d-01d9-4bbf-b82c-5d6c55e0a1f5</ProjectGuid>
|
||||
<RootNamespace>Emby.Dlna</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
@ -19,6 +19,8 @@ using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using Rssdp;
|
||||
using Rssdp.Infrastructure;
|
||||
|
||||
@ -29,7 +31,6 @@ namespace Emby.Dlna.Main
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly INetworkManager _network;
|
||||
|
||||
private PlayToManager _manager;
|
||||
private readonly ISessionManager _sessionManager;
|
||||
@ -49,10 +50,13 @@ namespace Emby.Dlna.Main
|
||||
private bool _dlnaServerStarted;
|
||||
private SsdpDevicePublisher _Publisher;
|
||||
|
||||
private readonly ITimerFactory _timerFactory;
|
||||
private readonly ISocketFactory _socketFactory;
|
||||
|
||||
|
||||
public DlnaEntryPoint(IServerConfigurationManager config,
|
||||
ILogManager logManager,
|
||||
IServerApplicationHost appHost,
|
||||
INetworkManager network,
|
||||
ISessionManager sessionManager,
|
||||
IHttpClient httpClient,
|
||||
ILibraryManager libraryManager,
|
||||
@ -62,11 +66,10 @@ namespace Emby.Dlna.Main
|
||||
IUserDataManager userDataManager,
|
||||
ILocalizationManager localization,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
IDeviceDiscovery deviceDiscovery, IMediaEncoder mediaEncoder)
|
||||
IDeviceDiscovery deviceDiscovery, IMediaEncoder mediaEncoder, ISocketFactory socketFactory, ITimerFactory timerFactory)
|
||||
{
|
||||
_config = config;
|
||||
_appHost = appHost;
|
||||
_network = network;
|
||||
_sessionManager = sessionManager;
|
||||
_httpClient = httpClient;
|
||||
_libraryManager = libraryManager;
|
||||
@ -78,6 +81,8 @@ namespace Emby.Dlna.Main
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_deviceDiscovery = deviceDiscovery;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_socketFactory = socketFactory;
|
||||
_timerFactory = timerFactory;
|
||||
_logger = logManager.GetLogger("Dlna");
|
||||
}
|
||||
|
||||
@ -164,7 +169,7 @@ namespace Emby.Dlna.Main
|
||||
private void StartPublishing()
|
||||
{
|
||||
SsdpDevicePublisherBase.LogFunction = LogMessage;
|
||||
_Publisher = new SsdpDevicePublisher();
|
||||
_Publisher = new SsdpDevicePublisher(_socketFactory, _timerFactory, "Windows", "10");
|
||||
}
|
||||
|
||||
private void StartDeviceDiscovery()
|
||||
@ -328,7 +333,8 @@ namespace Emby.Dlna.Main
|
||||
_userDataManager,
|
||||
_localization,
|
||||
_mediaSourceManager,
|
||||
_mediaEncoder);
|
||||
_mediaEncoder,
|
||||
_timerFactory);
|
||||
|
||||
_manager.Start();
|
||||
}
|
||||
|
@ -5,15 +5,12 @@ using Emby.Dlna.Service;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Xml;
|
||||
|
||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||
{
|
||||
public class ControlHandler : BaseControlHandler
|
||||
{
|
||||
public ControlHandler(IServerConfigurationManager config, ILogger logger) : base(config, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
|
||||
{
|
||||
if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase))
|
||||
@ -39,5 +36,9 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||
{ "Result", "1" }
|
||||
};
|
||||
}
|
||||
|
||||
public ControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(config, logger, xmlReaderSettingsFactory)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,20 @@ using Emby.Dlna.Service;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Xml;
|
||||
|
||||
namespace Emby.Dlna.MediaReceiverRegistrar
|
||||
{
|
||||
public class MediaReceiverRegistrar : BaseService, IMediaReceiverRegistrar, IDisposable
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
|
||||
|
||||
public MediaReceiverRegistrar(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config)
|
||||
public MediaReceiverRegistrar(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
||||
: base(logger, httpClient)
|
||||
{
|
||||
_config = config;
|
||||
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
||||
}
|
||||
|
||||
public string GetServiceXml(IDictionary<string, string> headers)
|
||||
@ -27,7 +30,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar
|
||||
{
|
||||
return new ControlHandler(
|
||||
_config,
|
||||
Logger)
|
||||
Logger, XmlReaderSettingsFactory)
|
||||
.ProcessControlRequest(request);
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Emby.Dlna.Server;
|
||||
using MediaBrowser.Model.Threading;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
@ -24,7 +25,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
#region Fields & Properties
|
||||
|
||||
private Timer _timer;
|
||||
private ITimer _timer;
|
||||
|
||||
public DeviceInfo Properties { get; set; }
|
||||
|
||||
@ -96,12 +97,15 @@ namespace Emby.Dlna.PlayTo
|
||||
public DateTime DateLastActivity { get; private set; }
|
||||
public Action OnDeviceUnavailable { get; set; }
|
||||
|
||||
public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config)
|
||||
private readonly ITimerFactory _timerFactory;
|
||||
|
||||
public Device(DeviceInfo deviceProperties, IHttpClient httpClient, ILogger logger, IServerConfigurationManager config, ITimerFactory timerFactory)
|
||||
{
|
||||
Properties = deviceProperties;
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
_timerFactory = timerFactory;
|
||||
}
|
||||
|
||||
private int GetPlaybackTimerIntervalMs()
|
||||
@ -116,7 +120,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_timer = new Timer(TimerCallback, null, GetPlaybackTimerIntervalMs(), GetInactiveTimerIntervalMs());
|
||||
_timer = _timerFactory.Create(TimerCallback, null, GetPlaybackTimerIntervalMs(), GetInactiveTimerIntervalMs());
|
||||
|
||||
_timerActive = false;
|
||||
}
|
||||
@ -830,7 +834,7 @@ namespace Emby.Dlna.PlayTo
|
||||
set;
|
||||
}
|
||||
|
||||
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger)
|
||||
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, ITimerFactory timerFactory)
|
||||
{
|
||||
var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
|
||||
|
||||
@ -922,7 +926,7 @@ namespace Emby.Dlna.PlayTo
|
||||
}
|
||||
}
|
||||
|
||||
var device = new Device(deviceProperties, httpClient, logger, config);
|
||||
var device = new Device(deviceProperties, httpClient, logger, config, timerFactory);
|
||||
|
||||
if (isRenderer)
|
||||
{
|
||||
|
@ -11,12 +11,12 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Threading;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
@ -38,11 +38,12 @@ namespace Emby.Dlna.PlayTo
|
||||
private readonly IDeviceDiscovery _deviceDiscovery;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly ITimerFactory _timerFactory;
|
||||
|
||||
private readonly List<string> _nonRendererUrls = new List<string>();
|
||||
private DateTime _lastRendererClear;
|
||||
|
||||
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
|
||||
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, ITimerFactory timerFactory)
|
||||
{
|
||||
_logger = logger;
|
||||
_sessionManager = sessionManager;
|
||||
@ -58,6 +59,7 @@ namespace Emby.Dlna.PlayTo
|
||||
_localization = localization;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_timerFactory = timerFactory;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
@ -107,7 +109,7 @@ namespace Emby.Dlna.PlayTo
|
||||
|
||||
var uri = info.Location;
|
||||
_logger.Debug("Attempting to create PlayToController from location {0}", location);
|
||||
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger).ConfigureAwait(false);
|
||||
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, _timerFactory).ConfigureAwait(false);
|
||||
|
||||
if (device.RendererCommands == null)
|
||||
{
|
||||
|
@ -1,19 +1,30 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Emby.Dlna2")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Emby.Dlna")]
|
||||
[assembly: AssemblyProduct("Emby.Dlna2")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f40e364d-01d9-4bbf-b82c-5d6c55e0a1f5")]
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
@ -216,7 +216,17 @@ namespace Emby.Dlna.Server
|
||||
return "Emby - " + _serverName;
|
||||
}
|
||||
|
||||
var characters = _serverName.Where(c => (char.IsLetterOrDigit(c) || c == '-')).ToArray();
|
||||
var characterList = new List<char>();
|
||||
|
||||
foreach (var c in _serverName)
|
||||
{
|
||||
if (char.IsLetterOrDigit(c) || c == '-')
|
||||
{
|
||||
characterList.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
var characters = characterList.ToArray();
|
||||
|
||||
var serverName = new string(characters);
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace Emby.Dlna.Server
|
||||
{
|
||||
private readonly bool _asIs = false;
|
||||
private readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
|
||||
private readonly static Regex Validator = new Regex(@"^[a-z\d][a-z\d_.-]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private readonly static Regex Validator = new Regex(@"^[a-z\d][a-z\d_.-]+$", RegexOptions.IgnoreCase);
|
||||
|
||||
public Headers(bool asIs)
|
||||
{
|
||||
@ -42,13 +42,6 @@ namespace Emby.Dlna.Server
|
||||
return hb.ToString();
|
||||
}
|
||||
}
|
||||
public Stream HeaderStream
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MemoryStream(Encoding.ASCII.GetBytes(HeaderBlock));
|
||||
}
|
||||
}
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace Emby.Dlna.Server
|
||||
{
|
||||
@ -9,9 +10,9 @@ namespace Emby.Dlna.Server
|
||||
public readonly string Type;
|
||||
public readonly string USN;
|
||||
public readonly string Uuid;
|
||||
public readonly IPAddress Address;
|
||||
public readonly IpAddressInfo Address;
|
||||
|
||||
public UpnpDevice(string aUuid, string aType, Uri aDescriptor, IPAddress address)
|
||||
public UpnpDevice(string aUuid, string aType, Uri aDescriptor, IpAddressInfo address)
|
||||
{
|
||||
Uuid = aUuid;
|
||||
Type = aType;
|
||||
|
@ -4,9 +4,12 @@ using Emby.Dlna.Server;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Emby.Dlna.Didl;
|
||||
using MediaBrowser.Model.Xml;
|
||||
|
||||
namespace Emby.Dlna.Service
|
||||
{
|
||||
@ -16,11 +19,13 @@ namespace Emby.Dlna.Service
|
||||
|
||||
protected readonly IServerConfigurationManager Config;
|
||||
protected readonly ILogger Logger;
|
||||
protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory;
|
||||
|
||||
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger)
|
||||
protected BaseControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
||||
{
|
||||
Config = config;
|
||||
Logger = logger;
|
||||
XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
||||
}
|
||||
|
||||
public ControlResponse ProcessControlRequest(ControlRequest request)
|
||||
@ -53,47 +58,57 @@ namespace Emby.Dlna.Service
|
||||
|
||||
private ControlResponse ProcessControlRequestInternal(ControlRequest request)
|
||||
{
|
||||
var soap = new XmlDocument();
|
||||
soap.LoadXml(request.InputXml);
|
||||
var sparams = new Headers();
|
||||
var body = soap.GetElementsByTagName("Body", NS_SOAPENV).Item(0);
|
||||
ControlRequestInfo requestInfo = null;
|
||||
|
||||
var method = body.FirstChild;
|
||||
using (var streamReader = new StreamReader(request.InputXml))
|
||||
{
|
||||
var readerSettings = XmlReaderSettingsFactory.Create(false);
|
||||
|
||||
foreach (var p in method.ChildNodes)
|
||||
readerSettings.CheckCharacters = false;
|
||||
readerSettings.IgnoreProcessingInstructions = true;
|
||||
readerSettings.IgnoreComments = true;
|
||||
|
||||
using (var reader = XmlReader.Create(streamReader, readerSettings))
|
||||
{
|
||||
var e = p as XmlElement;
|
||||
if (e == null)
|
||||
{
|
||||
continue;
|
||||
requestInfo = ParseRequest(reader);
|
||||
}
|
||||
sparams.Add(e.LocalName, e.InnerText.Trim());
|
||||
}
|
||||
|
||||
Logger.Debug("Received control request {0}", method.LocalName);
|
||||
Logger.Debug("Received control request {0}", requestInfo.LocalName);
|
||||
|
||||
var result = GetResult(method.LocalName, sparams);
|
||||
var result = GetResult(requestInfo.LocalName, requestInfo.Headers);
|
||||
|
||||
var env = new XmlDocument();
|
||||
env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", string.Empty));
|
||||
var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV);
|
||||
env.AppendChild(envelope);
|
||||
envelope.SetAttribute("encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false
|
||||
};
|
||||
|
||||
var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV);
|
||||
env.DocumentElement.AppendChild(rbody);
|
||||
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
|
||||
|
||||
var response = env.CreateElement(String.Format("u:{0}Response", method.LocalName), method.NamespaceURI);
|
||||
rbody.AppendChild(response);
|
||||
using (XmlWriter writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
writer.WriteStartDocument(true);
|
||||
|
||||
writer.WriteStartElement("SOAP-ENV", "Envelope", NS_SOAPENV);
|
||||
writer.WriteAttributeString(string.Empty, "encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
|
||||
|
||||
writer.WriteStartElement("SOAP-ENV", "Body", NS_SOAPENV);
|
||||
writer.WriteStartElement("u", requestInfo.LocalName + "Response", requestInfo.NamespaceURI);
|
||||
foreach (var i in result)
|
||||
{
|
||||
var ri = env.CreateElement(i.Key);
|
||||
ri.InnerText = i.Value;
|
||||
response.AppendChild(ri);
|
||||
writer.WriteStartElement(i.Key);
|
||||
writer.WriteString(i.Value);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteEndElement();
|
||||
writer.WriteEndDocument();
|
||||
}
|
||||
|
||||
var xml = env.OuterXml.Replace("xmlns:m=", "xmlns:u=");
|
||||
var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=");
|
||||
|
||||
var controlResponse = new ControlResponse
|
||||
{
|
||||
@ -108,6 +123,102 @@ namespace Emby.Dlna.Service
|
||||
return controlResponse;
|
||||
}
|
||||
|
||||
private ControlRequestInfo ParseRequest(XmlReader reader)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
reader.Read();
|
||||
|
||||
// Loop through each element
|
||||
while (!reader.EOF)
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.LocalName)
|
||||
{
|
||||
case "Body":
|
||||
{
|
||||
using (var subReader = reader.ReadSubtree())
|
||||
{
|
||||
return ParseBodyTag(subReader);
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
reader.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
|
||||
return new ControlRequestInfo();
|
||||
}
|
||||
|
||||
private ControlRequestInfo ParseBodyTag(XmlReader reader)
|
||||
{
|
||||
var result = new ControlRequestInfo();
|
||||
|
||||
reader.MoveToContent();
|
||||
reader.Read();
|
||||
|
||||
// Loop through each element
|
||||
while (!reader.EOF)
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
result.LocalName = reader.LocalName;
|
||||
result.NamespaceURI = reader.NamespaceURI;
|
||||
|
||||
using (var subReader = reader.ReadSubtree())
|
||||
{
|
||||
result.Headers = ParseFirstBodyChild(subReader);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Headers ParseFirstBodyChild(XmlReader reader)
|
||||
{
|
||||
var result = new Headers();
|
||||
|
||||
reader.MoveToContent();
|
||||
reader.Read();
|
||||
|
||||
// Loop through each element
|
||||
while (!reader.EOF)
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
result.Add(reader.LocalName, reader.ReadElementContentAsString());
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private class ControlRequestInfo
|
||||
{
|
||||
public string LocalName;
|
||||
public string NamespaceURI;
|
||||
public Headers Headers = new Headers();
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams);
|
||||
|
||||
private void LogRequest(ControlRequest request)
|
||||
|
@ -1,6 +1,9 @@
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Emby.Dlna.Didl;
|
||||
|
||||
namespace Emby.Dlna.Service
|
||||
{
|
||||
@ -10,30 +13,41 @@ namespace Emby.Dlna.Service
|
||||
|
||||
public ControlResponse GetResponse(Exception ex)
|
||||
{
|
||||
var env = new XmlDocument();
|
||||
env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", "yes"));
|
||||
var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV);
|
||||
env.AppendChild(envelope);
|
||||
envelope.SetAttribute("encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
|
||||
var settings = new XmlWriterSettings
|
||||
{
|
||||
Encoding = Encoding.UTF8,
|
||||
CloseOutput = false
|
||||
};
|
||||
|
||||
var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV);
|
||||
env.DocumentElement.AppendChild(rbody);
|
||||
StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
|
||||
|
||||
var fault = env.CreateElement("SOAP-ENV", "Fault", NS_SOAPENV);
|
||||
var faultCode = env.CreateElement("faultcode");
|
||||
faultCode.InnerText = "500";
|
||||
fault.AppendChild(faultCode);
|
||||
var faultString = env.CreateElement("faultstring");
|
||||
faultString.InnerText = ex.ToString();
|
||||
fault.AppendChild(faultString);
|
||||
var detail = env.CreateDocumentFragment();
|
||||
detail.InnerXml = "<detail><UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\"><errorCode>401</errorCode><errorDescription>Invalid Action</errorDescription></UPnPError></detail>";
|
||||
fault.AppendChild(detail);
|
||||
rbody.AppendChild(fault);
|
||||
using (XmlWriter writer = XmlWriter.Create(builder, settings))
|
||||
{
|
||||
writer.WriteStartDocument(true);
|
||||
|
||||
writer.WriteStartElement("SOAP-ENV", "Envelope", NS_SOAPENV);
|
||||
writer.WriteAttributeString(string.Empty, "encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
|
||||
|
||||
writer.WriteStartElement("SOAP-ENV", "Body", NS_SOAPENV);
|
||||
writer.WriteStartElement("SOAP-ENV", "Fault", NS_SOAPENV);
|
||||
|
||||
writer.WriteElementString("faultcode", "500");
|
||||
writer.WriteElementString("faultstring", ex.Message);
|
||||
|
||||
writer.WriteStartElement("detail");
|
||||
writer.WriteRaw("<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\"><errorCode>401</errorCode><errorDescription>Invalid Action</errorDescription></UPnPError>");
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteEndElement();
|
||||
writer.WriteEndElement();
|
||||
|
||||
writer.WriteEndElement();
|
||||
writer.WriteEndDocument();
|
||||
}
|
||||
|
||||
return new ControlResponse
|
||||
{
|
||||
Xml = env.OuterXml,
|
||||
Xml = builder.ToString(),
|
||||
IsSuccessful = false
|
||||
};
|
||||
}
|
||||
|
@ -7,12 +7,13 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using Rssdp;
|
||||
|
||||
namespace Emby.Dlna.Ssdp
|
||||
@ -30,18 +31,23 @@ namespace Emby.Dlna.Ssdp
|
||||
|
||||
private SsdpDeviceLocator _DeviceLocator;
|
||||
|
||||
public DeviceDiscovery(ILogger logger, IServerConfigurationManager config)
|
||||
private readonly ITimerFactory _timerFactory;
|
||||
private readonly ISocketFactory _socketFactory;
|
||||
|
||||
public DeviceDiscovery(ILogger logger, IServerConfigurationManager config, ISocketFactory socketFactory, ITimerFactory timerFactory)
|
||||
{
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
_socketFactory = socketFactory;
|
||||
_timerFactory = timerFactory;
|
||||
}
|
||||
|
||||
// Call this method from somewhere in your code to start the search.
|
||||
public void BeginSearch()
|
||||
{
|
||||
_DeviceLocator = new SsdpDeviceLocator();
|
||||
_DeviceLocator = new SsdpDeviceLocator(_socketFactory, _timerFactory);
|
||||
|
||||
// (Optional) Set the filter so we only see notifications for devices we care about
|
||||
// (can be any search target value i.e device type, uuid value etc - any value that appears in the
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
@ -1,57 +0,0 @@
|
||||
{
|
||||
"version": "1.0.0-*",
|
||||
|
||||
"dependencies": {
|
||||
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"net46": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Collections": "4.0.0.0",
|
||||
"System.IO": "4.0.0.0",
|
||||
"System.Xml": "4.0.0.0",
|
||||
"System.Xml.Linq": "4.0.0.0",
|
||||
"System.Xml.Serialization": "4.0.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"MediaBrowser.Controller": {
|
||||
"target": "project"
|
||||
},
|
||||
"MediaBrowser.Common": {
|
||||
"target": "project"
|
||||
},
|
||||
"MediaBrowser.Model": {
|
||||
"target": "project"
|
||||
},
|
||||
"RSSDP": {
|
||||
"target": "project"
|
||||
}
|
||||
}
|
||||
},
|
||||
"netstandard1.6": {
|
||||
"imports": "dnxcore50",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.0",
|
||||
"MediaBrowser.Controller": {
|
||||
"target": "project"
|
||||
},
|
||||
"MediaBrowser.Common": {
|
||||
"target": "project"
|
||||
},
|
||||
"MediaBrowser.Model": {
|
||||
"target": "project"
|
||||
},
|
||||
"System.Xml.XmlSerializer": "4.0.11",
|
||||
"System.Xml.XDocument": "4.0.11",
|
||||
"System.Xml.XmlDocument": "4.0.1",
|
||||
"System.Reflection": "4.1.0",
|
||||
"System.Reflection.Primitives": "4.0.1",
|
||||
"System.Runtime.Loader": "4.0.0",
|
||||
"RSSDP": {
|
||||
"target": "project"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -159,6 +159,9 @@
|
||||
<Compile Include="ScheduledTasks\RefreshIntrosTask.cs" />
|
||||
<Compile Include="ScheduledTasks\RefreshMediaLibraryTask.cs" />
|
||||
<Compile Include="ScheduledTasks\SystemUpdateTask.cs" />
|
||||
<Compile Include="Security\MBLicenseFile.cs" />
|
||||
<Compile Include="Security\PluginSecurityManager.cs" />
|
||||
<Compile Include="Security\RegRecord.cs" />
|
||||
<Compile Include="ServerManager\ServerManager.cs" />
|
||||
<Compile Include="ServerManager\WebSocketConnection.cs" />
|
||||
<Compile Include="Session\HttpSessionController.cs" />
|
||||
|
@ -4,15 +4,18 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Security
|
||||
namespace Emby.Server.Implementations.Security
|
||||
{
|
||||
internal class MBLicenseFile
|
||||
{
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
public string RegKey
|
||||
{
|
||||
@ -40,9 +43,11 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
private readonly object _fileLock = new object();
|
||||
private string _regKey;
|
||||
|
||||
public MBLicenseFile(IApplicationPaths appPaths)
|
||||
public MBLicenseFile(IApplicationPaths appPaths, IFileSystem fileSystem, ICryptographyProvider cryptographyProvider)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
_fileSystem = fileSystem;
|
||||
_cryptographyProvider = cryptographyProvider;
|
||||
|
||||
Load();
|
||||
}
|
||||
@ -54,22 +59,16 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
|
||||
public void AddRegCheck(string featureId)
|
||||
{
|
||||
using (var provider = new MD5CryptoServiceProvider())
|
||||
{
|
||||
var key = new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId)));
|
||||
var key = new Guid(_cryptographyProvider.GetMD5Bytes(Encoding.Unicode.GetBytes(featureId)));
|
||||
var value = DateTime.UtcNow;
|
||||
|
||||
SetUpdateRecord(key, value);
|
||||
Save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void RemoveRegCheck(string featureId)
|
||||
{
|
||||
using (var provider = new MD5CryptoServiceProvider())
|
||||
{
|
||||
var key = new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId)));
|
||||
var key = new Guid(_cryptographyProvider.GetMD5Bytes(Encoding.Unicode.GetBytes(featureId)));
|
||||
DateTime val;
|
||||
|
||||
_updateRecords.TryRemove(key, out val);
|
||||
@ -77,19 +76,14 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
Save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public DateTime LastChecked(string featureId)
|
||||
{
|
||||
using (var provider = new MD5CryptoServiceProvider())
|
||||
{
|
||||
DateTime last;
|
||||
_updateRecords.TryGetValue(new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId))), out last);
|
||||
_updateRecords.TryGetValue(new Guid(_cryptographyProvider.GetMD5Bytes(Encoding.Unicode.GetBytes(featureId))), out last);
|
||||
|
||||
// guard agains people just putting a large number in the file
|
||||
return last < DateTime.UtcNow ? last : DateTime.MinValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
@ -99,15 +93,21 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
{
|
||||
try
|
||||
{
|
||||
contents = File.ReadAllLines(licenseFile);
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
File.Create(licenseFile).Close();
|
||||
contents = _fileSystem.ReadAllLines(licenseFile);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
File.Create(licenseFile).Close();
|
||||
lock (_fileLock)
|
||||
{
|
||||
_fileSystem.WriteAllBytes(licenseFile, new byte[] {});
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
lock (_fileLock)
|
||||
{
|
||||
_fileSystem.WriteAllBytes(licenseFile, new byte[] { });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (contents != null && contents.Length > 0)
|
||||
@ -150,8 +150,11 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
}
|
||||
|
||||
var licenseFile = Filename;
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(licenseFile));
|
||||
lock (_fileLock) File.WriteAllLines(licenseFile, lines);
|
||||
_fileSystem.CreateDirectory(Path.GetDirectoryName(licenseFile));
|
||||
lock (_fileLock)
|
||||
{
|
||||
_fileSystem.WriteAllLines(licenseFile, lines);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,18 +5,18 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Security;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Security
|
||||
namespace Emby.Server.Implementations.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Class PluginSecurityManager
|
||||
@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
private MBLicenseFile _licenseFile;
|
||||
private MBLicenseFile LicenseFile
|
||||
{
|
||||
get { return _licenseFile ?? (_licenseFile = new MBLicenseFile(_appPaths)); }
|
||||
get { return _licenseFile ?? (_licenseFile = new MBLicenseFile(_appPaths, _fileSystem, _cryptographyProvider)); }
|
||||
}
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
@ -64,6 +64,7 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
private readonly ILogger _logger;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
private IEnumerable<IRequiresRegistration> _registeredEntities;
|
||||
protected IEnumerable<IRequiresRegistration> RegisteredEntities
|
||||
@ -78,7 +79,7 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
/// Initializes a new instance of the <see cref="PluginSecurityManager" /> class.
|
||||
/// </summary>
|
||||
public PluginSecurityManager(IServerApplicationHost appHost, IHttpClient httpClient, IJsonSerializer jsonSerializer,
|
||||
IApplicationPaths appPaths, ILogManager logManager, IFileSystem fileSystem)
|
||||
IApplicationPaths appPaths, ILogManager logManager, IFileSystem fileSystem, ICryptographyProvider cryptographyProvider)
|
||||
{
|
||||
if (httpClient == null)
|
||||
{
|
||||
@ -90,6 +91,7 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_appPaths = appPaths;
|
||||
_fileSystem = fileSystem;
|
||||
_cryptographyProvider = cryptographyProvider;
|
||||
_logger = logManager.GetLogger("SecurityManager");
|
||||
}
|
||||
|
||||
@ -191,7 +193,7 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
{
|
||||
var msg = "Result from appstore registration was null.";
|
||||
_logger.Error(msg);
|
||||
throw new ApplicationException(msg);
|
||||
throw new ArgumentException(msg);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(reg.key))
|
||||
{
|
||||
@ -200,7 +202,7 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
}
|
||||
|
||||
}
|
||||
catch (ApplicationException)
|
||||
catch (ArgumentException)
|
||||
{
|
||||
SaveAppStoreInfo(parameters);
|
||||
throw;
|
||||
@ -213,14 +215,14 @@ namespace MediaBrowser.Server.Implementations.Security
|
||||
{
|
||||
throw new PaymentRequiredException();
|
||||
}
|
||||
throw new ApplicationException("Error registering store sale");
|
||||
throw new Exception("Error registering store sale");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Error registering appstore purchase {0}", e, parameters ?? "NO PARMS SENT");
|
||||
SaveAppStoreInfo(parameters);
|
||||
//TODO - could create a re-try routine on start-up if this file is there. For now we can handle manually.
|
||||
throw new ApplicationException("Error registering store sale");
|
||||
throw new Exception("Error registering store sale");
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Security
|
||||
namespace Emby.Server.Implementations.Security
|
||||
{
|
||||
class RegRecord
|
||||
{
|
@ -152,42 +152,39 @@ namespace MediaBrowser.Api.Dlna
|
||||
return ResultFactory.GetResult(xml, XMLContentType);
|
||||
}
|
||||
|
||||
public async Task<object> Post(ProcessMediaReceiverRegistrarControlRequest request)
|
||||
public object Post(ProcessMediaReceiverRegistrarControlRequest request)
|
||||
{
|
||||
var response = await PostAsync(request.RequestStream, _mediaReceiverRegistrar).ConfigureAwait(false);
|
||||
var response = PostAsync(request.RequestStream, _mediaReceiverRegistrar);
|
||||
|
||||
return ResultFactory.GetResult(response.Xml, XMLContentType);
|
||||
}
|
||||
|
||||
public async Task<object> Post(ProcessContentDirectoryControlRequest request)
|
||||
public object Post(ProcessContentDirectoryControlRequest request)
|
||||
{
|
||||
var response = await PostAsync(request.RequestStream, _contentDirectory).ConfigureAwait(false);
|
||||
var response = PostAsync(request.RequestStream, _contentDirectory);
|
||||
|
||||
return ResultFactory.GetResult(response.Xml, XMLContentType);
|
||||
}
|
||||
|
||||
public async Task<object> Post(ProcessConnectionManagerControlRequest request)
|
||||
public object Post(ProcessConnectionManagerControlRequest request)
|
||||
{
|
||||
var response = await PostAsync(request.RequestStream, _connectionManager).ConfigureAwait(false);
|
||||
var response = PostAsync(request.RequestStream, _connectionManager);
|
||||
|
||||
return ResultFactory.GetResult(response.Xml, XMLContentType);
|
||||
}
|
||||
|
||||
private async Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
|
||||
private ControlResponse PostAsync(Stream requestStream, IUpnpService service)
|
||||
{
|
||||
var id = GetPathValue(2);
|
||||
|
||||
using (var reader = new StreamReader(requestStream))
|
||||
{
|
||||
return service.ProcessControlRequest(new ControlRequest
|
||||
{
|
||||
Headers = Request.Headers.ToDictionary(),
|
||||
InputXml = await reader.ReadToEndAsync().ConfigureAwait(false),
|
||||
InputXml = requestStream,
|
||||
TargetServerUuId = id,
|
||||
RequestedUrl = Request.AbsoluteUri
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public object Get(GetIcon request)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
@ -6,7 +7,7 @@ namespace MediaBrowser.Controller.Dlna
|
||||
{
|
||||
public IDictionary<string, string> Headers { get; set; }
|
||||
|
||||
public string InputXml { get; set; }
|
||||
public Stream InputXml { get; set; }
|
||||
|
||||
public string TargetServerUuId { get; set; }
|
||||
|
||||
|
@ -276,6 +276,10 @@ namespace MediaBrowser.Model.IO
|
||||
/// <returns>System.String.</returns>
|
||||
string ReadAllText(string path, Encoding encoding);
|
||||
|
||||
string[] ReadAllLines(string path);
|
||||
|
||||
void WriteAllLines(string path, IEnumerable<string> lines);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the directory paths.
|
||||
/// </summary>
|
||||
|
@ -137,6 +137,10 @@
|
||||
<Compile Include="Dto\MetadataEditorInfo.cs" />
|
||||
<Compile Include="Dto\NameIdPair.cs" />
|
||||
<Compile Include="Dto\NameValuePair.cs" />
|
||||
<Compile Include="Net\IpEndPointInfo.cs" />
|
||||
<Compile Include="Net\ISocketFactory.cs" />
|
||||
<Compile Include="Net\IUdpSocket.cs" />
|
||||
<Compile Include="Net\ReceivedUdpData.cs" />
|
||||
<Compile Include="TextEncoding\IEncoding.cs" />
|
||||
<Compile Include="Extensions\LinqExtensions.cs" />
|
||||
<Compile Include="FileOrganization\SmartMatchInfo.cs" />
|
||||
|
@ -1,10 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
|
||||
namespace MediaBrowser.Model.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Implemented by components that can create a platform specific UDP socket implementation, and wrap it in the cross platform <see cref="IUdpSocket"/> interface.
|
||||
@ -26,8 +21,6 @@ namespace Rssdp.Infrastructure
|
||||
/// <param name="multicastTimeToLive">The multicast time to live value. Actually a maximum number of network hops for UDP packets.</param>
|
||||
/// <param name="localPort">The local port to bind to.</param>
|
||||
/// <returns>A <see cref="IUdpSocket"/> implementation.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "ip", Justification="IP is a well known and understood abbreviation and the full name is excessive.")]
|
||||
IUdpSocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort);
|
||||
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
namespace MediaBrowser.Model.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a common interface across platforms for UDP sockets used by this SSDP implementation.
|
||||
@ -15,14 +15,13 @@ namespace Rssdp.Infrastructure
|
||||
/// Waits for and returns the next UDP message sent to this socket (uni or multicast).
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
System.Threading.Tasks.Task<ReceivedUdpData> ReceiveAsync();
|
||||
Task<ReceivedUdpData> ReceiveAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Sends a UDP message to a particular end point (uni or multicast).
|
||||
/// </summary>
|
||||
/// <param name="messageData">The data to send.</param>
|
||||
/// <param name="endPoint">The <see cref="UdpEndPoint"/> providing the address and port to send to.</param>
|
||||
Task SendTo(byte[] messageData, UdpEndPoint endPoint);
|
||||
|
||||
/// <param name="endPoint">The <see cref="IpEndPointInfo"/> providing the address and port to send to.</param>
|
||||
Task SendTo(byte[] messageData, IpEndPointInfo endPoint);
|
||||
}
|
||||
}
|
18
MediaBrowser.Model/Net/IpEndPointInfo.cs
Normal file
18
MediaBrowser.Model/Net/IpEndPointInfo.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Model.Net
|
||||
{
|
||||
public class IpEndPointInfo
|
||||
{
|
||||
public IpAddressInfo IpAddress { get; set; }
|
||||
|
||||
public int Port { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var ipAddresString = IpAddress == null ? string.Empty : IpAddress.ToString();
|
||||
|
||||
return ipAddresString + ":" + this.Port.ToString();
|
||||
}
|
||||
}
|
||||
}
|
24
MediaBrowser.Model/Net/ReceivedUdpData.cs
Normal file
24
MediaBrowser.Model/Net/ReceivedUdpData.cs
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
namespace MediaBrowser.Model.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Used by the sockets wrapper to hold raw data received from a UDP socket.
|
||||
/// </summary>
|
||||
public sealed class ReceivedUdpData
|
||||
{
|
||||
/// <summary>
|
||||
/// The buffer to place received data into.
|
||||
/// </summary>
|
||||
public byte[] Buffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes received.
|
||||
/// </summary>
|
||||
public int ReceivedBytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IpEndPointInfo"/> the data was received from.
|
||||
/// </summary>
|
||||
public IpEndPointInfo ReceivedFrom { get; set; }
|
||||
}
|
||||
}
|
@ -6,5 +6,6 @@ namespace MediaBrowser.Model.Reflection
|
||||
public interface IAssemblyInfo
|
||||
{
|
||||
Stream GetManifestResourceStream(Type type, string resource);
|
||||
string[] GetManifestResourceNames(Type type);
|
||||
}
|
||||
}
|
||||
|
@ -39,14 +39,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Photos", "Emby.Photos\
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Emby.Common.Implementations", "Emby.Common.Implementations\Emby.Common.Implementations.xproj", "{5A27010A-09C6-4E86-93EA-437484C10917}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RSSDP", "RSSDP\RSSDP.xproj", "{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Emby.Dlna", "Emby.Dlna\Emby.Dlna.xproj", "{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Mono.Nat", "Mono.Nat\Mono.Nat.xproj", "{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Server.Implementations", "Emby.Server.Implementations\Emby.Server.Implementations.csproj", "{E383961B-9356-4D5D-8233-9A1079D03055}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RSSDP", "RSSDP\RSSDP.csproj", "{21002819-C39A-4D3E-BE83-2A276A77FB1F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Dlna", "Emby.Dlna\Emby.Dlna.csproj", "{805844AB-E92F-45E6-9D99-4F6D48D129A5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -243,28 +243,6 @@ Global
|
||||
{5A27010A-09C6-4E86-93EA-437484C10917}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5A27010A-09C6-4E86-93EA-437484C10917}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5A27010A-09C6-4E86-93EA-437484C10917}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|x86.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|x86.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|x86.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|x86.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
@ -289,6 +267,30 @@ Global
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Release|x86.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|x86.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|x86.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|x86.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|x86.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1,10 +1,10 @@
|
||||
using MediaBrowser.Common.Net;
|
||||
using System;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Server.Implementations.Udp;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
{
|
||||
@ -60,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
||||
|
||||
UdpServer = udpServer;
|
||||
}
|
||||
catch (SocketException ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Failed to start UDP Server", ex);
|
||||
}
|
||||
|
@ -171,9 +171,6 @@
|
||||
<Compile Include="Persistence\DataExtensions.cs" />
|
||||
<Compile Include="Persistence\IDbConnector.cs" />
|
||||
<Compile Include="Persistence\MediaStreamColumns.cs" />
|
||||
<Compile Include="Security\MBLicenseFile.cs" />
|
||||
<Compile Include="Security\PluginSecurityManager.cs" />
|
||||
<Compile Include="Security\RegRecord.cs" />
|
||||
<Compile Include="Serialization\JsonSerializer.cs" />
|
||||
<Compile Include="Social\SharingManager.cs" />
|
||||
<Compile Include="Social\SharingRepository.cs" />
|
||||
|
@ -112,6 +112,7 @@ using Emby.Server.Implementations.MediaEncoder;
|
||||
using Emby.Server.Implementations.Notifications;
|
||||
using Emby.Server.Implementations.Persistence;
|
||||
using Emby.Server.Implementations.Playlists;
|
||||
using Emby.Server.Implementations.Security;
|
||||
using Emby.Server.Implementations.ServerManager;
|
||||
using Emby.Server.Implementations.Session;
|
||||
using Emby.Server.Implementations.Sync;
|
||||
@ -532,7 +533,7 @@ namespace MediaBrowser.Server.Startup.Common
|
||||
{
|
||||
await base.RegisterResources(progress).ConfigureAwait(false);
|
||||
|
||||
SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager, FileSystemManager);
|
||||
SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager, FileSystemManager, CryptographyProvider);
|
||||
RegisterSingleInstance(SecurityManager);
|
||||
|
||||
InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager, CryptographyProvider);
|
||||
@ -558,7 +559,8 @@ namespace MediaBrowser.Server.Startup.Common
|
||||
RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer(FileSystemManager, textEncoding));
|
||||
|
||||
RegisterSingleInstance<IXmlReaderSettingsFactory>(new XmlReaderSettingsFactory());
|
||||
RegisterSingleInstance<IAssemblyInfo>(new AssemblyInfo());
|
||||
IAssemblyInfo assemblyInfo = new AssemblyInfo();
|
||||
RegisterSingleInstance<IAssemblyInfo>(assemblyInfo);
|
||||
|
||||
UserDataManager = new UserDataManager(LogManager, ServerConfigurationManager);
|
||||
RegisterSingleInstance(UserDataManager);
|
||||
@ -648,10 +650,10 @@ namespace MediaBrowser.Server.Startup.Common
|
||||
SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager, TimerFactory);
|
||||
RegisterSingleInstance(SessionManager);
|
||||
|
||||
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("Dlna"), JsonSerializer, this);
|
||||
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("Dlna"), JsonSerializer, this, assemblyInfo);
|
||||
RegisterSingleInstance<IDlnaManager>(dlnaManager);
|
||||
|
||||
var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient);
|
||||
var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient, new XmlReaderSettingsFactory());
|
||||
RegisterSingleInstance<IConnectionManager>(connectionManager);
|
||||
|
||||
CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"), ProviderManager);
|
||||
@ -666,10 +668,10 @@ namespace MediaBrowser.Server.Startup.Common
|
||||
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
|
||||
RegisterSingleInstance(UserViewManager);
|
||||
|
||||
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder);
|
||||
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory());
|
||||
RegisterSingleInstance<IContentDirectory>(contentDirectory);
|
||||
|
||||
var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager);
|
||||
var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory());
|
||||
RegisterSingleInstance<IMediaReceiverRegistrar>(mediaRegistrar);
|
||||
|
||||
NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager);
|
||||
@ -678,7 +680,7 @@ namespace MediaBrowser.Server.Startup.Common
|
||||
SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager);
|
||||
RegisterSingleInstance(SubtitleManager);
|
||||
|
||||
RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager));
|
||||
RegisterSingleInstance<IDeviceDiscovery>(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager, SocketFactory, TimerFactory));
|
||||
|
||||
ChapterManager = new ChapterManager(LibraryManager, LogManager.GetLogger("ChapterManager"), ServerConfigurationManager, ItemRepository);
|
||||
RegisterSingleInstance(ChapterManager);
|
||||
|
@ -35,9 +35,6 @@
|
||||
<Reference Include="Emby.Common.Implementations">
|
||||
<HintPath>..\ThirdParty\emby\Emby.Common.Implementations.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Emby.Dlna">
|
||||
<HintPath>..\ThirdParty\emby\Emby.Dlna.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MediaBrowser.Naming, Version=1.0.6151.30291, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.59\lib\portable-net45+win8\MediaBrowser.Naming.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
@ -50,9 +47,6 @@
|
||||
<HintPath>..\packages\Patterns.Logging.1.0.0.6\lib\portable-net45+win8\Patterns.Logging.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="RSSDP">
|
||||
<HintPath>..\ThirdParty\emby\RSSDP.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ServiceStack.Interfaces, Version=4.0.0.0, Culture=neutral, PublicKeyToken=e06fbc6124f57c43, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
|
||||
@ -99,6 +93,10 @@
|
||||
<Compile Include="UnhandledExceptionWriter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj">
|
||||
<Project>{805844ab-e92f-45e6-9d99-4f6d48d129a5}</Project>
|
||||
<Name>Emby.Dlna</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj">
|
||||
<Project>{08fff49b-f175-4807-a2b5-73b0ebd9f716}</Project>
|
||||
<Name>Emby.Drawing</Name>
|
||||
@ -155,6 +153,10 @@
|
||||
<Project>{4a4402d4-e910-443b-b8fc-2c18286a2ca0}</Project>
|
||||
<Name>OpenSubtitlesHandler</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\RSSDP\RSSDP.csproj">
|
||||
<Project>{21002819-c39a-4d3e-be83-2a276a77fb1f}</Project>
|
||||
<Name>RSSDP</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
|
128
MediaBrowser.sln
128
MediaBrowser.sln
@ -64,14 +64,14 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Emby.Common.Implementations
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BDInfo", "BDInfo\BDInfo.csproj", "{88AE38DF-19D7-406F-A6A9-09527719A21E}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RSSDP", "RSSDP\RSSDP.xproj", "{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Server.Implementations", "Emby.Server.Implementations\Emby.Server.Implementations.csproj", "{E383961B-9356-4D5D-8233-9A1079D03055}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Emby.Dlna", "Emby.Dlna\Emby.Dlna.xproj", "{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Mono.Nat", "Mono.Nat\Mono.Nat.xproj", "{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RSSDP", "RSSDP\RSSDP.csproj", "{21002819-C39A-4D3E-BE83-2A276A77FB1F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Dlna", "Emby.Dlna\Emby.Dlna.csproj", "{805844AB-E92F-45E6-9D99-4F6D48D129A5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -566,36 +566,6 @@ Global
|
||||
{88AE38DF-19D7-406F-A6A9-09527719A21E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{88AE38DF-19D7-406F-A6A9-09527719A21E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{88AE38DF-19D7-406F-A6A9-09527719A21E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|Win32.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|Win32.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|x64.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|x64.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|x86.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release Mono|x86.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C227ADB7-E256-4E70-A8B9-22B9E0CF4F55}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
@ -626,36 +596,6 @@ Global
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E383961B-9356-4D5D-8233-9A1079D03055}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|Win32.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|Win32.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|x64.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|x64.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|x86.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release Mono|x86.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F40E364D-01D9-4BBF-B82C-5D6C55E0A1F5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
@ -686,6 +626,66 @@ Global
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4ACAB6A2-AC9A-4B50-BAEC-1FE4A1F3B8BC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|Win32.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|Win32.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|x64.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|x64.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|x86.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release Mono|x86.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{21002819-C39A-4D3E-BE83-2A276A77FB1F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|Win32.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|Win32.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|x64.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|x64.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|x86.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release Mono|x86.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|x64.Build.0 = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{805844AB-E92F-45E6-9D99-4F6D48D129A5}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
@ -44,8 +45,8 @@ namespace Rssdp.Infrastructure
|
||||
/// Sends a message to a particular address (uni or multicast) and port.
|
||||
/// </summary>
|
||||
/// <param name="messageData">A byte array containing the data to send.</param>
|
||||
/// <param name="destination">A <see cref="UdpEndPoint"/> representing the destination address for the data. Can be either a multicast or unicast destination.</param>
|
||||
Task SendMessage(byte[] messageData, UdpEndPoint destination);
|
||||
/// <param name="destination">A <see cref="IpEndPointInfo"/> representing the destination address for the data. Can be either a multicast or unicast destination.</param>
|
||||
Task SendMessage(byte[] messageData, IpEndPointInfo destination);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to the SSDP multicast address and port.
|
||||
|
@ -1,19 +1,30 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("RSSDP2")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("RSSDP")]
|
||||
[assembly: AssemblyProduct("RSSDP2")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c227adb7-e256-4e70-a8b9-22b9e0cf4f55")]
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
@ -1,23 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
|
||||
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{67F9D3A8-F71E-4428-913F-C37AE82CDB24}</ProjectGuid>
|
||||
<ProjectGuid>{21002819-C39A-4D3E-BE83-2A276A77FB1F}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Rssdp</RootNamespace>
|
||||
<AssemblyName>Rssdp.Portable</AssemblyName>
|
||||
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TargetFrameworkProfile>Profile44</TargetFrameworkProfile>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<RootNamespace>RSSDP</RootNamespace>
|
||||
<AssemblyName>RSSDP</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NuGetPackageImportStamp>1c5b2aa5</NuGetPackageImportStamp>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@ -27,79 +24,57 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
<CodeAnalysisRuleSet>..\RssdpRuleset.ruleset</CodeAnalysisRuleSet>
|
||||
<DocumentationFile>bin\Debug\Rssdp.Portable.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\lib\portable-net45+win+wpa81+wp80\</OutputPath>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>..\RssdpRuleset.ruleset</CodeAnalysisRuleSet>
|
||||
<DocumentationFile>..\lib\portable-net45+win+wpa81+wp80\Rssdp.Portable.XML</DocumentationFile>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Shared\AssemblyInfoCommon.cs">
|
||||
<Link>Properties\AssemblyInfoCommon.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="CustomHttpHeaders.cs" />
|
||||
<Compile Include="DeviceAvailableEventArgs.cs" />
|
||||
<Compile Include="DeviceEventArgs.cs" />
|
||||
<Compile Include="DeviceUnavailableEventArgs.cs" />
|
||||
<Compile Include="DiscoveredSsdpDevice.cs" />
|
||||
<Compile Include="DisposableManagedObjectBase.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="HttpParserBase.cs" />
|
||||
<Compile Include="HttpRequestParser.cs" />
|
||||
<Compile Include="HttpResponseParser.cs" />
|
||||
<Compile Include="IEnumerableExtensions.cs" />
|
||||
<Compile Include="ISsdpCommunicationsServer.cs" />
|
||||
<Compile Include="ISsdpDeviceLocator.cs" />
|
||||
<Compile Include="ISsdpDevicePublisher.cs" />
|
||||
<Compile Include="IUPnPDeviceValidator.cs" />
|
||||
<Compile Include="ReadOnlyEnumerable.cs" />
|
||||
<Compile Include="SsdpDeviceExtensions.cs" />
|
||||
<Compile Include="SsdpDeviceLocatorBase.cs" />
|
||||
<Compile Include="DiscoveredSsdpDevice.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="HttpRequestParser.cs" />
|
||||
<Compile Include="HttpResponseParser.cs" />
|
||||
<Compile Include="ISocketFactory.cs" />
|
||||
<Compile Include="IUdpSocket.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ReceivedUdpData.cs" />
|
||||
<Compile Include="ReadOnlyEnumerable.cs" />
|
||||
<Compile Include="RequestReceivedEventArgs.cs" />
|
||||
<Compile Include="ResponseReceivedEventArgs.cs" />
|
||||
<Compile Include="SsdpCommunicationsServer.cs" />
|
||||
<Compile Include="SsdpConstants.cs" />
|
||||
<Compile Include="SsdpDevice.cs" />
|
||||
<Compile Include="SsdpDeviceExtensions.cs" />
|
||||
<Compile Include="SsdpDeviceIcon.cs" />
|
||||
<Compile Include="SsdpDeviceLocator.cs" />
|
||||
<Compile Include="SsdpDeviceLocatorBase.cs" />
|
||||
<Compile Include="SsdpDeviceProperties.cs" />
|
||||
<Compile Include="SsdpDeviceProperty.cs" />
|
||||
<Compile Include="SsdpDevicePublisher.cs" />
|
||||
<Compile Include="SsdpDevicePublisherBase.cs" />
|
||||
<Compile Include="SsdpEmbeddedDevice.cs" />
|
||||
<Compile Include="SsdpRootDevice.cs" />
|
||||
<Compile Include="UdpEndPoint.cs" />
|
||||
<Compile Include="UPnP10DeviceValidator.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CodeAnalysisDictionary Include="..\Shared\CodeAnalysisDictionary.xml">
|
||||
<Link>Properties\CodeAnalysisDictionary.xml</Link>
|
||||
<SubType>Designer</SubType>
|
||||
</CodeAnalysisDictionary>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
|
||||
<Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
|
||||
<Name>MediaBrowser.Model</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>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}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>c227adb7-e256-4e70-a8b9-22b9e0cf4f55</ProjectGuid>
|
||||
<RootNamespace>RSSDP</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// Used by the sockets wrapper to hold raw data received from a UDP socket.
|
||||
/// </summary>
|
||||
public sealed class ReceivedUdpData
|
||||
{
|
||||
/// <summary>
|
||||
/// The buffer to place received data into.
|
||||
/// </summary>
|
||||
public byte[] Buffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes received.
|
||||
/// </summary>
|
||||
public int ReceivedBytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="UdpEndPoint"/> the data was received from.
|
||||
/// </summary>
|
||||
public UdpEndPoint ReceivedFrom { get; set; }
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
@ -17,7 +18,7 @@ namespace Rssdp.Infrastructure
|
||||
#region Fields
|
||||
|
||||
private readonly HttpRequestMessage _Message;
|
||||
private readonly UdpEndPoint _ReceivedFrom;
|
||||
private readonly IpEndPointInfo _ReceivedFrom;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -28,7 +29,7 @@ namespace Rssdp.Infrastructure
|
||||
/// </summary>
|
||||
/// <param name="message">The <see cref="HttpRequestMessage"/> that was received.</param>
|
||||
/// <param name="receivedFrom">A <see cref="UdpEndPoint"/> representing the sender's address (sometimes used for replies).</param>
|
||||
public RequestReceivedEventArgs(HttpRequestMessage message, UdpEndPoint receivedFrom)
|
||||
public RequestReceivedEventArgs(HttpRequestMessage message, IpEndPointInfo receivedFrom)
|
||||
{
|
||||
_Message = message;
|
||||
_ReceivedFrom = receivedFrom;
|
||||
@ -49,7 +50,7 @@ namespace Rssdp.Infrastructure
|
||||
/// <summary>
|
||||
/// The <see cref="UdpEndPoint"/> the request came from.
|
||||
/// </summary>
|
||||
public UdpEndPoint ReceivedFrom
|
||||
public IpEndPointInfo ReceivedFrom
|
||||
{
|
||||
get { return _ReceivedFrom; }
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
@ -17,7 +18,7 @@ namespace Rssdp.Infrastructure
|
||||
#region Fields
|
||||
|
||||
private readonly HttpResponseMessage _Message;
|
||||
private readonly UdpEndPoint _ReceivedFrom;
|
||||
private readonly IpEndPointInfo _ReceivedFrom;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -26,9 +27,7 @@ namespace Rssdp.Infrastructure
|
||||
/// <summary>
|
||||
/// Full constructor.
|
||||
/// </summary>
|
||||
/// <param name="message">The <see cref="HttpResponseMessage"/> that was received.</param>
|
||||
/// <param name="receivedFrom">A <see cref="UdpEndPoint"/> representing the sender's address (sometimes used for replies).</param>
|
||||
public ResponseReceivedEventArgs(HttpResponseMessage message, UdpEndPoint receivedFrom)
|
||||
public ResponseReceivedEventArgs(HttpResponseMessage message, IpEndPointInfo receivedFrom)
|
||||
{
|
||||
_Message = message;
|
||||
_ReceivedFrom = receivedFrom;
|
||||
@ -49,7 +48,7 @@ namespace Rssdp.Infrastructure
|
||||
/// <summary>
|
||||
/// The <see cref="UdpEndPoint"/> the response came from.
|
||||
/// </summary>
|
||||
public UdpEndPoint ReceivedFrom
|
||||
public IpEndPointInfo ReceivedFrom
|
||||
{
|
||||
get { return _ReceivedFrom; }
|
||||
}
|
||||
|
@ -1,114 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using Rssdp.Infrastructure;
|
||||
|
||||
namespace Rssdp
|
||||
{
|
||||
// THIS IS A LINKED FILE - SHARED AMONGST MULTIPLE PLATFORMS
|
||||
// Be careful to check any changes compile and work for all platform projects it is shared in.
|
||||
|
||||
// Not entirely happy with this. Would have liked to have done something more generic/reusable,
|
||||
// but that wasn't really the point so kept to YAGNI principal for now, even if the
|
||||
// interfaces are a bit ugly, specific and make assumptions.
|
||||
|
||||
/// <summary>
|
||||
/// Used by RSSDP components to create implementations of the <see cref="IUdpSocket"/> interface, to perform platform agnostic socket communications.
|
||||
/// </summary>
|
||||
public sealed class SocketFactory : ISocketFactory
|
||||
{
|
||||
private IPAddress _LocalIP;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor.
|
||||
/// </summary>
|
||||
/// <param name="localIP">A string containing the IP address of the local network adapter to bind sockets to. Null or empty string will use <see cref="IPAddress.Any"/>.</param>
|
||||
public SocketFactory(string localIP)
|
||||
{
|
||||
if (String.IsNullOrEmpty(localIP))
|
||||
_LocalIP = IPAddress.Any;
|
||||
else
|
||||
_LocalIP = IPAddress.Parse(localIP);
|
||||
}
|
||||
|
||||
#region ISocketFactory Members
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new UDP socket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
|
||||
/// </summary>
|
||||
/// <param name="localPort">An integer specifying the local port to bind the socket to.</param>
|
||||
/// <returns>An implementation of the <see cref="IUdpSocket"/> interface used by RSSDP components to perform socket operations.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "The purpose of this method is to create and returns a disposable result, it is up to the caller to dispose it when they are done with it.")]
|
||||
public IUdpSocket CreateUdpSocket(int localPort)
|
||||
{
|
||||
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
|
||||
|
||||
var retVal = new Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
|
||||
try
|
||||
{
|
||||
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, SsdpConstants.SsdpDefaultMulticastTimeToLive);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse(SsdpConstants.MulticastLocalAdminAddress), _LocalIP));
|
||||
return new UdpSocket(retVal, localPort, _LocalIP.ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (retVal != null)
|
||||
retVal.Dispose();
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new UDP socket that is a member of the specified multicast IP address, and binds it to the specified local port.
|
||||
/// </summary>
|
||||
/// <param name="ipAddress">The multicast IP address to make the socket a member of.</param>
|
||||
/// <param name="multicastTimeToLive">The multicast time to live value for the socket.</param>
|
||||
/// <param name="localPort">The number of the local port to bind to.</param>
|
||||
/// <returns></returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "ip"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "The purpose of this method is to create and returns a disposable result, it is up to the caller to dispose it when they are done with it.")]
|
||||
public IUdpSocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort)
|
||||
{
|
||||
if (ipAddress == null) throw new ArgumentNullException("ipAddress");
|
||||
if (ipAddress.Length == 0) throw new ArgumentException("ipAddress cannot be an empty string.", "ipAddress");
|
||||
if (multicastTimeToLive <= 0) throw new ArgumentException("multicastTimeToLive cannot be zero or less.", "multicastTimeToLive");
|
||||
if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
|
||||
|
||||
var retVal = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||
|
||||
try
|
||||
{
|
||||
#if NETSTANDARD1_3
|
||||
// The ExclusiveAddressUse socket option is a Windows-specific option that, when set to "true," tells Windows not to allow another socket to use the same local address as this socket
|
||||
// See https://github.com/dotnet/corefx/pull/11509 for more details
|
||||
if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
|
||||
{
|
||||
retVal.ExclusiveAddressUse = false;
|
||||
}
|
||||
#else
|
||||
retVal.ExclusiveAddressUse = false;
|
||||
#endif
|
||||
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
|
||||
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse(ipAddress), _LocalIP));
|
||||
retVal.MulticastLoopback = true;
|
||||
|
||||
return new UdpSocket(retVal, localPort, _LocalIP.ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (retVal != null)
|
||||
retVal.Dispose();
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
@ -157,10 +158,10 @@ namespace Rssdp.Infrastructure
|
||||
/// Sends a message to a particular address (uni or multicast) and port.
|
||||
/// </summary>
|
||||
/// <param name="messageData">A byte array containing the data to send.</param>
|
||||
/// <param name="destination">A <see cref="UdpEndPoint"/> representing the destination address for the data. Can be either a multicast or unicast destination.</param>
|
||||
/// <param name="destination">A <see cref="IpEndPointInfo"/> representing the destination address for the data. Can be either a multicast or unicast destination.</param>
|
||||
/// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="messageData"/> argument is null.</exception>
|
||||
/// <exception cref="System.ObjectDisposedException">Thrown if the <see cref="DisposableManagedObjectBase.IsDisposed"/> property is true (because <seealso cref="DisposableManagedObjectBase.Dispose()" /> has been called previously).</exception>
|
||||
public async Task SendMessage(byte[] messageData, UdpEndPoint destination)
|
||||
public async Task SendMessage(byte[] messageData, IpEndPointInfo destination)
|
||||
{
|
||||
if (messageData == null) throw new ArgumentNullException("messageData");
|
||||
|
||||
@ -188,7 +189,7 @@ namespace Rssdp.Infrastructure
|
||||
|
||||
// SSDP spec recommends sending messages multiple times (not more than 3) to account for possible packet loss over UDP.
|
||||
await Repeat(SsdpConstants.UdpResendCount, TimeSpan.FromMilliseconds(100),
|
||||
() => SendMessageIfSocketNotDisposed(messageData, new UdpEndPoint() { IPAddress = SsdpConstants.MulticastLocalAdminAddress, Port = SsdpConstants.MulticastPort })).ConfigureAwait(false);
|
||||
() => SendMessageIfSocketNotDisposed(messageData, new IpEndPointInfo() { IpAddress = new IpAddressInfo { Address = SsdpConstants.MulticastLocalAdminAddress }, Port = SsdpConstants.MulticastPort })).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -254,7 +255,7 @@ namespace Rssdp.Infrastructure
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private async Task SendMessageIfSocketNotDisposed(byte[] messageData, UdpEndPoint destination)
|
||||
private async Task SendMessageIfSocketNotDisposed(byte[] messageData, IpEndPointInfo destination)
|
||||
{
|
||||
var socket = _SendSocket;
|
||||
if (socket != null)
|
||||
@ -343,7 +344,7 @@ namespace Rssdp.Infrastructure
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessMessage(string data, UdpEndPoint endPoint)
|
||||
private void ProcessMessage(string data, IpEndPointInfo endPoint)
|
||||
{
|
||||
//Responses start with the HTTP version, prefixed with HTTP/ while
|
||||
//requests start with a method which can vary and might be one we haven't
|
||||
@ -375,7 +376,7 @@ namespace Rssdp.Infrastructure
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRequestReceived(HttpRequestMessage data, UdpEndPoint endPoint)
|
||||
private void OnRequestReceived(HttpRequestMessage data, IpEndPointInfo endPoint)
|
||||
{
|
||||
//SSDP specification says only * is currently used but other uri's might
|
||||
//be implemented in the future and should be ignored unless understood.
|
||||
@ -387,7 +388,7 @@ namespace Rssdp.Infrastructure
|
||||
handlers(this, new RequestReceivedEventArgs(data, endPoint));
|
||||
}
|
||||
|
||||
private void OnResponseReceived(HttpResponseMessage data, UdpEndPoint endPoint)
|
||||
private void OnResponseReceived(HttpResponseMessage data, IpEndPointInfo endPoint)
|
||||
{
|
||||
var handlers = this.ResponseReceived;
|
||||
if (handlers != null)
|
||||
|
@ -2,6 +2,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using Rssdp.Infrastructure;
|
||||
|
||||
namespace Rssdp
|
||||
@ -19,7 +21,7 @@ namespace Rssdp
|
||||
/// Default constructor. Constructs a new instance using the default <see cref="ISsdpCommunicationsServer"/> and <see cref="ISocketFactory"/> implementations for this platform.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification="Can't expose along exception paths here (exceptions should be very rare anyway, and probably fatal too) and we shouldn't dipose the items we pass to base in any other case.")]
|
||||
public SsdpDeviceLocator() : base(new SsdpCommunicationsServer(new SocketFactory(null)))
|
||||
public SsdpDeviceLocator(ISocketFactory socketFactory, ITimerFactory timerFacatory) : base(new SsdpCommunicationsServer(socketFactory), timerFacatory)
|
||||
{
|
||||
// This is not the problem you are looking for;
|
||||
// Yes, this is poor man's dependency injection which some call an anti-pattern.
|
||||
@ -30,14 +32,5 @@ namespace Rssdp
|
||||
// There is a constructor that takes a manually injected dependency anyway, so proper DI using
|
||||
// a container or whatever can be done anyway.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Full constructor. Constructs a new instance using the provided <see cref="ISsdpCommunicationsServer"/> implementation.
|
||||
/// </summary>
|
||||
public SsdpDeviceLocator(ISsdpCommunicationsServer communicationsServer)
|
||||
: base(communicationsServer)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Threading;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
@ -24,7 +25,8 @@ namespace Rssdp.Infrastructure
|
||||
private IList<DiscoveredSsdpDevice> _SearchResults;
|
||||
private object _SearchResultsSynchroniser;
|
||||
|
||||
private System.Threading.Timer _ExpireCachedDevicesTimer;
|
||||
private ITimer _ExpireCachedDevicesTimer;
|
||||
private ITimerFactory _timerFactory;
|
||||
|
||||
private const string HttpURequestMessageFormat = @"{0} * HTTP/1.1
|
||||
HOST: {1}:{2}
|
||||
@ -44,12 +46,12 @@ ST: {4}
|
||||
/// <summary>
|
||||
/// Default constructor.
|
||||
/// </summary>
|
||||
/// <param name="communicationsServer">The <see cref="ISsdpCommunicationsServer"/> implementation to use for network communications.</param>
|
||||
protected SsdpDeviceLocatorBase(ISsdpCommunicationsServer communicationsServer)
|
||||
protected SsdpDeviceLocatorBase(ISsdpCommunicationsServer communicationsServer, ITimerFactory timerFactory)
|
||||
{
|
||||
if (communicationsServer == null) throw new ArgumentNullException("communicationsServer");
|
||||
|
||||
_CommunicationsServer = communicationsServer;
|
||||
_timerFactory = timerFactory;
|
||||
_CommunicationsServer.ResponseReceived += CommsServer_ResponseReceived;
|
||||
|
||||
_SearchResultsSynchroniser = new object();
|
||||
@ -521,7 +523,7 @@ ST: {4}
|
||||
if (IsDisposed) return;
|
||||
|
||||
if (_ExpireCachedDevicesTimer == null)
|
||||
_ExpireCachedDevicesTimer = new Timer(this.ExpireCachedDevices, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
|
||||
_ExpireCachedDevicesTimer = _timerFactory.Create(this.ExpireCachedDevices, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
|
||||
|
||||
_ExpireCachedDevicesTimer.Change(60000, System.Threading.Timeout.Infinite);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using Rssdp.Infrastructure;
|
||||
|
||||
namespace Rssdp
|
||||
@ -24,79 +26,13 @@ namespace Rssdp
|
||||
/// <para>Uses the default <see cref="ISsdpCommunicationsServer"/> implementation and network settings for Windows and the SSDP specification.</para>
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "No way to do this here, and we don't want to dispose it except in the (rare) case of an exception anyway.")]
|
||||
public SsdpDevicePublisher()
|
||||
: this(new SsdpCommunicationsServer(new SocketFactory(null)))
|
||||
public SsdpDevicePublisher(ISocketFactory socketFactory, ITimerFactory timerFactory, string osName, string osVersion)
|
||||
: base(new SsdpCommunicationsServer(socketFactory), timerFactory, osName, osVersion)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Full constructor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Allows the caller to specify their own <see cref="ISsdpCommunicationsServer"/> implementation for full control over the networking, or for mocking/testing purposes..</para>
|
||||
/// </remarks>
|
||||
public SsdpDevicePublisher(ISsdpCommunicationsServer communicationsServer)
|
||||
: base(communicationsServer, GetOSName(), GetOSVersion())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partial constructor.
|
||||
/// </summary>
|
||||
/// <param name="localPort">The local port to use for socket communications, specify 0 to have the system choose it's own.</param>
|
||||
/// <remarks>
|
||||
/// <para>Uses the default <see cref="ISsdpCommunicationsServer"/> implementation and network settings for Windows and the SSDP specification, but specifies the local port to use for socket communications. Specify 0 to indicate the system should choose it's own port.</para>
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "No way to do this here, and we don't want to dispose it except in the (rare) case of an exception anyway.")]
|
||||
public SsdpDevicePublisher(int localPort)
|
||||
: this(new SsdpCommunicationsServer(new SocketFactory(null), localPort))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Partial constructor.
|
||||
/// </summary>
|
||||
/// <param name="localPort">The local port to use for socket communications, specify 0 to have the system choose it's own.</param>
|
||||
/// <param name="multicastTimeToLive">The number of hops a multicast packet can make before it expires. Must be 1 or greater.</param>
|
||||
/// <remarks>
|
||||
/// <para>Uses the default <see cref="ISsdpCommunicationsServer"/> implementation and network settings for Windows and the SSDP specification, but specifies the local port to use and multicast time to live setting for socket communications.</para>
|
||||
/// <para>Specify 0 for the <paramref name="localPort"/> argument to indicate the system should choose it's own port.</para>
|
||||
/// <para>The <paramref name="multicastTimeToLive"/> is actually a number of 'hops' on the network and not a time based argument.</para>
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "No way to do this here, and we don't want to dispose it except in the (rare) case of an exception anyway.")]
|
||||
public SsdpDevicePublisher(int localPort, int multicastTimeToLive)
|
||||
: this(new SsdpCommunicationsServer(new SocketFactory(null), localPort, multicastTimeToLive))
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private static string GetOSName()
|
||||
{
|
||||
#if NET46
|
||||
return Environment.OSVersion.Platform.ToString();
|
||||
#elif NETSTANDARD1_6
|
||||
return System.Runtime.InteropServices.RuntimeInformation.OSDescription;
|
||||
#endif
|
||||
return "Operating System";
|
||||
}
|
||||
|
||||
private static string GetOSVersion()
|
||||
{
|
||||
#if NET46
|
||||
return Environment.OSVersion.Version.ToString() + " " + Environment.OSVersion.ServicePack.ToString();
|
||||
#elif NETSTANDARD1_6
|
||||
return System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription;
|
||||
#endif
|
||||
return "1.0";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
@ -24,7 +26,8 @@ namespace Rssdp.Infrastructure
|
||||
private IList<SsdpRootDevice> _Devices;
|
||||
private ReadOnlyEnumerable<SsdpRootDevice> _ReadOnlyDevices;
|
||||
|
||||
private System.Threading.Timer _RebroadcastAliveNotificationsTimer;
|
||||
private ITimer _RebroadcastAliveNotificationsTimer;
|
||||
private ITimerFactory _timerFactory;
|
||||
//private TimeSpan _RebroadcastAliveNotificationsTimeSpan;
|
||||
private DateTime _LastNotificationTime;
|
||||
|
||||
@ -47,10 +50,7 @@ namespace Rssdp.Infrastructure
|
||||
/// <summary>
|
||||
/// Default constructor.
|
||||
/// </summary>
|
||||
/// <param name="communicationsServer">The <see cref="ISsdpCommunicationsServer"/> implementation, used to send and receive SSDP network messages.</param>
|
||||
/// <param name="osName">Then name of the operating system running the server.</param>
|
||||
/// <param name="osVersion">The version of the operating system running the server.</param>
|
||||
protected SsdpDevicePublisherBase(ISsdpCommunicationsServer communicationsServer, string osName, string osVersion)
|
||||
protected SsdpDevicePublisherBase(ISsdpCommunicationsServer communicationsServer, ITimerFactory timerFactory, string osName, string osVersion)
|
||||
{
|
||||
if (communicationsServer == null) throw new ArgumentNullException("communicationsServer");
|
||||
if (osName == null) throw new ArgumentNullException("osName");
|
||||
@ -59,6 +59,7 @@ namespace Rssdp.Infrastructure
|
||||
if (osVersion.Length == 0) throw new ArgumentException("osVersion cannot be an empty string.", "osName");
|
||||
|
||||
_SupportPnpRootDevice = true;
|
||||
_timerFactory = timerFactory;
|
||||
_Devices = new List<SsdpRootDevice>();
|
||||
_ReadOnlyDevices = new ReadOnlyEnumerable<SsdpRootDevice>(_Devices);
|
||||
_RecentSearchRequests = new Dictionary<string, SearchRequest>(StringComparer.OrdinalIgnoreCase);
|
||||
@ -234,7 +235,7 @@ namespace Rssdp.Infrastructure
|
||||
|
||||
#region Search Related Methods
|
||||
|
||||
private void ProcessSearchRequest(string mx, string searchTarget, UdpEndPoint endPoint)
|
||||
private void ProcessSearchRequest(string mx, string searchTarget, IpEndPointInfo endPoint)
|
||||
{
|
||||
if (String.IsNullOrEmpty(searchTarget))
|
||||
{
|
||||
@ -305,7 +306,7 @@ namespace Rssdp.Infrastructure
|
||||
return _Devices.Union(_Devices.SelectManyRecursive<SsdpDevice>((d) => d.Devices));
|
||||
}
|
||||
|
||||
private void SendDeviceSearchResponses(SsdpDevice device, UdpEndPoint endPoint)
|
||||
private void SendDeviceSearchResponses(SsdpDevice device, IpEndPointInfo endPoint)
|
||||
{
|
||||
bool isRootDevice = (device as SsdpRootDevice) != null;
|
||||
if (isRootDevice)
|
||||
@ -325,7 +326,7 @@ namespace Rssdp.Infrastructure
|
||||
return String.Format("{0}::{1}", udn, fullDeviceType);
|
||||
}
|
||||
|
||||
private async void SendSearchResponse(string searchTarget, SsdpDevice device, string uniqueServiceName, UdpEndPoint endPoint)
|
||||
private async void SendSearchResponse(string searchTarget, SsdpDevice device, string uniqueServiceName, IpEndPointInfo endPoint)
|
||||
{
|
||||
var rootDevice = device.ToRootDevice();
|
||||
|
||||
@ -357,7 +358,7 @@ namespace Rssdp.Infrastructure
|
||||
WriteTrace(String.Format("Sent search response to " + endPoint.ToString()), device);
|
||||
}
|
||||
|
||||
private bool IsDuplicateSearchRequest(string searchTarget, UdpEndPoint endPoint)
|
||||
private bool IsDuplicateSearchRequest(string searchTarget, IpEndPointInfo endPoint)
|
||||
{
|
||||
var isDuplicateRequest = false;
|
||||
|
||||
@ -590,7 +591,7 @@ namespace Rssdp.Infrastructure
|
||||
}
|
||||
|
||||
//_RebroadcastAliveNotificationsTimeSpan = rebroadCastInterval;
|
||||
_RebroadcastAliveNotificationsTimer = new System.Threading.Timer(SendAllAliveNotifications, null, nextBroadcastInterval, rebroadCastInterval);
|
||||
_RebroadcastAliveNotificationsTimer = _timerFactory.Create(SendAllAliveNotifications, null, nextBroadcastInterval, rebroadCastInterval);
|
||||
|
||||
WriteTrace(String.Format("Rebroadcast Interval = {0}, Next Broadcast At = {1}", rebroadCastInterval.ToString(), nextBroadcastInterval.ToString()));
|
||||
}
|
||||
@ -704,7 +705,7 @@ namespace Rssdp.Infrastructure
|
||||
|
||||
private class SearchRequest
|
||||
{
|
||||
public UdpEndPoint EndPoint { get; set; }
|
||||
public IpEndPointInfo EndPoint { get; set; }
|
||||
public DateTime Received { get; set; }
|
||||
public string SearchTarget { get; set; }
|
||||
|
||||
|
@ -1,37 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// Cross platform representation of a UDP end point, being an IP address (either IPv4 or IPv6) and a port.
|
||||
/// </summary>
|
||||
public sealed class UdpEndPoint
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The IP Address of the end point.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Can be either IPv4 or IPv6, up to the code using this instance to determine which was provided.</para>
|
||||
/// </remarks>
|
||||
public string IPAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The port of the end point.
|
||||
/// </summary>
|
||||
public int Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="IPAddress"/> and <see cref="Port"/> values separated by a colon.
|
||||
/// </summary>
|
||||
/// <returns>A string containing <see cref="IPAddress"/>:<see cref="Port"/>.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return (this.IPAddress ?? String.Empty) + ":" + this.Port.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
{
|
||||
"version": "1.0.0-*",
|
||||
|
||||
"dependencies": {
|
||||
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"net46": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Collections": "4.0.0.0",
|
||||
"System.Net": "4.0.0.0",
|
||||
"System.Net.Http": "4.0.0.0",
|
||||
"System.Runtime": "4.0.0.0",
|
||||
"System.Threading": "4.0.0.0",
|
||||
"System.Threading.Tasks": "4.0.0.0",
|
||||
"System.Xml": "4.0.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
}
|
||||
},
|
||||
"netstandard1.6": {
|
||||
"imports": "dnxcore50",
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.0",
|
||||
"System.Collections": "4.0.11",
|
||||
"System.Diagnostics.Debug": "4.0.11",
|
||||
"System.Diagnostics.Tools": "4.0.1",
|
||||
"System.IO": "4.1.0",
|
||||
"System.Linq": "4.1.0",
|
||||
"System.Net.Http": "4.1.0",
|
||||
"System.Net.Primitives": "4.0.11",
|
||||
"System.Net.Sockets": "4.1.0",
|
||||
"System.Resources.ResourceManager": "4.0.1",
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Runtime.Extensions": "4.1.0",
|
||||
"System.Runtime.InteropServices.RuntimeInformation": "4.0.0",
|
||||
"System.Text.Encoding": "4.0.11",
|
||||
"System.Text.Encoding.Extensions": "4.0.11",
|
||||
"System.Threading": "4.0.11",
|
||||
"System.Threading.Tasks": "4.0.11",
|
||||
"System.Threading.Timer": "4.0.1",
|
||||
"System.Xml.ReaderWriter": "4.0.11"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user