commit
862018b5c2
|
@ -13,7 +13,9 @@ namespace Emby.Common.Implementations.Net
|
||||||
public Socket Socket { get; private set; }
|
public Socket Socket { get; private set; }
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public NetSocket(Socket socket, ILogger logger)
|
public bool DualMode { get; private set; }
|
||||||
|
|
||||||
|
public NetSocket(Socket socket, ILogger logger, bool isDualMode)
|
||||||
{
|
{
|
||||||
if (socket == null)
|
if (socket == null)
|
||||||
{
|
{
|
||||||
|
@ -26,6 +28,7 @@ namespace Emby.Common.Implementations.Net
|
||||||
|
|
||||||
Socket = socket;
|
Socket = socket;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
DualMode = isDualMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IpEndPointInfo LocalEndPoint
|
public IpEndPointInfo LocalEndPoint
|
||||||
|
@ -81,7 +84,7 @@ namespace Emby.Common.Implementations.Net
|
||||||
private SocketAcceptor _acceptor;
|
private SocketAcceptor _acceptor;
|
||||||
public void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed)
|
public void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed)
|
||||||
{
|
{
|
||||||
_acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed);
|
_acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
|
||||||
|
|
||||||
_acceptor.StartAccept();
|
_acceptor.StartAccept();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,9 @@ namespace Emby.Common.Implementations.Net
|
||||||
private readonly Socket _originalSocket;
|
private readonly Socket _originalSocket;
|
||||||
private readonly Func<bool> _isClosed;
|
private readonly Func<bool> _isClosed;
|
||||||
private readonly Action<ISocket> _onAccept;
|
private readonly Action<ISocket> _onAccept;
|
||||||
|
private readonly bool _isDualMode;
|
||||||
|
|
||||||
public SocketAcceptor(ILogger logger, Socket originalSocket, Action<ISocket> onAccept, Func<bool> isClosed)
|
public SocketAcceptor(ILogger logger, Socket originalSocket, Action<ISocket> onAccept, Func<bool> isClosed, bool isDualMode)
|
||||||
{
|
{
|
||||||
if (logger == null)
|
if (logger == null)
|
||||||
{
|
{
|
||||||
|
@ -34,6 +35,7 @@ namespace Emby.Common.Implementations.Net
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_originalSocket = originalSocket;
|
_originalSocket = originalSocket;
|
||||||
_isClosed = isClosed;
|
_isClosed = isClosed;
|
||||||
|
_isDualMode = isDualMode;
|
||||||
_onAccept = onAccept;
|
_onAccept = onAccept;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +117,7 @@ namespace Emby.Common.Implementations.Net
|
||||||
if (acceptSocket != null)
|
if (acceptSocket != null)
|
||||||
{
|
{
|
||||||
//ProcessAccept(acceptSocket);
|
//ProcessAccept(acceptSocket);
|
||||||
_onAccept(new NetSocket(acceptSocket, _logger));
|
_onAccept(new NetSocket(acceptSocket, _logger, _isDualMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept the next connection request
|
// Accept the next connection request
|
||||||
|
|
|
@ -46,21 +46,11 @@ namespace Emby.Common.Implementations.Net
|
||||||
socket.DualMode = true;
|
socket.DualMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NetSocket(socket, _logger);
|
return new NetSocket(socket, _logger, dualMode);
|
||||||
}
|
}
|
||||||
catch (SocketException ex)
|
catch (SocketException ex)
|
||||||
{
|
{
|
||||||
if (dualMode)
|
throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex);
|
||||||
{
|
|
||||||
_logger.Error("Error creating dual mode socket: {0}. Will retry with ipv4-only.", ex.SocketErrorCode);
|
|
||||||
|
|
||||||
if (ex.SocketErrorCode == SocketError.AddressFamilyNotSupported)
|
|
||||||
{
|
|
||||||
return CreateSocket(IpAddressFamily.InterNetwork, socketType, protocolType, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1305,19 +1305,49 @@ namespace Emby.Server.Core
|
||||||
|
|
||||||
public async Task<List<IpAddressInfo>> GetLocalIpAddresses()
|
public async Task<List<IpAddressInfo>> GetLocalIpAddresses()
|
||||||
{
|
{
|
||||||
var addresses = NetworkManager.GetLocalIpAddresses().ToList();
|
var addresses = ServerConfigurationManager
|
||||||
var list = new List<IpAddressInfo>();
|
.Configuration
|
||||||
|
.LocalNetworkAddresses
|
||||||
|
.Select(NormalizeConfiguredLocalAddress)
|
||||||
|
.Where(i => i != null)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
foreach (var address in addresses)
|
if (addresses.Count == 0)
|
||||||
{
|
{
|
||||||
var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
|
addresses.AddRange(NetworkManager.GetLocalIpAddresses());
|
||||||
if (valid)
|
|
||||||
|
var list = new List<IpAddressInfo>();
|
||||||
|
|
||||||
|
foreach (var address in addresses)
|
||||||
{
|
{
|
||||||
list.Add(address);
|
var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
list.Add(address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addresses = list;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
|
||||||
|
{
|
||||||
|
var index = address.Trim('/').IndexOf('/');
|
||||||
|
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
address = address.Substring(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
IpAddressInfo result;
|
||||||
|
if (NetworkManager.TryParseIpAddress(address.Trim('/'), out result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
@ -1553,7 +1583,8 @@ namespace Emby.Server.Core
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var process = ProcessFactory.Create(new ProcessOptions {
|
var process = ProcessFactory.Create(new ProcessOptions
|
||||||
|
{
|
||||||
FileName = url,
|
FileName = url,
|
||||||
EnableRaisingEvents = true,
|
EnableRaisingEvents = true,
|
||||||
UseShellExecute = true,
|
UseShellExecute = true,
|
||||||
|
|
|
@ -1351,6 +1351,27 @@ namespace Emby.Server.Implementations.Dto
|
||||||
if (episodeSeries != null)
|
if (episodeSeries != null)
|
||||||
{
|
{
|
||||||
dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
|
dto.SeriesStudio = episodeSeries.Studios.FirstOrDefault();
|
||||||
|
if (!string.IsNullOrWhiteSpace(dto.SeriesStudio))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var studio = _libraryManager.GetStudio(dto.SeriesStudio);
|
||||||
|
|
||||||
|
if (studio != null)
|
||||||
|
{
|
||||||
|
dto.SeriesStudioInfo = new StudioDto
|
||||||
|
{
|
||||||
|
Name = dto.SeriesStudio,
|
||||||
|
Id = studio.Id.ToString("N"),
|
||||||
|
PrimaryImageTag = GetImageCacheTag(studio, ImageType.Primary)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,13 +341,13 @@ namespace Emby.Server.Implementations.Library
|
||||||
}
|
}
|
||||||
if (item is IItemByName)
|
if (item is IItemByName)
|
||||||
{
|
{
|
||||||
if (!(item is MusicArtist))
|
if (!(item is MusicArtist) && !(item is Studio))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.IsFolder)
|
else if (item.IsFolder)
|
||||||
{
|
{
|
||||||
//if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder))
|
//if (!(item is ICollectionFolder) && !(item is UserView) && !(item is Channel) && !(item is AggregateFolder))
|
||||||
//{
|
//{
|
||||||
|
|
|
@ -1594,7 +1594,17 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
private void Process_Exited(object sender, EventArgs e)
|
private void Process_Exited(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
((IProcess)sender).Dispose();
|
var process = (IProcess)sender;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Info("Recording post-processing script completed with exit code {0}", process.ExitCode);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
process.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveRecordingImage(string recordingPath, LiveTvProgram program, ItemImageInfo image)
|
private async Task SaveRecordingImage(string recordingPath, LiveTvProgram program, ItemImageInfo image)
|
||||||
|
|
|
@ -377,7 +377,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
var url = GetApiUrl(info, true) + "/auto/v" + channelId;
|
var url = GetApiUrl(info, true) + "/auto/v" + channelId;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(profile) && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
|
// If raw was used, the tuner doesn't support params
|
||||||
|
if (!string.IsNullOrWhiteSpace(profile)
|
||||||
|
&& !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
url += "?transcode=" + profile;
|
url += "?transcode=" + profile;
|
||||||
}
|
}
|
||||||
|
@ -451,16 +453,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
}
|
}
|
||||||
var hdhrId = GetHdHrIdFromChannelId(channelId);
|
var hdhrId = GetHdHrIdFromChannelId(channelId);
|
||||||
|
|
||||||
list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (info.AllowHWTranscoding)
|
var model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
|
||||||
{
|
model = model ?? string.Empty;
|
||||||
string model = await GetModelInfo(info, cancellationToken).ConfigureAwait(false);
|
|
||||||
model = model ?? string.Empty;
|
|
||||||
|
|
||||||
if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
|
if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
|
||||||
|
{
|
||||||
|
list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
|
||||||
|
|
||||||
|
if (info.AllowHWTranscoding)
|
||||||
{
|
{
|
||||||
list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false));
|
list.Add(await GetMediaSource(info, hdhrId, "heavy").ConfigureAwait(false));
|
||||||
|
|
||||||
|
@ -477,6 +479,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (list.Count == 0)
|
||||||
|
{
|
||||||
|
list.Add(await GetMediaSource(info, hdhrId, "native").ConfigureAwait(false));
|
||||||
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
@ -100,16 +101,23 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
|
|
||||||
extInf = extInf.Trim();
|
extInf = extInf.Trim();
|
||||||
|
|
||||||
channel.ImageUrl = FindProperty("tvg-logo", extInf);
|
string remaining;
|
||||||
|
var attributes = ParseExtInf(extInf, out remaining);
|
||||||
|
extInf = remaining;
|
||||||
|
|
||||||
channel.Name = GetChannelName(extInf);
|
string value;
|
||||||
|
if (attributes.TryGetValue("tvg-logo", out value))
|
||||||
|
{
|
||||||
|
channel.ImageUrl = value;
|
||||||
|
}
|
||||||
|
|
||||||
channel.Number = GetChannelNumber(extInf, mediaUrl);
|
channel.Name = GetChannelName(extInf, attributes);
|
||||||
|
channel.Number = GetChannelNumber(extInf, attributes, mediaUrl);
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetChannelNumber(string extInf, string mediaUrl)
|
private string GetChannelNumber(string extInf, Dictionary<string, string> attributes, string mediaUrl)
|
||||||
{
|
{
|
||||||
var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
var nameInExtInf = nameParts.Length > 1 ? nameParts.Last().Trim() : null;
|
var nameInExtInf = nameParts.Length > 1 ? nameParts.Last().Trim() : null;
|
||||||
|
@ -130,18 +138,41 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(numberString) ||
|
if (!string.IsNullOrWhiteSpace(numberString))
|
||||||
string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
numberString = FindProperty("tvg-id", extInf);
|
numberString = numberString.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(numberString) ||
|
if (string.IsNullOrWhiteSpace(numberString) ||
|
||||||
string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
|
string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
|
string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
numberString = FindProperty("channel-id", extInf);
|
string value;
|
||||||
|
if (attributes.TryGetValue("tvg-id", out value))
|
||||||
|
{
|
||||||
|
numberString = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(numberString))
|
||||||
|
{
|
||||||
|
numberString = numberString.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(numberString) ||
|
||||||
|
string.Equals(numberString, "-1", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(numberString, "0", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string value;
|
||||||
|
if (attributes.TryGetValue("channel-id", out value))
|
||||||
|
{
|
||||||
|
numberString = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(numberString))
|
||||||
|
{
|
||||||
|
numberString = numberString.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(numberString) ||
|
if (string.IsNullOrWhiteSpace(numberString) ||
|
||||||
|
@ -160,13 +191,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
|
numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
|
||||||
|
|
||||||
|
double value;
|
||||||
|
if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
|
||||||
|
{
|
||||||
|
numberString = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return numberString;
|
return numberString;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetChannelName(string extInf)
|
private string GetChannelName(string extInf, Dictionary<string, string> attributes)
|
||||||
{
|
{
|
||||||
var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
var nameInExtInf = nameParts.Length > 1 ? nameParts.Last().Trim() : null;
|
var nameInExtInf = nameParts.Length > 1 ? nameParts.Last().Trim() : null;
|
||||||
|
@ -186,7 +223,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = FindProperty("tvg-name", extInf);
|
string name;
|
||||||
|
attributes.TryGetValue("tvg-name", out name);
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
{
|
{
|
||||||
name = nameInExtInf;
|
name = nameInExtInf;
|
||||||
|
@ -194,7 +233,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
{
|
{
|
||||||
name = FindProperty("tvg-id", extInf);
|
attributes.TryGetValue("tvg-id", out name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
@ -205,18 +244,27 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string FindProperty(string property, string properties)
|
private Dictionary<string, string> ParseExtInf(string line, out string remaining)
|
||||||
{
|
{
|
||||||
|
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
|
var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
|
||||||
var matches = reg.Matches(properties);
|
var matches = reg.Matches(line);
|
||||||
|
var minIndex = int.MaxValue;
|
||||||
foreach (Match match in matches)
|
foreach (Match match in matches)
|
||||||
{
|
{
|
||||||
if (match.Groups[1].Value == property)
|
dict[match.Groups[1].Value] = match.Groups[2].Value;
|
||||||
{
|
minIndex = Math.Min(minIndex, match.Index);
|
||||||
return match.Groups[2].Value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
if (minIndex > 0 && minIndex < line.Length)
|
||||||
|
{
|
||||||
|
line = line.Substring(0, minIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining = line;
|
||||||
|
|
||||||
|
return dict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -258,7 +258,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
// add when stream copying?
|
// add when stream copying?
|
||||||
// -avoid_negative_ts make_zero -fflags +genpts
|
// -avoid_negative_ts make_zero -fflags +genpts
|
||||||
|
|
||||||
var args = string.Format("{0} {1} {2} -map_metadata -1 -threads {3} {4} {5} -fflags +genpts -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
|
var args = string.Format("{0} {1} {2} -map_metadata -1 -map_chapters -1 -threads {3} {4} {5} -fflags +genpts -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
|
||||||
itsOffset,
|
itsOffset,
|
||||||
inputModifier,
|
inputModifier,
|
||||||
GetInputArgument(state),
|
GetInputArgument(state),
|
||||||
|
|
|
@ -895,7 +895,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state);
|
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state);
|
||||||
|
|
||||||
return string.Format("{0} {10} {1} -map_metadata -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} -break_non_keyframes 1 -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
|
return string.Format("{0} {10} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -f segment -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -segment_time {6} -break_non_keyframes 1 -segment_format mpegts -segment_list_type m3u8 -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
|
||||||
inputModifier,
|
inputModifier,
|
||||||
GetInputArgument(state),
|
GetInputArgument(state),
|
||||||
threads,
|
threads,
|
||||||
|
@ -913,7 +913,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
var splitByTime = hlsProtocolSupportsSplittingByTime && enableSplittingOnNonKeyFrames;
|
var splitByTime = hlsProtocolSupportsSplittingByTime && enableSplittingOnNonKeyFrames;
|
||||||
var splitByTimeArg = splitByTime ? " -hls_flags split_by_time" : "";
|
var splitByTimeArg = splitByTime ? " -hls_flags split_by_time" : "";
|
||||||
|
|
||||||
return string.Format("{0}{12} {1} -map_metadata -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7}{8} -start_number {9} -hls_list_size {10} -y \"{11}\"",
|
return string.Format("{0}{12} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4}{5} {6} -max_delay 5000000 -avoid_negative_ts disabled -start_at_zero -hls_time {7}{8} -start_number {9} -hls_list_size {10} -y \"{11}\"",
|
||||||
inputModifier,
|
inputModifier,
|
||||||
GetInputArgument(state),
|
GetInputArgument(state),
|
||||||
threads,
|
threads,
|
||||||
|
|
|
@ -111,7 +111,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
|
|
||||||
var inputModifier = GetInputModifier(state);
|
var inputModifier = GetInputModifier(state);
|
||||||
|
|
||||||
return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
|
return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -map_chapters -1 -threads {5} {6}{7} -y \"{8}\"",
|
||||||
inputModifier,
|
inputModifier,
|
||||||
GetInputArgument(state),
|
GetInputArgument(state),
|
||||||
keyFrame,
|
keyFrame,
|
||||||
|
|
|
@ -3,7 +3,6 @@ namespace MediaBrowser.Api.Reports
|
||||||
public enum ReportViewType
|
public enum ReportViewType
|
||||||
{
|
{
|
||||||
ReportData,
|
ReportData,
|
||||||
ReportStatistics,
|
|
||||||
ReportActivities
|
ReportActivities
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace MediaBrowser.Api.Reports
|
||||||
{
|
{
|
||||||
/// <summary> Gets or sets the report view. </summary>
|
/// <summary> Gets or sets the report view. </summary>
|
||||||
/// <value> The report view. </value>
|
/// <value> The report view. </value>
|
||||||
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string ReportView { get; set; }
|
public string ReportView { get; set; }
|
||||||
|
|
||||||
/// <summary> Gets or sets the report view. </summary>
|
/// <summary> Gets or sets the report view. </summary>
|
||||||
|
@ -101,7 +101,7 @@ namespace MediaBrowser.Api.Reports
|
||||||
{
|
{
|
||||||
/// <summary> Gets or sets the report view. </summary>
|
/// <summary> Gets or sets the report view. </summary>
|
||||||
/// <value> The report view. </value>
|
/// <value> The report view. </value>
|
||||||
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string ReportView { get; set; }
|
public string ReportView { get; set; }
|
||||||
|
|
||||||
/// <summary> Gets or sets the report view. </summary>
|
/// <summary> Gets or sets the report view. </summary>
|
||||||
|
@ -120,13 +120,6 @@ namespace MediaBrowser.Api.Reports
|
||||||
public string ReportColumns { get; set; }
|
public string ReportColumns { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("/Reports/Statistics", "GET", Summary = "Gets reports statistics based on library items")]
|
|
||||||
public class GetReportStatistics : BaseReportRequest, IReturn<ReportStatResult>
|
|
||||||
{
|
|
||||||
public int? TopItems { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Route("/Reports/Items/Download", "GET", Summary = "Downloads report")]
|
[Route("/Reports/Items/Download", "GET", Summary = "Downloads report")]
|
||||||
public class GetReportDownload : BaseReportRequest, IReportsDownload
|
public class GetReportDownload : BaseReportRequest, IReportsDownload
|
||||||
{
|
{
|
||||||
|
@ -150,7 +143,7 @@ namespace MediaBrowser.Api.Reports
|
||||||
{
|
{
|
||||||
/// <summary> Gets or sets the report view. </summary>
|
/// <summary> Gets or sets the report view. </summary>
|
||||||
/// <value> The report view. </value>
|
/// <value> The report view. </value>
|
||||||
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportStatistics, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "ReportView", Description = "The report view. Values (ReportData, ReportActivities)", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||||
public string ReportView { get; set; }
|
public string ReportView { get; set; }
|
||||||
|
|
||||||
/// <summary> Gets or sets the report view. </summary>
|
/// <summary> Gets or sets the report view. </summary>
|
||||||
|
|
|
@ -82,8 +82,6 @@ namespace MediaBrowser.Api.Reports
|
||||||
ReportBuilder dataBuilder = new ReportBuilder(_libraryManager);
|
ReportBuilder dataBuilder = new ReportBuilder(_libraryManager);
|
||||||
result = dataBuilder.GetHeaders(request);
|
result = dataBuilder.GetHeaders(request);
|
||||||
break;
|
break;
|
||||||
case ReportViewType.ReportStatistics:
|
|
||||||
break;
|
|
||||||
case ReportViewType.ReportActivities:
|
case ReportViewType.ReportActivities:
|
||||||
ReportActivitiesBuilder activityBuilder = new ReportActivitiesBuilder(_libraryManager, _userManager);
|
ReportActivitiesBuilder activityBuilder = new ReportActivitiesBuilder(_libraryManager, _userManager);
|
||||||
result = activityBuilder.GetHeaders(request);
|
result = activityBuilder.GetHeaders(request);
|
||||||
|
@ -109,20 +107,6 @@ namespace MediaBrowser.Api.Reports
|
||||||
return ToOptimizedResult(reportResult);
|
return ToOptimizedResult(reportResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Gets the given request. </summary>
|
|
||||||
/// <param name="request"> The request. </param>
|
|
||||||
/// <returns> A Task<object> </returns>
|
|
||||||
public async Task<object> Get(GetReportStatistics request)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(request.IncludeItemTypes))
|
|
||||||
return null;
|
|
||||||
request.DisplayType = "Screen";
|
|
||||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
|
||||||
var reportResult = await GetReportStatistic(request, user);
|
|
||||||
|
|
||||||
return ToOptimizedResult(reportResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Gets the given request. </summary>
|
/// <summary> Gets the given request. </summary>
|
||||||
/// <param name="request"> The request. </param>
|
/// <param name="request"> The request. </param>
|
||||||
/// <returns> A Task<object> </returns>
|
/// <returns> A Task<object> </returns>
|
||||||
|
@ -155,7 +139,6 @@ namespace MediaBrowser.Api.Reports
|
||||||
ReportResult result = null;
|
ReportResult result = null;
|
||||||
switch (reportViewType)
|
switch (reportViewType)
|
||||||
{
|
{
|
||||||
case ReportViewType.ReportStatistics:
|
|
||||||
case ReportViewType.ReportData:
|
case ReportViewType.ReportData:
|
||||||
ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
|
ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
|
||||||
ReportBuilder dataBuilder = new ReportBuilder(_libraryManager);
|
ReportBuilder dataBuilder = new ReportBuilder(_libraryManager);
|
||||||
|
@ -463,20 +446,6 @@ namespace MediaBrowser.Api.Reports
|
||||||
return reportResult;
|
return reportResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Gets report statistic. </summary>
|
|
||||||
/// <param name="request"> The request. </param>
|
|
||||||
/// <returns> The report statistic. </returns>
|
|
||||||
private async Task<ReportStatResult> GetReportStatistic(GetReportStatistics request, User user)
|
|
||||||
{
|
|
||||||
ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes);
|
|
||||||
QueryResult<BaseItem> queryResult = await GetQueryResult(request, user).ConfigureAwait(false);
|
|
||||||
|
|
||||||
ReportStatBuilder reportBuilder = new ReportStatBuilder(_libraryManager);
|
|
||||||
ReportStatResult reportResult = reportBuilder.GetResult(queryResult.Items, ReportHelper.GetRowType(request.IncludeItemTypes), request.TopItems ?? 5);
|
|
||||||
reportResult.TotalRecordCount = reportResult.Groups.Count();
|
|
||||||
return reportResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MediaBrowser.Model.Serialization;
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
|
@ -184,7 +185,16 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
|
|
||||||
public string FindSeasonName()
|
public string FindSeasonName()
|
||||||
{
|
{
|
||||||
var season = Season;
|
var season = Season;
|
||||||
|
|
||||||
|
if (season == null)
|
||||||
|
{
|
||||||
|
if (ParentIndexNumber.HasValue)
|
||||||
|
{
|
||||||
|
return "Season " + ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return season == null ? SeasonName : season.Name;
|
return season == null ? SeasonName : season.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,6 @@
|
||||||
<Compile Include="Providers\GameXmlProvider.cs" />
|
<Compile Include="Providers\GameXmlProvider.cs" />
|
||||||
<Compile Include="Providers\MovieXmlProvider.cs" />
|
<Compile Include="Providers\MovieXmlProvider.cs" />
|
||||||
<Compile Include="Providers\MusicVideoXmlProvider.cs" />
|
<Compile Include="Providers\MusicVideoXmlProvider.cs" />
|
||||||
<Compile Include="Providers\PersonXmlProvider.cs" />
|
|
||||||
<Compile Include="Providers\PlaylistXmlProvider.cs" />
|
<Compile Include="Providers\PlaylistXmlProvider.cs" />
|
||||||
<Compile Include="Providers\SeriesXmlProvider.cs" />
|
<Compile Include="Providers\SeriesXmlProvider.cs" />
|
||||||
<Compile Include="Providers\VideoXmlProvider.cs" />
|
<Compile Include="Providers\VideoXmlProvider.cs" />
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Model.IO;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.IO;
|
|
||||||
using MediaBrowser.Controller.Providers;
|
|
||||||
using MediaBrowser.LocalMetadata.Parsers;
|
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using MediaBrowser.Model.Xml;
|
|
||||||
|
|
||||||
namespace MediaBrowser.LocalMetadata.Providers
|
|
||||||
{
|
|
||||||
//public class PersonXmlProvider : BaseXmlProvider<Person>
|
|
||||||
//{
|
|
||||||
// private readonly ILogger _logger;
|
|
||||||
// private readonly IProviderManager _providerManager;
|
|
||||||
// protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; }
|
|
||||||
|
|
||||||
// public PersonXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
|
|
||||||
// : base(fileSystem)
|
|
||||||
// {
|
|
||||||
// _logger = logger;
|
|
||||||
// _providerManager = providerManager;
|
|
||||||
// XmlReaderSettingsFactory = xmlReaderSettingsFactory;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// protected override void Fetch(MetadataResult<Person> result, string path, CancellationToken cancellationToken)
|
|
||||||
// {
|
|
||||||
// new BaseItemXmlParser<Person>(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
|
|
||||||
// {
|
|
||||||
// return directoryService.GetFile(Path.Combine(info.Path, "person.xml"));
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
|
@ -729,6 +729,8 @@ namespace MediaBrowser.Model.Dto
|
||||||
/// <value>The series studio.</value>
|
/// <value>The series studio.</value>
|
||||||
public string SeriesStudio { get; set; }
|
public string SeriesStudio { get; set; }
|
||||||
|
|
||||||
|
public StudioDto SeriesStudioInfo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the parent thumb item id.
|
/// Gets or sets the parent thumb item id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace MediaBrowser.Model.Net
|
||||||
{
|
{
|
||||||
public interface ISocket : IDisposable
|
public interface ISocket : IDisposable
|
||||||
{
|
{
|
||||||
|
bool DualMode { get; }
|
||||||
IpEndPointInfo LocalEndPoint { get; }
|
IpEndPointInfo LocalEndPoint { get; }
|
||||||
IpEndPointInfo RemoteEndPoint { get; }
|
IpEndPointInfo RemoteEndPoint { get; }
|
||||||
void Close();
|
void Close();
|
||||||
|
@ -13,4 +14,15 @@ namespace MediaBrowser.Model.Net
|
||||||
|
|
||||||
void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed);
|
void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class SocketCreateException : Exception
|
||||||
|
{
|
||||||
|
public SocketCreateException(string errorCode, Exception originalException)
|
||||||
|
: base(errorCode, originalException)
|
||||||
|
{
|
||||||
|
ErrorCode = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ErrorCode { get; private set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,7 +249,7 @@ namespace Rssdp.Infrastructure
|
||||||
|
|
||||||
if (IsDuplicateSearchRequest(searchTarget, remoteEndPoint))
|
if (IsDuplicateSearchRequest(searchTarget, remoteEndPoint))
|
||||||
{
|
{
|
||||||
WriteTrace("Search Request is Duplicate, ignoring.");
|
//WriteTrace("Search Request is Duplicate, ignoring.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +299,9 @@ namespace Rssdp.Infrastructure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
WriteTrace(String.Format("Sending 0 search responses."));
|
WriteTrace(String.Format("Sending 0 search responses."));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace SocketHttpListener.Net
|
||||||
Dictionary<HttpConnection, HttpConnection> unregistered;
|
Dictionary<HttpConnection, HttpConnection> unregistered;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private bool _closed;
|
private bool _closed;
|
||||||
private readonly bool _enableDualMode;
|
private bool _enableDualMode;
|
||||||
private readonly ICryptoProvider _cryptoProvider;
|
private readonly ICryptoProvider _cryptoProvider;
|
||||||
private readonly IStreamFactory _streamFactory;
|
private readonly IStreamFactory _streamFactory;
|
||||||
private readonly ISocketFactory _socketFactory;
|
private readonly ISocketFactory _socketFactory;
|
||||||
|
@ -65,7 +65,23 @@ namespace SocketHttpListener.Net
|
||||||
|
|
||||||
private void CreateSocket()
|
private void CreateSocket()
|
||||||
{
|
{
|
||||||
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
|
try
|
||||||
|
{
|
||||||
|
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
|
||||||
|
}
|
||||||
|
catch (SocketCreateException ex)
|
||||||
|
{
|
||||||
|
if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) && string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port);
|
||||||
|
_enableDualMode = false;
|
||||||
|
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sock.Bind(endpoint);
|
sock.Bind(endpoint);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user