Merge pull request #2436 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2017-02-01 15:57:05 -05:00 committed by GitHub
commit 7ab5db614f
15 changed files with 90 additions and 70 deletions

View File

@ -309,8 +309,8 @@
<Project>{4f26d5d8-a7b0-42b3-ba42-7cb7d245934e}</Project> <Project>{4f26d5d8-a7b0-42b3-ba42-7cb7d245934e}</Project>
<Name>SocketHttpListener.Portable</Name> <Name>SocketHttpListener.Portable</Name>
</ProjectReference> </ProjectReference>
<Reference Include="Emby.XmlTv, Version=1.0.6236.39295, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Emby.XmlTv, Version=1.0.6241.4924, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Emby.XmlTv.1.0.4\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath> <HintPath>..\packages\Emby.XmlTv.1.0.5\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="MediaBrowser.Naming, Version=1.0.6201.24431, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="MediaBrowser.Naming, Version=1.0.6201.24431, Culture=neutral, processorArchitecture=MSIL">

View File

@ -64,6 +64,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
episode.SeasonId = season.Id; episode.SeasonId = season.Id;
episode.SeasonName = season.Name; episode.SeasonName = season.Name;
} }
// Assume season 1 if there's no season folder and a season number could not be determined
if (season == null && !episode.ParentIndexNumber.HasValue && (episode.IndexNumber.HasValue || episode.PremiereDate.HasValue))
{
episode.ParentIndexNumber = 1;
}
} }
return episode; return episode;

View File

@ -176,7 +176,7 @@ namespace Emby.Server.Implementations.Library
return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2); return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2);
})); }));
var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).Select(i => new SearchHintInfo var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).ThenBy(i => i.Item1.SortName).Select(i => new SearchHintInfo
{ {
Item = i.Item1, Item = i.Item1,
MatchedTerm = i.Item2 MatchedTerm = i.Item2

View File

@ -847,6 +847,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var channelMappings = GetChannelMappings(provider.Item2); var channelMappings = GetChannelMappings(provider.Item2);
var channelNumber = channel.Number; var channelNumber = channel.Number;
var tunerChannelId = channel.TunerChannelId;
if (!string.IsNullOrWhiteSpace(channelNumber)) if (!string.IsNullOrWhiteSpace(channelNumber))
{ {
@ -858,7 +859,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
} }
} }
var programs = await provider.Item1.GetProgramsAsync(provider.Item2, channelNumber, channel.Name, startDateUtc, endDateUtc, cancellationToken) var programs = await provider.Item1.GetProgramsAsync(provider.Item2, tunerChannelId, channelNumber, channel.Name, startDateUtc, endDateUtc, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
var list = programs.ToList(); var list = programs.ToList();

View File

@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return dates; return dates;
} }
public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{ {
List<ProgramInfo> programsInfo = new List<ProgramInfo>(); List<ProgramInfo> programsInfo = new List<ProgramInfo>();

View File

@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return cacheFile; return cacheFile;
} }
public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
{ {
if (!await EmbyTV.EmbyTVRegistration.Instance.EnableXmlTv().ConfigureAwait(false)) if (!await EmbyTV.EmbyTVRegistration.Instance.EnableXmlTv().ConfigureAwait(false))
{ {
@ -161,8 +161,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
} }
else else
{ {
var uniqueString = (p.Title ?? string.Empty) + (episodeTitle ?? string.Empty); var uniqueString = (p.Title ?? string.Empty) + (episodeTitle ?? string.Empty) + (p.IceTvEpisodeNumber ?? string.Empty);
if (programInfo.SeasonNumber.HasValue)
{
uniqueString = "-" + programInfo.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture);
}
if (programInfo.EpisodeNumber.HasValue) if (programInfo.EpisodeNumber.HasValue)
{ {
uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture); uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture);

View File

@ -76,6 +76,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var channels = new List<M3UChannel>(); var channels = new List<M3UChannel>();
string line; string line;
string extInf = ""; string extInf = "";
while ((line = reader.ReadLine()) != null) while ((line = reader.ReadLine()) != null)
{ {
line = line.Trim(); line = line.Trim();
@ -111,6 +112,18 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
extInf = ""; extInf = "";
} }
} }
var startingNumber = 1;
foreach (var channel in channels)
{
if (!string.IsNullOrWhiteSpace(channel.Number))
{
continue;
}
channel.Number = startingNumber.ToString(CultureInfo.InvariantCulture);
startingNumber++;
}
return channels; return channels;
} }
@ -137,6 +150,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
if (attributes.TryGetValue("tvg-id", out value)) if (attributes.TryGetValue("tvg-id", out value))
{ {
channel.Id = value; channel.Id = value;
channel.TunerChannelId = value;
} }
return channel; return channel;

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -11,10 +12,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{ {
public class MulticastStream public class MulticastStream
{ {
private readonly List<QueueStream> _outputStreams = new List<QueueStream>(); private readonly ConcurrentDictionary<Guid,QueueStream> _outputStreams = new ConcurrentDictionary<Guid, QueueStream>();
private const int BufferSize = 81920; private const int BufferSize = 81920;
private CancellationToken _cancellationToken; private CancellationToken _cancellationToken;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly ConcurrentQueue<byte[]> _sharedBuffer = new ConcurrentQueue<byte[]>();
public MulticastStream(ILogger logger) public MulticastStream(ILogger logger)
{ {
@ -36,16 +38,18 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
byte[] copy = new byte[bytesRead]; byte[] copy = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead); Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
List<QueueStream> streams = null; _sharedBuffer.Enqueue(copy);
lock (_outputStreams) while (_sharedBuffer.Count > 3000)
{ {
streams = _outputStreams.ToList(); byte[] bytes;
_sharedBuffer.TryDequeue(out bytes);
} }
foreach (var stream in streams) var allStreams = _outputStreams.ToList();
foreach (var stream in allStreams)
{ {
stream.Queue(copy); stream.Value.Queue(copy);
} }
if (onStarted != null) if (onStarted != null)
@ -70,11 +74,20 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
OnFinished = OnFinished OnFinished = OnFinished
}; };
lock (_outputStreams) var initial = _sharedBuffer.ToList();
var list = new List<byte>();
foreach (var bytes in initial)
{ {
_outputStreams.Add(result); list.AddRange(bytes);
} }
_logger.Info("QueueStream started with {0} initial bytes", list.Count);
result.Queue(list.ToArray());
_outputStreams.TryAdd(result.Id, result);
result.Start(_cancellationToken); result.Start(_cancellationToken);
return result.TaskCompletion.Task; return result.TaskCompletion.Task;
@ -82,10 +95,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public void RemoveOutputStream(QueueStream stream) public void RemoveOutputStream(QueueStream stream)
{ {
lock (_outputStreams) QueueStream removed;
{ _outputStreams.TryRemove(stream.Id, out removed);
_outputStreams.Remove(stream);
}
} }
private void OnFinished(QueueStream queueStream) private void OnFinished(QueueStream queueStream)

View File

@ -19,7 +19,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public Action<QueueStream> OnFinished { get; set; } public Action<QueueStream> OnFinished { get; set; }
private readonly ILogger _logger; private readonly ILogger _logger;
private bool _isActive; public Guid Id = Guid.NewGuid();
public QueueStream(Stream outputStream, ILogger logger) public QueueStream(Stream outputStream, ILogger logger)
{ {
@ -30,10 +30,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public void Queue(byte[] bytes) public void Queue(byte[] bytes)
{ {
if (_isActive) _queue.Enqueue(bytes);
{
_queue.Enqueue(bytes);
}
} }
public void Start(CancellationToken cancellationToken) public void Start(CancellationToken cancellationToken)
@ -59,10 +56,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
try try
{ {
while (!cancellationToken.IsCancellationRequested) while (true)
{ {
_isActive = true;
var bytes = Dequeue(); var bytes = Dequeue();
if (bytes != null) if (bytes != null)
{ {
@ -73,9 +68,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
await Task.Delay(50, cancellationToken).ConfigureAwait(false); await Task.Delay(50, cancellationToken).ConfigureAwait(false);
} }
} }
TaskCompletion.TrySetResult(true);
_logger.Debug("QueueStream complete");
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -89,8 +81,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
} }
finally finally
{ {
_isActive = false;
if (OnFinished != null) if (OnFinished != null)
{ {
OnFinished(this); OnFinished(this);

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Emby.XmlTv" version="1.0.4" targetFramework="portable45-net45+win8" /> <package id="Emby.XmlTv" version="1.0.5" targetFramework="portable45-net45+win8" />
<package id="MediaBrowser.Naming" version="1.0.4" targetFramework="portable45-net45+win8" /> <package id="MediaBrowser.Naming" version="1.0.4" targetFramework="portable45-net45+win8" />
<package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" /> <package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
<package id="SQLitePCLRaw.core" version="1.1.1" targetFramework="portable45-net45+win8" /> <package id="SQLitePCLRaw.core" version="1.1.1" targetFramework="portable45-net45+win8" />

View File

@ -23,8 +23,8 @@ namespace MediaBrowser.Api
/// <summary> /// <summary>
/// The _active connections /// The _active connections
/// </summary> /// </summary>
protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim>> ActiveConnections = protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>> ActiveConnections =
new List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim>>(); new List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>>();
/// <summary> /// <summary>
/// Gets the name. /// Gets the name.
@ -132,11 +132,9 @@ namespace MediaBrowser.Api
InitialDelayMs = dueTimeMs InitialDelayMs = dueTimeMs
}; };
var semaphore = new SemaphoreSlim(1, 1);
lock (ActiveConnections) lock (ActiveConnections)
{ {
ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim>(message.Connection, cancellationTokenSource, timer, state, semaphore)); ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>(message.Connection, cancellationTokenSource, timer, state));
} }
if (timer != null) if (timer != null)
@ -153,7 +151,7 @@ namespace MediaBrowser.Api
{ {
var connection = (IWebSocketConnection)state; var connection = (IWebSocketConnection)state;
Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim> tuple; Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> tuple;
lock (ActiveConnections) lock (ActiveConnections)
{ {
@ -176,7 +174,7 @@ namespace MediaBrowser.Api
protected void SendData(bool force) protected void SendData(bool force)
{ {
List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim>> tuples; List<Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType>> tuples;
lock (ActiveConnections) lock (ActiveConnections)
{ {
@ -204,14 +202,12 @@ namespace MediaBrowser.Api
} }
} }
private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim> tuple) private async void SendData(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> tuple)
{ {
var connection = tuple.Item1; var connection = tuple.Item1;
try try
{ {
await tuple.Item5.WaitAsync(tuple.Item2.Token).ConfigureAwait(false);
var state = tuple.Item4; var state = tuple.Item4;
var data = await GetDataToSend(state).ConfigureAwait(false); var data = await GetDataToSend(state).ConfigureAwait(false);
@ -227,8 +223,6 @@ namespace MediaBrowser.Api
state.DateLastSendUtc = DateTime.UtcNow; state.DateLastSendUtc = DateTime.UtcNow;
} }
tuple.Item5.Release();
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -265,7 +259,7 @@ namespace MediaBrowser.Api
/// Disposes the connection. /// Disposes the connection.
/// </summary> /// </summary>
/// <param name="connection">The connection.</param> /// <param name="connection">The connection.</param>
private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType, SemaphoreSlim> connection) private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, ITimer, TStateType> connection)
{ {
Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name);
@ -293,15 +287,6 @@ namespace MediaBrowser.Api
} }
try
{
connection.Item5.Dispose();
}
catch (ObjectDisposedException)
{
}
ActiveConnections.Remove(connection); ActiveConnections.Remove(connection);
} }

View File

@ -2720,6 +2720,15 @@ namespace MediaBrowser.Api.Playback
//inputModifier += " -noaccurate_seek"; //inputModifier += " -noaccurate_seek";
} }
if (!string.IsNullOrWhiteSpace(state.InputContainer))
{
var inputFormat = GetInputFormat(state.InputContainer);
if (!string.IsNullOrWhiteSpace(inputFormat))
{
inputModifier += " -f " + inputFormat;
}
}
if (state.RunTimeTicks.HasValue) if (state.RunTimeTicks.HasValue)
{ {
foreach (var stream in state.MediaSource.MediaStreams) foreach (var stream in state.MediaSource.MediaStreams)
@ -2738,23 +2747,21 @@ namespace MediaBrowser.Api.Playback
} }
} }
} }
//var videoStream = state.VideoStream;
//if (videoStream != null && !string.IsNullOrWhiteSpace(videoStream.Codec))
//{
// inputModifier += " -codec:0 " + videoStream.Codec;
// var audioStream = state.AudioStream;
// if (audioStream != null && !string.IsNullOrWhiteSpace(audioStream.Codec))
// {
// inputModifier += " -codec:1 " + audioStream.Codec;
// }
//}
} }
return inputModifier; return inputModifier;
} }
private string GetInputFormat(string container)
{
if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase))
{
return "matroska";
}
return container;
}
private string GetDecoderFromCodec(string codec) private string GetDecoderFromCodec(string codec)
{ {
return null; return null;

View File

@ -103,7 +103,7 @@ namespace MediaBrowser.Api.Playback.Hls
throw; throw;
} }
var waitForSegments = state.SegmentLength >= 10 ? 2 : 3; var waitForSegments = state.SegmentLength >= 10 ? 2 : 2;
await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false); await WaitForMinimumSegmentCount(playlist, waitForSegments, cancellationTokenSource.Token).ConfigureAwait(false);
} }
} }

View File

@ -25,6 +25,8 @@ namespace MediaBrowser.Controller.LiveTv
/// <value>The id of the channel.</value> /// <value>The id of the channel.</value>
public string Id { get; set; } public string Id { get; set; }
public string TunerChannelId { get; set; }
/// <summary> /// <summary>
/// Gets or sets the tuner host identifier. /// Gets or sets the tuner host identifier.
/// </summary> /// </summary>

View File

@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.LiveTv
{ {
string Name { get; } string Name { get; }
string Type { get; } string Type { get; }
Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken); Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, string channelNumber, string channelName, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken);
Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken); Task AddMetadata(ListingsProviderInfo info, List<ChannelInfo> channels, CancellationToken cancellationToken);
Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings); Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings);
Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location); Task<List<NameIdPair>> GetLineups(ListingsProviderInfo info, string country, string location);