commit
09e01d9aad
|
@ -127,10 +127,14 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
args.EndPoint = endPoint;
|
args.EndPoint = endPoint;
|
||||||
args.LocalEndPoint = new IPEndPoint(localIp, 0);
|
args.LocalEndPoint = new IPEndPoint(localIp, 0);
|
||||||
|
|
||||||
if (!_ssdpHandler.IsSelfNotification(args))
|
if (_ssdpHandler.IgnoreMessage(args, true))
|
||||||
{
|
{
|
||||||
TryCreateDevice(args);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ssdpHandler.LogMessageReceived(args, true);
|
||||||
|
|
||||||
|
TryCreateDevice(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,14 +221,6 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLog)
|
|
||||||
{
|
|
||||||
var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
|
||||||
var headerText = string.Join(",", headerTexts.ToArray());
|
|
||||||
|
|
||||||
_logger.Debug("{0} Device message received from {1}. Headers: {2}", args.Method, args.EndPoint, headerText);
|
|
||||||
}
|
|
||||||
|
|
||||||
EventHelper.FireEventIfNotNull(DeviceDiscovered, this, args, _logger);
|
EventHelper.FireEventIfNotNull(DeviceDiscovered, this, args, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
public event EventHandler<SsdpMessageEventArgs> MessageReceived;
|
public event EventHandler<SsdpMessageEventArgs> MessageReceived;
|
||||||
|
|
||||||
private async void OnMessageReceived(SsdpMessageEventArgs args)
|
private async void OnMessageReceived(SsdpMessageEventArgs args, bool isMulticast)
|
||||||
{
|
{
|
||||||
|
if (IgnoreMessage(args, isMulticast))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogMessageReceived(args, isMulticast);
|
||||||
|
|
||||||
var headers = args.Headers;
|
var headers = args.Headers;
|
||||||
string st;
|
string st;
|
||||||
|
|
||||||
|
@ -108,6 +115,59 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
|
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void LogMessageReceived(SsdpMessageEventArgs args, bool isMulticast)
|
||||||
|
{
|
||||||
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog;
|
||||||
|
|
||||||
|
if (enableDebugLogging)
|
||||||
|
{
|
||||||
|
var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
||||||
|
var headerText = string.Join(",", headerTexts.ToArray());
|
||||||
|
|
||||||
|
var protocol = isMulticast ? "Multicast" : "Unicast";
|
||||||
|
var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString();
|
||||||
|
_logger.Debug("{0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool IgnoreMessage(SsdpMessageEventArgs args, bool isMulticast)
|
||||||
|
{
|
||||||
|
string usn;
|
||||||
|
if (args.Headers.TryGetValue("USN", out usn))
|
||||||
|
{
|
||||||
|
// USN=uuid:b67df29b5c379445fde78c3774ab518d::urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1
|
||||||
|
if (RegisteredDevices.Select(i => i.USN).Contains(usn, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
//var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
||||||
|
//var headerText = string.Join(",", headerTexts.ToArray());
|
||||||
|
|
||||||
|
//var protocol = isMulticast ? "Multicast" : "Unicast";
|
||||||
|
//var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString();
|
||||||
|
//_logger.Debug("IGNORING {0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string serverId;
|
||||||
|
if (args.Headers.TryGetValue("X-EMBY-SERVERID", out serverId))
|
||||||
|
{
|
||||||
|
if (string.Equals(serverId, _appHost.SystemId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
//var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
||||||
|
//var headerText = string.Join(",", headerTexts.ToArray());
|
||||||
|
|
||||||
|
//var protocol = isMulticast ? "Multicast" : "Unicast";
|
||||||
|
//var localEndPointString = args.LocalEndPoint == null ? "null" : args.LocalEndPoint.ToString();
|
||||||
|
//_logger.Debug("IGNORING {0} message received from {1} on {3}. Protocol: {4} Headers: {2}", args.Method, args.EndPoint, headerText, localEndPointString, protocol);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<UpnpDevice> RegisteredDevices
|
public IEnumerable<UpnpDevice> RegisteredDevices
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -126,7 +186,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
RestartSocketListener();
|
RestartSocketListener();
|
||||||
ReloadAliveNotifier();
|
ReloadAliveNotifier();
|
||||||
|
|
||||||
//CreateUnicastClient();
|
CreateUnicastClient();
|
||||||
|
|
||||||
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
|
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
|
||||||
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
|
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
|
||||||
|
@ -146,6 +206,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
values["HOST"] = "239.255.255.250:1900";
|
values["HOST"] = "239.255.255.250:1900";
|
||||||
values["USER-AGENT"] = "UPnP/1.0 DLNADOC/1.50 Platinum/1.0.4.2";
|
values["USER-AGENT"] = "UPnP/1.0 DLNADOC/1.50 Platinum/1.0.4.2";
|
||||||
|
values["X-EMBY-SERVERID"] = _appHost.SystemId;
|
||||||
|
|
||||||
values["MAN"] = "\"ssdp:discover\"";
|
values["MAN"] = "\"ssdp:discover\"";
|
||||||
|
|
||||||
|
@ -162,7 +223,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
// UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
|
// UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
|
||||||
SendDatagram(msg, _ssdpEndp, localIp, true);
|
SendDatagram(msg, _ssdpEndp, localIp, true);
|
||||||
|
|
||||||
//SendUnicastRequest(msg);
|
SendUnicastRequest(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void SendDatagram(string msg,
|
public async void SendDatagram(string msg,
|
||||||
|
@ -242,9 +303,17 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
||||||
|
|
||||||
SendDatagram(msg, endpoint, null, false, 1);
|
var ipEndPoint = endpoint as IPEndPoint;
|
||||||
SendDatagram(msg, endpoint, new IPEndPoint(d.Address, 0), false, 1);
|
if (ipEndPoint != null)
|
||||||
|
{
|
||||||
|
SendUnicastRequest(msg, ipEndPoint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SendDatagram(msg, endpoint, null, false, 2);
|
||||||
|
SendDatagram(msg, endpoint, new IPEndPoint(d.Address, 0), false, 2);
|
||||||
//SendDatagram(header, values, endpoint, null, true);
|
//SendDatagram(header, values, endpoint, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (enableDebugLogging)
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
|
@ -324,20 +393,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
var args = SsdpHelper.ParseSsdpResponse(received);
|
var args = SsdpHelper.ParseSsdpResponse(received);
|
||||||
args.EndPoint = endpoint;
|
args.EndPoint = endpoint;
|
||||||
|
|
||||||
if (IsSelfNotification(args))
|
OnMessageReceived(args, true);
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enableDebugLogging)
|
|
||||||
{
|
|
||||||
var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
|
||||||
var headerText = string.Join(",", headerTexts.ToArray());
|
|
||||||
|
|
||||||
_logger.Debug("{0} message received from {1} on {3}. Headers: {2}", args.Method, args.EndPoint, headerText, _multicastSocket.LocalEndPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnMessageReceived(args);
|
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException)
|
catch (ObjectDisposedException)
|
||||||
{
|
{
|
||||||
|
@ -357,26 +413,6 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool IsSelfNotification(SsdpMessageEventArgs args)
|
|
||||||
{
|
|
||||||
// Avoid responding to self search messages
|
|
||||||
//string serverId;
|
|
||||||
//if (args.Headers.TryGetValue("X-EMBYSERVERID", out serverId) &&
|
|
||||||
// string.Equals(serverId, _appHost.SystemId, StringComparison.OrdinalIgnoreCase))
|
|
||||||
//{
|
|
||||||
// return true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
string server;
|
|
||||||
args.Headers.TryGetValue("SERVER", out server);
|
|
||||||
|
|
||||||
if (string.Equals(server, _serverSignature, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
//return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
|
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
|
||||||
|
@ -440,6 +476,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
values["NTS"] = "ssdp:" + type;
|
values["NTS"] = "ssdp:" + type;
|
||||||
values["NT"] = dev.Type;
|
values["NT"] = dev.Type;
|
||||||
values["USN"] = dev.USN;
|
values["USN"] = dev.USN;
|
||||||
|
values["X-EMBY-SERVERID"] = _appHost.SystemId;
|
||||||
|
|
||||||
if (logMessage)
|
if (logMessage)
|
||||||
{
|
{
|
||||||
|
@ -449,6 +486,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
||||||
|
|
||||||
SendDatagram(msg, _ssdpEndp, new IPEndPoint(dev.Address, 0), true);
|
SendDatagram(msg, _ssdpEndp, new IPEndPoint(dev.Address, 0), true);
|
||||||
|
//SendUnicastRequest(msg, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterNotification(string uuid, Uri descriptionUri, IPAddress address, IEnumerable<string> services)
|
public void RegisterNotification(string uuid, Uri descriptionUri, IPAddress address, IEnumerable<string> services)
|
||||||
|
@ -489,15 +527,8 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
_logger.ErrorException("Error creating unicast client", ex);
|
_logger.ErrorException("Error creating unicast client", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
UnicastSetBeginReceive();
|
UnicastSetBeginReceive();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error in UnicastSetBeginReceive", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeUnicastClient()
|
private void DisposeUnicastClient()
|
||||||
|
@ -521,6 +552,8 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
/// Listen for Unicast SSDP Responses
|
/// Listen for Unicast SSDP Responses
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UnicastSetBeginReceive()
|
private void UnicastSetBeginReceive()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var ipRxEnd = new IPEndPoint(IPAddress.Any, _unicastPort);
|
var ipRxEnd = new IPEndPoint(IPAddress.Any, _unicastPort);
|
||||||
var udpListener = new UdpState { EndPoint = ipRxEnd };
|
var udpListener = new UdpState { EndPoint = ipRxEnd };
|
||||||
|
@ -528,6 +561,11 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
udpListener.UdpClient = _unicastClient;
|
udpListener.UdpClient = _unicastClient;
|
||||||
_unicastClient.BeginReceive(UnicastReceiveCallback, udpListener);
|
_unicastClient.BeginReceive(UnicastReceiveCallback, udpListener);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error in UnicastSetBeginReceive", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The UnicastReceiveCallback receives Http Responses
|
/// The UnicastReceiveCallback receives Http Responses
|
||||||
|
@ -539,19 +577,41 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
var udpClient = ((UdpState)(ar.AsyncState)).UdpClient;
|
var udpClient = ((UdpState)(ar.AsyncState)).UdpClient;
|
||||||
var endpoint = ((UdpState)(ar.AsyncState)).EndPoint;
|
var endpoint = ((UdpState)(ar.AsyncState)).EndPoint;
|
||||||
if (udpClient.Client != null)
|
if (udpClient.Client != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var responseBytes = udpClient.EndReceive(ar, ref endpoint);
|
var responseBytes = udpClient.EndReceive(ar, ref endpoint);
|
||||||
var args = SsdpHelper.ParseSsdpResponse(responseBytes);
|
var args = SsdpHelper.ParseSsdpResponse(responseBytes);
|
||||||
|
|
||||||
args.EndPoint = endpoint;
|
args.EndPoint = endpoint;
|
||||||
|
|
||||||
OnMessageReceived(args);
|
OnMessageReceived(args, false);
|
||||||
|
|
||||||
UnicastSetBeginReceive();
|
UnicastSetBeginReceive();
|
||||||
}
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SendUnicastRequest(string request)
|
private void SendUnicastRequest(string request, int sendCount = 3)
|
||||||
|
{
|
||||||
|
if (_unicastClient == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Sending unicast search request");
|
||||||
|
|
||||||
|
var ipSsdp = IPAddress.Parse(SSDPAddr);
|
||||||
|
var ipTxEnd = new IPEndPoint(ipSsdp, SSDPPort);
|
||||||
|
|
||||||
|
SendUnicastRequest(request, ipTxEnd, sendCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void SendUnicastRequest(string request, IPEndPoint toEndPoint, int sendCount = 3)
|
||||||
{
|
{
|
||||||
if (_unicastClient == null)
|
if (_unicastClient == null)
|
||||||
{
|
{
|
||||||
|
@ -561,16 +621,21 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
_logger.Debug("Sending unicast search request");
|
_logger.Debug("Sending unicast search request");
|
||||||
|
|
||||||
byte[] req = Encoding.ASCII.GetBytes(request);
|
byte[] req = Encoding.ASCII.GetBytes(request);
|
||||||
var ipSsdp = IPAddress.Parse(SSDPAddr);
|
|
||||||
var ipTxEnd = new IPEndPoint(ipSsdp, SSDPPort);
|
|
||||||
|
|
||||||
for (var i = 0; i < 3; i++)
|
try
|
||||||
|
{
|
||||||
|
for (var i = 0; i < sendCount; i++)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
await Task.Delay(50).ConfigureAwait(false);
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
_unicastClient.Send(req, req.Length, ipTxEnd);
|
_unicastClient.Send(req, req.Length, toEndPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error in SendUnicastRequest", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public Task<Model.MediaInfo.MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken)
|
public Task<MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
|
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task{MediaInfoResult}.</returns>
|
/// <returns>Task{MediaInfoResult}.</returns>
|
||||||
/// <exception cref="System.ApplicationException">ffprobe failed - streams and format are both null.</exception>
|
/// <exception cref="System.ApplicationException">ffprobe failed - streams and format are both null.</exception>
|
||||||
private async Task<Model.MediaInfo.MediaInfo> GetMediaInfoInternal(string inputPath,
|
private async Task<MediaInfo> GetMediaInfoInternal(string inputPath,
|
||||||
string primaryPath,
|
string primaryPath,
|
||||||
MediaProtocol protocol,
|
MediaProtocol protocol,
|
||||||
bool extractChapters,
|
bool extractChapters,
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
|
|
||||||
public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol)
|
public MediaInfo GetMediaInfo(InternalMediaInfoResult data, VideoType videoType, bool isAudio, string path, MediaProtocol protocol)
|
||||||
{
|
{
|
||||||
var info = new Model.MediaInfo.MediaInfo
|
var info = new MediaInfo
|
||||||
{
|
{
|
||||||
Path = path,
|
Path = path,
|
||||||
Protocol = protocol
|
Protocol = protocol
|
||||||
|
@ -56,22 +56,16 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAudio)
|
|
||||||
{
|
|
||||||
SetAudioRuntimeTicks(data, info);
|
|
||||||
|
|
||||||
var tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
var tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
var tagStreamType = isAudio ? "audio" : "video";
|
||||||
// tags are normally located under data.format, but we've seen some cases with ogg where they're part of the audio stream
|
|
||||||
// so let's create a combined list of both
|
|
||||||
|
|
||||||
if (data.streams != null)
|
if (data.streams != null)
|
||||||
{
|
{
|
||||||
var audioStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, "audio", StringComparison.OrdinalIgnoreCase));
|
var tagStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, tagStreamType, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
if (audioStream != null && audioStream.tags != null)
|
if (tagStream != null && tagStream.tags != null)
|
||||||
{
|
{
|
||||||
foreach (var pair in audioStream.tags)
|
foreach (var pair in tagStream.tags)
|
||||||
{
|
{
|
||||||
tags[pair.Key] = pair.Value;
|
tags[pair.Key] = pair.Value;
|
||||||
}
|
}
|
||||||
|
@ -86,10 +80,57 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FetchGenres(info, tags);
|
||||||
|
var overview = FFProbeHelpers.GetDictionaryValue(tags, "description");
|
||||||
|
if (!string.IsNullOrWhiteSpace(overview))
|
||||||
|
{
|
||||||
|
info.Overview = overview;
|
||||||
|
}
|
||||||
|
|
||||||
|
var title = FFProbeHelpers.GetDictionaryValue(tags, "title");
|
||||||
|
if (!string.IsNullOrWhiteSpace(title))
|
||||||
|
{
|
||||||
|
info.Name = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");
|
||||||
|
|
||||||
|
// Several different forms of retaildate
|
||||||
|
info.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ??
|
||||||
|
FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ??
|
||||||
|
FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ??
|
||||||
|
FFProbeHelpers.GetDictionaryDateTime(tags, "date");
|
||||||
|
|
||||||
|
if (isAudio)
|
||||||
|
{
|
||||||
|
SetAudioRuntimeTicks(data, info);
|
||||||
|
|
||||||
|
// tags are normally located under data.format, but we've seen some cases with ogg where they're part of the audio stream
|
||||||
|
// so let's create a combined list of both
|
||||||
|
|
||||||
SetAudioInfoFromTags(info, tags);
|
SetAudioInfoFromTags(info, tags);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var iTunEXTC = FFProbeHelpers.GetDictionaryValue(tags, "iTunEXTC");
|
||||||
|
if (!string.IsNullOrWhiteSpace(iTunEXTC))
|
||||||
|
{
|
||||||
|
var parts = iTunEXTC.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
// Example
|
||||||
|
// mpaa|G|100|For crude humor
|
||||||
|
if (parts.Length == 4)
|
||||||
|
{
|
||||||
|
info.OfficialRating = parts[1];
|
||||||
|
info.OfficialRatingDescription = parts[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var itunesXml = FFProbeHelpers.GetDictionaryValue(tags, "iTunMOVI");
|
||||||
|
if (!string.IsNullOrWhiteSpace(itunesXml))
|
||||||
|
{
|
||||||
|
FetchFromItunesInfo(itunesXml, info);
|
||||||
|
}
|
||||||
|
|
||||||
if (data.format != null && !string.IsNullOrEmpty(data.format.duration))
|
if (data.format != null && !string.IsNullOrEmpty(data.format.duration))
|
||||||
{
|
{
|
||||||
info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks;
|
info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks;
|
||||||
|
@ -108,6 +149,11 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FetchFromItunesInfo(string xml, MediaInfo info)
|
||||||
|
{
|
||||||
|
// <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>cast</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Blender Foundation</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Janus Bager Kristensen</string>\n\t\t</dict>\n\t</array>\n\t<key>directors</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Sacha Goedegebure</string>\n\t\t</dict>\n\t</array>\n\t<key>studio</key>\n\t<string>Blender Foundation</string>\n</dict>\n</plist>\n
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts ffprobe stream info to our MediaStream class
|
/// Converts ffprobe stream info to our MediaStream class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -430,16 +476,8 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAudioInfoFromTags(Model.MediaInfo.MediaInfo audio, Dictionary<string, string> tags)
|
private void SetAudioInfoFromTags(MediaInfo audio, Dictionary<string, string> tags)
|
||||||
{
|
{
|
||||||
var title = FFProbeHelpers.GetDictionaryValue(tags, "title");
|
|
||||||
|
|
||||||
// Only set Name if title was found in the dictionary
|
|
||||||
if (!string.IsNullOrEmpty(title))
|
|
||||||
{
|
|
||||||
audio.Title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
var composer = FFProbeHelpers.GetDictionaryValue(tags, "composer");
|
var composer = FFProbeHelpers.GetDictionaryValue(tags, "composer");
|
||||||
if (!string.IsNullOrWhiteSpace(composer))
|
if (!string.IsNullOrWhiteSpace(composer))
|
||||||
{
|
{
|
||||||
|
@ -511,22 +549,12 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
// Disc number
|
// Disc number
|
||||||
audio.ParentIndexNumber = GetDictionaryDiscValue(tags, "disc");
|
audio.ParentIndexNumber = GetDictionaryDiscValue(tags, "disc");
|
||||||
|
|
||||||
audio.ProductionYear = FFProbeHelpers.GetDictionaryNumericValue(tags, "date");
|
|
||||||
|
|
||||||
// Several different forms of retaildate
|
|
||||||
audio.PremiereDate = FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ??
|
|
||||||
FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ??
|
|
||||||
FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ??
|
|
||||||
FFProbeHelpers.GetDictionaryDateTime(tags, "date");
|
|
||||||
|
|
||||||
// If we don't have a ProductionYear try and get it from PremiereDate
|
// If we don't have a ProductionYear try and get it from PremiereDate
|
||||||
if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue)
|
if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue)
|
||||||
{
|
{
|
||||||
audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year;
|
audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year;
|
||||||
}
|
}
|
||||||
|
|
||||||
FetchGenres(audio, tags);
|
|
||||||
|
|
||||||
// There's several values in tags may or may not be present
|
// There's several values in tags may or may not be present
|
||||||
FetchStudios(audio, tags, "organization");
|
FetchStudios(audio, tags, "organization");
|
||||||
FetchStudios(audio, tags, "ensemble");
|
FetchStudios(audio, tags, "ensemble");
|
||||||
|
@ -693,7 +721,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="info">The information.</param>
|
/// <param name="info">The information.</param>
|
||||||
/// <param name="tags">The tags.</param>
|
/// <param name="tags">The tags.</param>
|
||||||
private void FetchGenres(Model.MediaInfo.MediaInfo info, Dictionary<string, string> tags)
|
private void FetchGenres(MediaInfo info, Dictionary<string, string> tags)
|
||||||
{
|
{
|
||||||
var val = FFProbeHelpers.GetDictionaryValue(tags, "genre");
|
var val = FFProbeHelpers.GetDictionaryValue(tags, "genre");
|
||||||
|
|
||||||
|
@ -764,7 +792,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
|
|
||||||
private const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
|
private const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
|
||||||
|
|
||||||
private void FetchWtvInfo(Model.MediaInfo.MediaInfo video, InternalMediaInfoResult data)
|
private void FetchWtvInfo(MediaInfo video, InternalMediaInfoResult data)
|
||||||
{
|
{
|
||||||
if (data.format == null || data.format.tags == null)
|
if (data.format == null || data.format.tags == null)
|
||||||
{
|
{
|
||||||
|
@ -775,15 +803,16 @@ namespace MediaBrowser.MediaEncoding.Probing
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(genres))
|
if (!string.IsNullOrWhiteSpace(genres))
|
||||||
{
|
{
|
||||||
//genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "genre");
|
var genreList = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(genres))
|
|
||||||
{
|
|
||||||
video.Genres = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||||
.Select(i => i.Trim())
|
.Select(i => i.Trim())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
// If this is empty then don't overwrite genres that might have been fetched earlier
|
||||||
|
if (genreList.Count > 0)
|
||||||
|
{
|
||||||
|
video.Genres = genreList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");
|
var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");
|
||||||
|
|
|
@ -47,5 +47,6 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
public string ListingsId { get; set; }
|
public string ListingsId { get; set; }
|
||||||
public string ZipCode { get; set; }
|
public string ZipCode { get; set; }
|
||||||
public string Country { get; set; }
|
public string Country { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,11 +9,6 @@ namespace MediaBrowser.Model.MediaInfo
|
||||||
{
|
{
|
||||||
public List<ChapterInfo> Chapters { get; set; }
|
public List<ChapterInfo> Chapters { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the title.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The title.</value>
|
|
||||||
public string Title { get; set; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the album.
|
/// Gets or sets the album.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -47,6 +42,11 @@ namespace MediaBrowser.Model.MediaInfo
|
||||||
/// <value>The official rating.</value>
|
/// <value>The official rating.</value>
|
||||||
public string OfficialRating { get; set; }
|
public string OfficialRating { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Gets or sets the official rating description.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The official rating description.</value>
|
||||||
|
public string OfficialRatingDescription { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// Gets or sets the overview.
|
/// Gets or sets the overview.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The overview.</value>
|
/// <value>The overview.</value>
|
||||||
|
|
|
@ -125,9 +125,9 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
private async Task FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data)
|
private async Task FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data)
|
||||||
{
|
{
|
||||||
// Only set Name if title was found in the dictionary
|
// Only set Name if title was found in the dictionary
|
||||||
if (!string.IsNullOrEmpty(data.Title))
|
if (!string.IsNullOrEmpty(data.Name))
|
||||||
{
|
{
|
||||||
audio.Name = data.Title;
|
audio.Name = data.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!audio.LockedFields.Contains(MetadataFields.Cast))
|
if (!audio.LockedFields.Contains(MetadataFields.Cast))
|
||||||
|
|
|
@ -383,6 +383,11 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(data.OfficialRatingDescription) || isFullRefresh)
|
||||||
|
{
|
||||||
|
video.OfficialRatingDescription = data.OfficialRatingDescription;
|
||||||
|
}
|
||||||
|
|
||||||
if (!video.LockedFields.Contains(MetadataFields.Genres))
|
if (!video.LockedFields.Contains(MetadataFields.Genres))
|
||||||
{
|
{
|
||||||
if (video.Genres.Count == 0 || isFullRefresh)
|
if (video.Genres.Count == 0 || isFullRefresh)
|
||||||
|
@ -437,6 +442,13 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
video.ParentIndexNumber = data.ParentIndexNumber;
|
video.ParentIndexNumber = data.ParentIndexNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(data.Name))
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(video.Name) || string.Equals(video.Name, Path.GetFileNameWithoutExtension(video.Path), StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
video.Name = data.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we don't have a ProductionYear try and get it from PremiereDate
|
// If we don't have a ProductionYear try and get it from PremiereDate
|
||||||
if (video.PremiereDate.HasValue && !video.ProductionYear.HasValue)
|
if (video.PremiereDate.HasValue && !video.ProductionYear.HasValue)
|
||||||
|
|
|
@ -42,7 +42,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
|
||||||
void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
|
void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
|
||||||
{
|
{
|
||||||
string st = null;
|
string st = null;
|
||||||
if (e.Headers.TryGetValue("ST", out st) && string.Equals(st, "urn:ses-com:device:SatIPServer:1", StringComparison.OrdinalIgnoreCase))
|
string nt = null;
|
||||||
|
e.Headers.TryGetValue("ST", out st);
|
||||||
|
e.Headers.TryGetValue("NT", out nt);
|
||||||
|
|
||||||
|
if (string.Equals(st, "urn:ses-com:device:SatIPServer:1", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(nt, "urn:ses-com:device:SatIPServer:1", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
string location;
|
string location;
|
||||||
if (e.Headers.TryGetValue("Location", out location) && !string.IsNullOrWhiteSpace(location))
|
if (e.Headers.TryGetValue("Location", out location) && !string.IsNullOrWhiteSpace(location))
|
||||||
|
|
|
@ -52,9 +52,9 @@
|
||||||
<Reference Include="Interfaces.IO">
|
<Reference Include="Interfaces.IO">
|
||||||
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
|
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="MediaBrowser.Naming, Version=1.0.5884.23751, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="MediaBrowser.Naming, Version=1.0.5891.29179, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.47\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
|
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.48\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="MoreLinq">
|
<Reference Include="MoreLinq">
|
||||||
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
|
<HintPath>..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll</HintPath>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<package id="CommonIO" version="1.0.0.7" targetFramework="net45" />
|
<package id="CommonIO" version="1.0.0.7" targetFramework="net45" />
|
||||||
<package id="Emby.XmlTv" version="1.0.0.48" targetFramework="net45" />
|
<package id="Emby.XmlTv" version="1.0.0.48" targetFramework="net45" />
|
||||||
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
|
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
|
||||||
<package id="MediaBrowser.Naming" version="1.0.0.47" targetFramework="net45" />
|
<package id="MediaBrowser.Naming" version="1.0.0.48" targetFramework="net45" />
|
||||||
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
|
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
|
||||||
<package id="morelinq" version="1.4.0" targetFramework="net45" />
|
<package id="morelinq" version="1.4.0" targetFramework="net45" />
|
||||||
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
||||||
|
|
|
@ -140,6 +140,9 @@
|
||||||
<Content Include="dashboard-ui\components\remotecontrolautoplay.js">
|
<Content Include="dashboard-ui\components\remotecontrolautoplay.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\devices\windowsphone\wp.css">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\legacy\buttonenabled.js">
|
<Content Include="dashboard-ui\legacy\buttonenabled.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -254,9 +257,6 @@
|
||||||
<Content Include="dashboard-ui\favorites.html">
|
<Content Include="dashboard-ui\favorites.html">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<None Include="dashboard-ui\legacy\deferred.js">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<Content Include="dashboard-ui\livetvguideprovider.html">
|
<Content Include="dashboard-ui\livetvguideprovider.html">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user