aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Common.Implementations/Net/UdpSocket.cs55
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs37
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs8
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs35
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs120
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs129
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs48
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs20
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs9
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs162
-rw-r--r--MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs5
-rw-r--r--MediaBrowser.Model/LiveTv/LiveTvOptions.cs2
-rw-r--r--MediaBrowser.Server.Mac/Emby.Server.Mac.csproj56
-rw-r--r--MediaBrowser.Server.Mac/MacAppHost.cs4
-rw-r--r--MediaBrowser.Server.Mac/Native/MonoFileSystem.cs5
-rw-r--r--SharedVersion.cs2
19 files changed, 227 insertions, 482 deletions
diff --git a/Emby.Common.Implementations/Net/UdpSocket.cs b/Emby.Common.Implementations/Net/UdpSocket.cs
index b85245ba1..45cb42ecd 100644
--- a/Emby.Common.Implementations/Net/UdpSocket.cs
+++ b/Emby.Common.Implementations/Net/UdpSocket.cs
@@ -16,12 +16,15 @@ namespace Emby.Common.Implementations.Net
internal sealed class UdpSocket : DisposableManagedObjectBase, ISocket
{
-
- #region Fields
-
private Socket _Socket;
private int _LocalPort;
- #endregion
+
+ private SocketAsyncEventArgs _receiveSocketAsyncEventArgs = new SocketAsyncEventArgs()
+ {
+ SocketFlags = SocketFlags.None
+ };
+
+ private TaskCompletionSource<SocketReceiveResult> _currentReceiveTaskCompletionSource;
public UdpSocket(Socket socket, int localPort, IPAddress ip)
{
@@ -32,6 +35,32 @@ namespace Emby.Common.Implementations.Net
LocalIPAddress = NetworkManager.ToIpAddressInfo(ip);
_Socket.Bind(new IPEndPoint(ip, _LocalPort));
+
+ InitReceiveSocketAsyncEventArgs();
+ }
+
+ private void InitReceiveSocketAsyncEventArgs()
+ {
+ var buffer = new byte[8192];
+ _receiveSocketAsyncEventArgs.SetBuffer(buffer, 0, buffer.Length);
+ _receiveSocketAsyncEventArgs.Completed += _receiveSocketAsyncEventArgs_Completed;
+ }
+
+ private void _receiveSocketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
+ {
+ var tcs = _currentReceiveTaskCompletionSource;
+ if (tcs != null)
+ {
+ _currentReceiveTaskCompletionSource = null;
+
+ tcs.TrySetResult(new SocketReceiveResult
+ {
+ Buffer = e.Buffer,
+ ReceivedBytes = e.BytesTransferred,
+ RemoteEndPoint = ToIpEndPointInfo(e.RemoteEndPoint as IPEndPoint),
+ LocalIPAddress = LocalIPAddress
+ });
+ }
}
public UdpSocket(Socket socket, IpEndPointInfo endPoint)
@@ -40,6 +69,8 @@ namespace Emby.Common.Implementations.Net
_Socket = socket;
_Socket.Connect(NetworkManager.ToIPEndPoint(endPoint));
+
+ InitReceiveSocketAsyncEventArgs();
}
public IpAddressInfo LocalIPAddress
@@ -57,12 +88,12 @@ namespace Emby.Common.Implementations.Net
var tcs = new TaskCompletionSource<SocketReceiveResult>();
EndPoint receivedFromEndPoint = new IPEndPoint(IPAddress.Any, 0);
- var state = new AsyncReceiveState(_Socket, receivedFromEndPoint);
- state.TaskCompletionSource = tcs;
-
cancellationToken.Register(() => tcs.TrySetCanceled());
#if NETSTANDARD1_6
+ var state = new AsyncReceiveState(_Socket, receivedFromEndPoint);
+ state.TaskCompletionSource = tcs;
+
_Socket.ReceiveFromAsync(new ArraySegment<Byte>(state.Buffer), SocketFlags.None, state.RemoteEndPoint)
.ContinueWith((task, asyncState) =>
{
@@ -74,7 +105,15 @@ namespace Emby.Common.Implementations.Net
}
}, state);
#else
- _Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.RemoteEndPoint, ProcessResponse, state);
+ //var state = new AsyncReceiveState(_Socket, receivedFromEndPoint);
+ //state.TaskCompletionSource = tcs;
+
+ //_Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.RemoteEndPoint, ProcessResponse, state);
+
+ _receiveSocketAsyncEventArgs.RemoteEndPoint = receivedFromEndPoint;
+ _currentReceiveTaskCompletionSource = tcs;
+
+ var isPending = _Socket.ReceiveFromAsync(_receiveSocketAsyncEventArgs);
#endif
return tcs.Task;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 2d9ea5853..368053b9d 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -498,11 +498,17 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (!string.IsNullOrWhiteSpace(tunerChannel.TunerChannelId))
{
- var mappedTunerChannelId = GetMappedChannel(tunerChannel.TunerChannelId, mappings);
+ var tunerChannelId = tunerChannel.TunerChannelId;
+ if (tunerChannelId.IndexOf(".json.schedulesdirect.org", StringComparison.OrdinalIgnoreCase) != -1)
+ {
+ tunerChannelId = tunerChannelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I');
+ }
+
+ var mappedTunerChannelId = GetMappedChannel(tunerChannelId, mappings);
if (string.IsNullOrWhiteSpace(mappedTunerChannelId))
{
- mappedTunerChannelId = tunerChannel.TunerChannelId;
+ mappedTunerChannelId = tunerChannelId;
}
var channel = epgChannels.FirstOrDefault(i => string.Equals(mappedTunerChannelId, i.Id, StringComparison.OrdinalIgnoreCase));
@@ -644,8 +650,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public Task<string> CreateTimer(TimerInfo timer, CancellationToken cancellationToken)
{
- var existingTimer = _timerProvider.GetAll()
- .FirstOrDefault(i => string.Equals(timer.ProgramId, i.ProgramId, StringComparison.OrdinalIgnoreCase));
+ var existingTimer = string.IsNullOrWhiteSpace(timer.ProgramId) ?
+ null :
+ _timerProvider.GetTimerByProgramId(timer.ProgramId);
if (existingTimer != null)
{
@@ -724,10 +731,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return true;
}
- //if (string.Equals(i.SeriesId, info.SeriesId, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(info.SeriesId))
- //{
- // return true;
- //}
+ if (string.Equals(i.SeriesId, info.SeriesId, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(info.SeriesId))
+ {
+ return true;
+ }
return false;
})
@@ -740,7 +747,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
timer.SeriesTimerId = info.Id;
timer.IsManual = true;
- _timerProvider.AddOrUpdate(timer);
+ _timerProvider.AddOrUpdate(timer, false);
}
await UpdateTimersForSeriesTimer(epgData, info, true, false).ConfigureAwait(false);
@@ -2342,6 +2349,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (existingTimer == null)
{
+ existingTimer = string.IsNullOrWhiteSpace(timer.ProgramId)
+ ? null
+ : _timerProvider.GetTimerByProgramId(timer.ProgramId);
+ }
+
+ if (existingTimer == null)
+ {
if (ShouldCancelTimerForSeriesTimer(seriesTimer, timer))
{
timer.Status = RecordingStatus.Cancelled;
@@ -2354,9 +2368,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
else
{
- // Only update if not currently active
+ // Only update if not currently active - test both new timer and existing in case Id's are different
+ // Id's could be different if the timer was created manually prior to series timer creation
ActiveRecordingInfo activeRecordingInfo;
- if (!_activeRecordings.TryGetValue(timer.Id, out activeRecordingInfo))
+ if (!_activeRecordings.TryGetValue(timer.Id, out activeRecordingInfo) && !_activeRecordings.TryGetValue(existingTimer.Id, out activeRecordingInfo))
{
UpdateExistingTimerWithNewMetadata(existingTimer, timer);
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 0567bdfd9..6cc5b6920 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -163,7 +163,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
var inputModifiers = "-fflags +genpts -async 1 -vsync -1";
- var commandLineArgs = "-i \"{0}\"{5} {2} -map_metadata -1 -threads 0 {3}{4} -y \"{1}\"";
+ var commandLineArgs = "-i \"{0}\"{5} {2} -map_metadata -1 -threads 0 {3}{4}{6} -y \"{1}\"";
long startTimeTicks = 0;
//if (mediaSource.DateLiveStreamOpened.HasValue)
@@ -193,7 +193,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var subtitleArgs = CopySubtitles ? " -codec:s copy" : " -sn";
- commandLineArgs = string.Format(commandLineArgs, inputTempFile, targetFile, videoArgs, GetAudioArgs(mediaSource), subtitleArgs, durationParam);
+ var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ?
+ " -f mp4 -movflags frag_keyframe+empty_moov" :
+ string.Empty;
+
+ commandLineArgs = string.Format(commandLineArgs, inputTempFile, targetFile, videoArgs, GetAudioArgs(mediaSource), subtitleArgs, durationParam, outputParam);
return inputModifiers + " " + commandLineArgs;
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 35868d318..2eec3df8a 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
@@ -166,5 +166,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
return GetAll().FirstOrDefault(r => string.Equals(r.Id, id, StringComparison.OrdinalIgnoreCase));
}
+
+ public TimerInfo GetTimerByProgramId(string programId)
+ {
+ return GetAll().FirstOrDefault(r => string.Equals(r.ProgramId, programId, StringComparison.OrdinalIgnoreCase));
+ }
}
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 8406d44a7..b9e73b62e 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1078,25 +1078,28 @@ namespace Emby.Server.Implementations.LiveTv
var channel = GetInternalChannel(program.ChannelId);
- var channelUserdata = _userDataManager.GetUserData(userId, channel);
-
- if (channelUserdata.Likes ?? false)
- {
- score += 2;
- }
- else if (!(channelUserdata.Likes ?? true))
+ if (channel != null)
{
- score -= 2;
- }
+ var channelUserdata = _userDataManager.GetUserData(userId, channel);
- if (channelUserdata.IsFavorite)
- {
- score += 3;
- }
+ if (channelUserdata.Likes ?? false)
+ {
+ score += 2;
+ }
+ else if (!(channelUserdata.Likes ?? true))
+ {
+ score -= 2;
+ }
- if (factorChannelWatchCount)
- {
- score += channelUserdata.PlayCount;
+ if (channelUserdata.IsFavorite)
+ {
+ score += 3;
+ }
+
+ if (factorChannelWatchCount)
+ {
+ score += channelUserdata.PlayCount;
+ }
}
return score;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 02a6bf85d..17c57712e 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -275,6 +275,16 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public int HD { get; set; }
}
+ protected EncodingOptions GetEncodingOptions()
+ {
+ return Config.GetConfiguration<EncodingOptions>("encoding");
+ }
+
+ private string GetHdHrIdFromChannelId(string channelId)
+ {
+ return channelId.Split('_')[1];
+ }
+
private MediaSourceInfo GetMediaSource(TunerHostInfo info, string channelId, ChannelInfo channelInfo, string profile)
{
int? width = null;
@@ -362,14 +372,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
nal = "0";
}
- var url = GetApiUrl(info, true) + "/auto/v" + channelId;
-
- // If raw was used, the tuner doesn't support params
- if (!string.IsNullOrWhiteSpace(profile)
- && !string.Equals(profile, "native", StringComparison.OrdinalIgnoreCase))
- {
- url += "?transcode=" + profile;
- }
+ var url = GetApiUrl(info, false);
var id = profile;
if (string.IsNullOrWhiteSpace(id))
@@ -381,92 +384,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var mediaSource = new MediaSourceInfo
{
Path = url,
- Protocol = MediaProtocol.Http,
- MediaStreams = new List<MediaStream>
- {
- new MediaStream
- {
- Type = MediaStreamType.Video,
- // Set the index to -1 because we don't know the exact index of the video stream within the container
- Index = -1,
- IsInterlaced = isInterlaced,
- Codec = videoCodec,
- Width = width,
- Height = height,
- BitRate = videoBitrate,
- NalLengthSize = nal
-
- },
- new MediaStream
- {
- Type = MediaStreamType.Audio,
- // Set the index to -1 because we don't know the exact index of the audio stream within the container
- Index = -1,
- Codec = audioCodec,
- BitRate = audioBitrate
- }
- },
- RequiresOpening = true,
- RequiresClosing = false,
- BufferMs = 0,
- Container = "ts",
- Id = id,
- SupportsDirectPlay = false,
- SupportsDirectStream = true,
- SupportsTranscoding = true,
- IsInfiniteStream = true
- };
-
- mediaSource.InferTotalBitrate();
-
- return mediaSource;
- }
-
- protected EncodingOptions GetEncodingOptions()
- {
- return Config.GetConfiguration<EncodingOptions>("encoding");
- }
-
- private string GetHdHrIdFromChannelId(string channelId)
- {
- return channelId.Split('_')[1];
- }
-
- private MediaSourceInfo GetLegacyMediaSource(TunerHostInfo info, string channelId, ChannelInfo channel)
- {
- int? width = null;
- int? height = null;
- bool isInterlaced = true;
- string videoCodec = null;
- string audioCodec = null;
-
- int? videoBitrate = null;
- int? audioBitrate = null;
-
- if (channel != null)
- {
- if (string.IsNullOrWhiteSpace(videoCodec))
- {
- videoCodec = channel.VideoCodec;
- }
- audioCodec = channel.AudioCodec;
- }
-
- // normalize
- if (string.Equals(videoCodec, "mpeg2", StringComparison.OrdinalIgnoreCase))
- {
- videoCodec = "mpeg2video";
- }
-
- string nal = null;
-
- var url = GetApiUrl(info, false);
- var id = channelId;
- id += "_" + url.GetMD5().ToString("N");
-
- var mediaSource = new MediaSourceInfo
- {
- Path = url,
Protocol = MediaProtocol.Udp,
MediaStreams = new List<MediaStream>
{
@@ -527,7 +444,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
if (isLegacyTuner)
{
- list.Add(GetLegacyMediaSource(info, hdhrId, channelInfo));
+ list.Add(GetMediaSource(info, hdhrId, channelInfo, "native"));
}
else
{
@@ -579,20 +496,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var hdhomerunChannel = channelInfo as HdHomerunChannelInfo;
+ var mediaSource = GetMediaSource(info, hdhrId, channelInfo, profile);
+ var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
+
if (hdhomerunChannel != null && hdhomerunChannel.IsLegacyTuner)
{
- var mediaSource = GetLegacyMediaSource(info, hdhrId, channelInfo);
- var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
-
return new HdHomerunUdpStream(mediaSource, streamId, new LegacyHdHomerunChannelCommands(hdhomerunChannel.Url), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
}
else
{
- var mediaSource = GetMediaSource(info, hdhrId, channelInfo, profile);
- //var modelInfo = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
-
- return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
- //return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
+ //return new HdHomerunHttpStream(mediaSource, streamId, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost);
+ return new HdHomerunUdpStream(mediaSource, streamId, new HdHomerunChannelCommands(hdhomerunChannel.Number), modelInfo.TunerCount, _fileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _socketFactory, _networkManager);
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index 867e07e87..92000a1b3 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -120,8 +120,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// send url to start streaming
await hdHomerunManager.StartStreaming(remoteAddress, localAddress, localPort, _channelCommands, _numTuners, cancellationToken).ConfigureAwait(false);
- var timeoutToken = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(5000).Token, cancellationToken).Token;
- var response = await udpClient.ReceiveAsync(timeoutToken).ConfigureAwait(false);
_logger.Info("Opened HDHR UDP stream from {0}", remoteAddress);
if (!cancellationToken.IsCancellationRequested)
@@ -132,8 +130,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
onStarted = () => openTaskCompletionSource.TrySetResult(true);
}
- var stream = new UdpClientStream(udpClient);
- await _multicastStream.CopyUntilCancelled(stream, onStarted, cancellationToken).ConfigureAwait(false);
+ await _multicastStream.CopyUntilCancelled(udpClient, onStarted, cancellationToken).ConfigureAwait(false);
}
}
catch (OperationCanceledException ex)
@@ -158,7 +155,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
await hdHomerunManager.StopStreaming().ConfigureAwait(false);
- udpClient.Dispose();
_liveStreamTaskCompletionSource.TrySetResult(true);
}
}
@@ -171,127 +167,4 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return _multicastStream.CopyToAsync(stream);
}
}
-
- // This handles the ReadAsync function only of a Stream object
- // This is used to wrap a UDP socket into a stream for MulticastStream which only uses ReadAsync
- public class UdpClientStream : Stream
- {
- private static int RtpHeaderBytes = 12;
- private static int PacketSize = 1316;
- private readonly ISocket _udpClient;
- bool disposed;
-
- public UdpClientStream(ISocket udpClient) : base()
- {
- _udpClient = udpClient;
- }
-
- public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- if (buffer == null)
- throw new ArgumentNullException("buffer");
-
- if (offset + count < 0)
- throw new ArgumentOutOfRangeException("offset + count must not be negative", "offset+count");
-
- if (offset + count > buffer.Length)
- throw new ArgumentException("offset + count must not be greater than the length of buffer", "offset+count");
-
- if (disposed)
- throw new ObjectDisposedException(typeof(UdpClientStream).ToString());
-
- // This will always receive a 1328 packet size (PacketSize + RtpHeaderSize)
- // The RTP header will be stripped so see how many reads we need to make to fill the buffer.
- int numReads = count / PacketSize;
- int totalBytesRead = 0;
-
- for (int i = 0; i < numReads; ++i)
- {
- var data = await _udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
-
- var bytesRead = data.ReceivedBytes - RtpHeaderBytes;
-
- // remove rtp header
- Buffer.BlockCopy(data.Buffer, RtpHeaderBytes, buffer, offset, bytesRead);
- offset += bytesRead;
- totalBytesRead += bytesRead;
- }
- return totalBytesRead;
- }
-
- protected override void Dispose(bool disposing)
- {
- disposed = true;
- }
-
- public override bool CanRead
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public override bool CanSeek
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public override bool CanWrite
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public override long Length
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public override long Position
- {
- get
- {
- throw new NotImplementedException();
- }
-
- set
- {
- throw new NotImplementedException();
- }
- }
-
- public override void Flush()
- {
- throw new NotImplementedException();
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
-
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
- }
} \ No newline at end of file
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index fe677f6fa..8c4b9bf60 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -144,11 +144,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
channel.TunerChannelId = string.IsNullOrWhiteSpace(tvgId) ? channelId : tvgId;
- if (!string.IsNullOrWhiteSpace(channel.TunerChannelId) && channel.TunerChannelId.IndexOf(".json.schedulesdirect.org", StringComparison.OrdinalIgnoreCase) != -1)
- {
- channel.TunerChannelId = channel.TunerChannelId.Replace(".json.schedulesdirect.org", string.Empty, StringComparison.OrdinalIgnoreCase).TrimStart('I');
- }
-
var channelIdValues = new List<string>();
if (!string.IsNullOrWhiteSpace(channelId))
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
index 90ff36441..e3d0d1eba 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/MulticastStream.cs
@@ -7,6 +7,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
@@ -40,7 +41,52 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var allStreams = _outputStreams.ToList();
foreach (var stream in allStreams)
{
- stream.Value.Queue(copy);
+ stream.Value.Queue(copy, 0, copy.Length);
+ }
+
+ if (onStarted != null)
+ {
+ var onStartedCopy = onStarted;
+ onStarted = null;
+ Task.Run(onStartedCopy);
+ }
+ }
+
+ else
+ {
+ await Task.Delay(100).ConfigureAwait(false);
+ }
+ }
+ }
+
+ private static int RtpHeaderBytes = 12;
+ public async Task CopyUntilCancelled(ISocket udpClient, Action onStarted, CancellationToken cancellationToken)
+ {
+ _cancellationToken = cancellationToken;
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ var receiveToken = cancellationToken;
+
+ // On the first connection attempt, put a timeout to avoid being stuck indefinitely in the event of failure
+ if (onStarted != null)
+ {
+ receiveToken = CancellationTokenSource.CreateLinkedTokenSource(new CancellationTokenSource(5000).Token, cancellationToken).Token;
+ }
+
+ var data = await udpClient.ReceiveAsync(receiveToken).ConfigureAwait(false);
+ var bytesRead = data.ReceivedBytes - RtpHeaderBytes;
+
+ if (bytesRead > 0)
+ {
+ byte[] copy = new byte[bytesRead];
+ Buffer.BlockCopy(data.Buffer, RtpHeaderBytes, copy, 0, bytesRead);
+
+ var allStreams = _outputStreams.ToList();
+ foreach (var stream in allStreams)
+ {
+ //stream.Value.Queue(data.Buffer, RtpHeaderBytes, bytesRead);
+ stream.Value.Queue(copy, 0, copy.Length);
}
if (onStarted != null)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
index 7b48ce21a..27dd288a7 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/QueueStream.cs
@@ -13,7 +13,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public class QueueStream
{
private readonly Stream _outputStream;
- private readonly ConcurrentQueue<byte[]> _queue = new ConcurrentQueue<byte[]>();
+ private readonly ConcurrentQueue<Tuple<byte[],int,int>> _queue = new ConcurrentQueue<Tuple<byte[], int, int>>();
private CancellationToken _cancellationToken;
public TaskCompletionSource<bool> TaskCompletion { get; private set; }
@@ -28,9 +28,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
TaskCompletion = new TaskCompletionSource<bool>();
}
- public void Queue(byte[] bytes)
+ public void Queue(byte[] bytes, int offset, int count)
{
- _queue.Enqueue(bytes);
+ _queue.Enqueue(new Tuple<byte[], int, int>(bytes, offset, count));
}
public void Start(CancellationToken cancellationToken)
@@ -39,12 +39,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
Task.Run(() => StartInternal());
}
- private byte[] Dequeue()
+ private Tuple<byte[], int, int> Dequeue()
{
- byte[] bytes;
- if (_queue.TryDequeue(out bytes))
+ Tuple<byte[], int, int> result;
+ if (_queue.TryDequeue(out result))
{
- return bytes;
+ return result;
}
return null;
@@ -58,10 +58,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
while (true)
{
- var bytes = Dequeue();
- if (bytes != null)
+ var result = Dequeue();
+ if (result != null)
{
- await _outputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+ await _outputStream.WriteAsync(result.Item1, result.Item2, result.Item3, cancellationToken).ConfigureAwait(false);
}
else
{
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index eb69a8f7b..5eaab4110 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -1583,6 +1583,15 @@ namespace MediaBrowser.Controller.MediaEncoding
MediaSourceInfo mediaSource,
string requestedUrl)
{
+ if (state == null)
+ {
+ throw new ArgumentNullException("state");
+ }
+ if (mediaSource == null)
+ {
+ throw new ArgumentNullException("mediaSource");
+ }
+
state.MediaPath = mediaSource.Path;
state.InputProtocol = mediaSource.Protocol;
state.InputContainer = mediaSource.Container;
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 580f5c615..97f2c57eb 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -647,9 +647,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
- if (videoStream != null)
+ if (videoStream != null && !videoStream.IsInterlaced)
{
- var isInterlaced = await DetectInterlaced(mediaInfo, videoStream, inputPath, probeSizeArgument).ConfigureAwait(false);
+ var isInterlaced = DetectInterlaced(mediaInfo, videoStream);
if (isInterlaced)
{
@@ -672,7 +672,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- private async Task<bool> DetectInterlaced(MediaSourceInfo video, MediaStream videoStream, string inputPath, string probeSizeArgument)
+ private bool DetectInterlaced(MediaSourceInfo video, MediaStream videoStream)
{
var formats = (video.Container ?? string.Empty).Split(',').ToList();
var enableInterlacedDection = formats.Contains("vob", StringComparer.OrdinalIgnoreCase) ||
@@ -698,165 +698,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
- if (video.Protocol != MediaProtocol.File)
- {
- return false;
- }
-
- var args = "{0} -i {1} -map 0:v:{2} -an -filter:v idet -frames:v 500 -an -f null /dev/null";
-
- var process = _processFactory.Create(new ProcessOptions
- {
- CreateNoWindow = true,
- UseShellExecute = false,
-
- // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
- RedirectStandardError = true,
- FileName = FFMpegPath,
- Arguments = string.Format(args, probeSizeArgument, inputPath, videoStream.Index.ToString(CultureInfo.InvariantCulture)).Trim(),
-
- IsHidden = true,
- ErrorDialog = false,
- EnableRaisingEvents = true
- });
-
- _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
- var idetFoundInterlaced = false;
-
- using (var processWrapper = new ProcessWrapper(process, this, _logger))
- {
- try
- {
- StartProcess(processWrapper);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error starting ffprobe", ex);
-
- throw;
- }
-
- try
- {
- //process.BeginOutputReadLine();
-
- using (var reader = new StreamReader(process.StandardError.BaseStream))
- {
- while (!reader.EndOfStream)
- {
- var line = await reader.ReadLineAsync().ConfigureAwait(false);
-
- if (line.StartsWith("[Parsed_idet", StringComparison.OrdinalIgnoreCase))
- {
- var idetResult = AnalyzeIdetResult(line);
-
- if (idetResult.HasValue)
- {
- if (!idetResult.Value)
- {
- return false;
- }
-
- idetFoundInterlaced = true;
- }
- }
- }
- }
-
- }
- catch
- {
- StopProcess(processWrapper, 100);
-
- throw;
- }
- }
-
- return idetFoundInterlaced;
- }
-
- private bool? AnalyzeIdetResult(string line)
- {
- // As you can see, the filter only guessed one frame as progressive.
- // Results like this are pretty typical. So if less than 30% of the detections are in the "Undetermined" category, then I only consider the video to be interlaced if at least 65% of the identified frames are in either the TFF or BFF category.
- // In this case (310 + 311)/(622) = 99.8% which is well over the 65% metric. I may refine that number with more testing but I honestly do not believe I will need to.
- // http://awel.domblogger.net/videoTranscode/interlace.html
- var index = line.IndexOf("detection:", StringComparison.OrdinalIgnoreCase);
-
- if (index == -1)
- {
- return null;
- }
-
- line = line.Substring(index).Trim();
- var parts = line.Split(' ').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => i.Trim()).ToList();
-
- if (parts.Count < 2)
- {
- return null;
- }
- double tff = 0;
- double bff = 0;
- double progressive = 0;
- double undetermined = 0;
- double total = 0;
-
- for (var i = 0; i < parts.Count - 1; i++)
- {
- var part = parts[i];
-
- if (string.Equals(part, "tff:", StringComparison.OrdinalIgnoreCase))
- {
- tff = GetNextPart(parts, i);
- total += tff;
- }
- else if (string.Equals(part, "bff:", StringComparison.OrdinalIgnoreCase))
- {
- bff = GetNextPart(parts, i);
- total += tff;
- }
- else if (string.Equals(part, "progressive:", StringComparison.OrdinalIgnoreCase))
- {
- progressive = GetNextPart(parts, i);
- total += progressive;
- }
- else if (string.Equals(part, "undetermined:", StringComparison.OrdinalIgnoreCase))
- {
- undetermined = GetNextPart(parts, i);
- total += undetermined;
- }
- }
-
- if (total == 0)
- {
- return null;
- }
-
- if ((undetermined / total) >= .3)
- {
- return false;
- }
-
- if (((tff + bff) / total) >= .4)
- {
- return true;
- }
-
return false;
}
- private int GetNextPart(List<string> parts, int index)
- {
- var next = parts[index + 1];
-
- int value;
- if (int.TryParse(next, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
- {
- return value;
- }
- return 0;
- }
-
/// <summary>
/// The us culture
/// </summary>
diff --git a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs
index f32dd178f..eef273250 100644
--- a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs
+++ b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs
@@ -264,6 +264,8 @@ namespace MediaBrowser.MediaEncoding.Probing
/// <value>The loro_surmixlev.</value>
public string loro_surmixlev { get; set; }
+ public string field_order { get; set; }
+
/// <summary>
/// Gets or sets the disposition.
/// </summary>
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 7927ddb6a..8b20dca1b 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -508,6 +508,11 @@ namespace MediaBrowser.MediaEncoding.Probing
stream.IsAVC = false;
}
+ if (!string.IsNullOrWhiteSpace(streamInfo.field_order) && !string.Equals(streamInfo.field_order, "progressive", StringComparison.OrdinalIgnoreCase))
+ {
+ stream.IsInterlaced = true;
+ }
+
// Filter out junk
if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1)
{
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 6a0fdede3..91ea977f7 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -34,7 +34,7 @@ namespace MediaBrowser.Model.LiveTv
TunerHosts = new List<TunerHostInfo>();
ListingProviders = new List<ListingsProviderInfo>();
MediaLocationsCreated = new string[] { };
- RecordingEncodingFormat = "mp4";
+ RecordingEncodingFormat = "mkv";
RecordingPostProcessorArguments = "\"{path}\"";
EnableRecordingEncoding = true;
}
diff --git a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
index 4d9f3e7c4..bb67a9e36 100644
--- a/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
+++ b/MediaBrowser.Server.Mac/Emby.Server.Mac.csproj
@@ -386,14 +386,8 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvstatus.html">
<Link>Resources\dashboard-ui\livetvstatus.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvtunerprovider-hdhomerun.html">
- <Link>Resources\dashboard-ui\livetvtunerprovider-hdhomerun.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvtunerprovider-m3u.html">
- <Link>Resources\dashboard-ui\livetvtunerprovider-m3u.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvtunerprovider-satip.html">
- <Link>Resources\dashboard-ui\livetvtunerprovider-satip.html</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\livetvtuner.html">
+ <Link>Resources\dashboard-ui\livetvtuner.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\log.html">
<Link>Resources\dashboard-ui\log.html</Link>
@@ -560,12 +554,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\wizardlibrary.html">
<Link>Resources\dashboard-ui\wizardlibrary.html</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\wizardlivetvguide.html">
- <Link>Resources\dashboard-ui\wizardlivetvguide.html</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\wizardlivetvtuner.html">
- <Link>Resources\dashboard-ui\wizardlivetvtuner.html</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\wizardsettings.html">
<Link>Resources\dashboard-ui\wizardsettings.html</Link>
</BundleResource>
@@ -800,6 +788,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\shortcuts.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\shortcuts.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\staticbackdrops.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\staticbackdrops.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\thememediaplayer.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\thememediaplayer.js</Link>
</BundleResource>
@@ -1253,6 +1244,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\empty.png">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\empty.png</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingbutton.js">
+ <Link>Resources\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingbutton.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingcreator.css">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\recordingcreator\recordingcreator.css</Link>
</BundleResource>
@@ -1736,9 +1730,15 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\iap.js">
<Link>Resources\dashboard-ui\components\iap.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\maintabsmanager.js">
+ <Link>Resources\dashboard-ui\components\maintabsmanager.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\remotecontrol.js">
<Link>Resources\dashboard-ui\components\remotecontrol.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\tunerpicker.js">
+ <Link>Resources\dashboard-ui\components\tunerpicker.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\viewcontainer-lite.js">
<Link>Resources\dashboard-ui\components\viewcontainer-lite.js</Link>
</BundleResource>
@@ -2141,8 +2141,8 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\librarysettings.js">
<Link>Resources\dashboard-ui\dashboard\librarysettings.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\livetvtunerprovider-satip.js">
- <Link>Resources\dashboard-ui\dashboard\livetvtunerprovider-satip.js</Link>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\livetvtuner.js">
+ <Link>Resources\dashboard-ui\dashboard\livetvtuner.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\logpage.js">
<Link>Resources\dashboard-ui\dashboard\logpage.js</Link>
@@ -2171,6 +2171,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\legacy\selectmenu.js">
<Link>Resources\dashboard-ui\legacy\selectmenu.js</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\offline\offline.html">
+ <Link>Resources\dashboard-ui\offline\offline.html</Link>
+ </BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\offline\offline.js">
+ <Link>Resources\dashboard-ui\offline\offline.js</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\addpluginpage.js">
<Link>Resources\dashboard-ui\scripts\addpluginpage.js</Link>
</BundleResource>
@@ -2189,9 +2195,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\channels.js">
<Link>Resources\dashboard-ui\scripts\channels.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\channelslatest.js">
- <Link>Resources\dashboard-ui\scripts\channelslatest.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\connectlogin.js">
<Link>Resources\dashboard-ui\scripts\connectlogin.js</Link>
</BundleResource>
@@ -2306,12 +2309,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvsuggested.js">
<Link>Resources\dashboard-ui\scripts\livetvsuggested.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvtunerprovider-hdhomerun.js">
- <Link>Resources\dashboard-ui\scripts\livetvtunerprovider-hdhomerun.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvtunerprovider-m3u.js">
- <Link>Resources\dashboard-ui\scripts\livetvtunerprovider-m3u.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\localsync.js">
<Link>Resources\dashboard-ui\scripts\localsync.js</Link>
</BundleResource>
@@ -2516,12 +2513,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardcontroller.js">
<Link>Resources\dashboard-ui\scripts\wizardcontroller.js</Link>
</BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardlivetvguide.js">
- <Link>Resources\dashboard-ui\scripts\wizardlivetvguide.js</Link>
- </BundleResource>
- <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardlivetvtuner.js">
- <Link>Resources\dashboard-ui\scripts\wizardlivetvtuner.js</Link>
- </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardsettings.js">
<Link>Resources\dashboard-ui\scripts\wizardsettings.js</Link>
</BundleResource>
@@ -2576,6 +2567,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\es.json">
<Link>Resources\dashboard-ui\strings\es.json</Link>
</BundleResource>
+ <BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\fa.json">
+ <Link>Resources\dashboard-ui\strings\fa.json</Link>
+ </BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\strings\fi.json">
<Link>Resources\dashboard-ui\strings\fi.json</Link>
</BundleResource>
diff --git a/MediaBrowser.Server.Mac/MacAppHost.cs b/MediaBrowser.Server.Mac/MacAppHost.cs
index f84e96126..304472529 100644
--- a/MediaBrowser.Server.Mac/MacAppHost.cs
+++ b/MediaBrowser.Server.Mac/MacAppHost.cs
@@ -87,10 +87,6 @@ namespace MediaBrowser.Server.Mac
throw new NotImplementedException();
}
- protected override void EnableLoopbackInternal(string appName)
- {
- }
-
public override bool SupportsRunningAsService
{
get
diff --git a/MediaBrowser.Server.Mac/Native/MonoFileSystem.cs b/MediaBrowser.Server.Mac/Native/MonoFileSystem.cs
index daf2b90e6..7aeff5ac8 100644
--- a/MediaBrowser.Server.Mac/Native/MonoFileSystem.cs
+++ b/MediaBrowser.Server.Mac/Native/MonoFileSystem.cs
@@ -1,13 +1,14 @@
using Emby.Common.Implementations.IO;
using MediaBrowser.Model.Logging;
using Mono.Unix.Native;
+using MediaBrowser.Model.System;
namespace Emby.Server.Mac.Native
{
public class MonoFileSystem : ManagedFileSystem
{
- public MonoFileSystem(ILogger logger, bool supportsAsyncFileStreams, bool enableManagedInvalidFileNameChars, string tempPath)
- : base(logger, supportsAsyncFileStreams, enableManagedInvalidFileNameChars, true, tempPath)
+ public MonoFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, string tempPath)
+ : base(logger, environmentInfo, tempPath)
{
}
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 4bb1f4610..33259a0bc 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,3 +1,3 @@
using System.Reflection;
-[assembly: AssemblyVersion("3.2.8.12")]
+[assembly: AssemblyVersion("3.2.8.13")]