aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/LiveTv
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations/LiveTv')
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs184
1 files changed, 123 insertions, 61 deletions
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 777a8936b9..2bc6cbadfe 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common;
+using System.Globalization;
+using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
@@ -14,6 +15,7 @@ using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
@@ -304,12 +306,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
- public async Task<ChannelMediaInfo> GetRecordingStream(string id, CancellationToken cancellationToken)
+ public async Task<MediaSourceInfo> GetRecordingStream(string id, CancellationToken cancellationToken)
{
return await GetLiveStream(id, false, cancellationToken).ConfigureAwait(false);
}
- public async Task<ChannelMediaInfo> GetChannelStream(string id, CancellationToken cancellationToken)
+ public async Task<MediaSourceInfo> GetChannelStream(string id, CancellationToken cancellationToken)
{
return await GetLiveStream(id, true, cancellationToken).ConfigureAwait(false);
}
@@ -324,20 +326,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return _services.FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
}
- private async Task<ChannelMediaInfo> GetLiveStream(string id, bool isChannel, CancellationToken cancellationToken)
+ private async Task<MediaSourceInfo> GetLiveStream(string id, bool isChannel, CancellationToken cancellationToken)
{
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
- ChannelMediaInfo info;
+ MediaSourceInfo info;
if (isChannel)
{
var channel = GetInternalChannel(id);
var service = GetService(channel);
_logger.Info("Opening channel stream from {0}, external channel Id: {1}", service.Name, channel.ExternalId);
- info = await service.GetChannelStream(channel.ExternalId, cancellationToken).ConfigureAwait(false);
+ info = await service.GetChannelStream(channel.ExternalId, null, cancellationToken).ConfigureAwait(false);
}
else
{
@@ -345,7 +347,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = GetService(recording);
_logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.RecordingInfo.Id);
- info = await service.GetRecordingStream(recording.RecordingInfo.Id, cancellationToken).ConfigureAwait(false);
+ info = await service.GetRecordingStream(recording.RecordingInfo.Id, null, cancellationToken).ConfigureAwait(false);
}
_logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info));
@@ -375,41 +377,73 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
}
- private void Sanitize(ChannelMediaInfo info)
+ private void Sanitize(MediaSourceInfo mediaSource)
{
- // Clean some bad data coming from providers
-
- if (info.AudioBitrate.HasValue && info.AudioBitrate <= 0)
- {
- info.AudioBitrate = null;
- }
- if (info.VideoBitrate.HasValue && info.VideoBitrate <= 0)
- {
- info.VideoBitrate = null;
- }
- if (info.AudioChannels.HasValue && info.AudioChannels <= 0)
- {
- info.AudioChannels = null;
- }
- if (info.Framerate.HasValue && info.Framerate <= 0)
- {
- info.Framerate = null;
- }
- if (info.Width.HasValue && info.Width <= 0)
- {
- info.Width = null;
- }
- if (info.Height.HasValue && info.Height <= 0)
+ if (mediaSource.MediaStreams.Count == 0)
{
- info.Height = null;
+ mediaSource.MediaStreams.AddRange(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
+ },
+ 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
+ }
+ });
}
- if (info.AudioSampleRate.HasValue && info.AudioSampleRate <= 0)
+
+ // Clean some bad data coming from providers
+ foreach (var stream in mediaSource.MediaStreams)
{
- info.AudioSampleRate = null;
+ if (stream.BitRate.HasValue && stream.BitRate <= 0)
+ {
+ stream.BitRate = null;
+ }
+ if (stream.Channels.HasValue && stream.Channels <= 0)
+ {
+ stream.Channels = null;
+ }
+ if (stream.AverageFrameRate.HasValue && stream.AverageFrameRate <= 0)
+ {
+ stream.AverageFrameRate = null;
+ }
+ if (stream.RealFrameRate.HasValue && stream.RealFrameRate <= 0)
+ {
+ stream.RealFrameRate = null;
+ }
+ if (stream.Width.HasValue && stream.Width <= 0)
+ {
+ stream.Width = null;
+ }
+ if (stream.Height.HasValue && stream.Height <= 0)
+ {
+ stream.Height = null;
+ }
+ if (stream.SampleRate.HasValue && stream.SampleRate <= 0)
+ {
+ stream.SampleRate = null;
+ }
+ if (stream.Level.HasValue && stream.Level <= 0)
+ {
+ stream.Level = null;
+ }
}
- if (info.VideoLevel.HasValue && info.VideoLevel <= 0)
+
+ var indexes = mediaSource.MediaStreams.Select(i => i.Index).Distinct().ToList();
+
+ // If there are duplicate stream indexes, set them all to unknown
+ if (indexes.Count != mediaSource.MediaStreams.Count)
{
- info.VideoLevel = null;
+ foreach (var stream in mediaSource.MediaStreams)
+ {
+ stream.Index = -1;
+ }
}
}
@@ -1077,13 +1111,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var numComplete = 0;
- foreach (var program in list)
+ foreach (var programId in list)
{
cancellationToken.ThrowIfCancellationRequested();
- if (!currentIdList.Contains(program.Id))
+ if (!currentIdList.Contains(programId))
{
- await _libraryManager.DeleteItem(program).ConfigureAwait(false);
+ var program = _libraryManager.GetItemById(programId);
+
+ if (program != null)
+ {
+ await _libraryManager.DeleteItem(program).ConfigureAwait(false);
+ }
}
numComplete++;
@@ -1250,36 +1289,47 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken)
{
- var service = ActiveService;
- var timers = await service.GetTimersAsync(cancellationToken).ConfigureAwait(false);
+ var tasks = _services.Select(async i =>
+ {
+ try
+ {
+ var recs = await i.GetTimersAsync(cancellationToken).ConfigureAwait(false);
+ return recs.Select(r => new Tuple<TimerInfo, ILiveTvService>(r, i));
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting recordings", ex);
+ return new List<Tuple<TimerInfo, ILiveTvService>>();
+ }
+ });
+ var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+ var timers = results.SelectMany(i => i.ToList());
if (!string.IsNullOrEmpty(query.ChannelId))
{
var guid = new Guid(query.ChannelId);
- timers = timers.Where(i => guid == _tvDtoService.GetInternalChannelId(service.Name, i.ChannelId));
+ timers = timers.Where(i => guid == _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId));
}
if (!string.IsNullOrEmpty(query.SeriesTimerId))
{
var guid = new Guid(query.SeriesTimerId);
- var currentServiceName = service.Name;
-
timers = timers
- .Where(i => _tvDtoService.GetInternalSeriesTimerId(currentServiceName, i.SeriesTimerId) == guid);
+ .Where(i => _tvDtoService.GetInternalSeriesTimerId(i.Item2.Name, i.Item1.SeriesTimerId) == guid);
}
var returnList = new List<TimerInfoDto>();
foreach (var i in timers)
{
- var program = string.IsNullOrEmpty(i.ProgramId) ?
+ var program = string.IsNullOrEmpty(i.Item1.ProgramId) ?
null :
- GetInternalProgram(_tvDtoService.GetInternalProgramId(service.Name, i.ProgramId).ToString("N"));
+ GetInternalProgram(_tvDtoService.GetInternalProgramId(i.Item2.Name, i.Item1.ProgramId).ToString("N"));
- var channel = string.IsNullOrEmpty(i.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, i.ChannelId));
+ var channel = string.IsNullOrEmpty(i.Item1.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId));
- returnList.Add(_tvDtoService.GetTimerInfoDto(i, service, program, channel));
+ returnList.Add(_tvDtoService.GetTimerInfoDto(i.Item1, i.Item2, program, channel));
}
var returnArray = returnList
@@ -1363,21 +1413,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<QueryResult<SeriesTimerInfoDto>> GetSeriesTimers(SeriesTimerQuery query, CancellationToken cancellationToken)
{
- var service = ActiveService;
-
- var timers = await service.GetSeriesTimersAsync(cancellationToken).ConfigureAwait(false);
+ var tasks = _services.Select(async i =>
+ {
+ try
+ {
+ var recs = await i.GetSeriesTimersAsync(cancellationToken).ConfigureAwait(false);
+ return recs.Select(r => new Tuple<SeriesTimerInfo, ILiveTvService>(r, i));
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting recordings", ex);
+ return new List<Tuple<SeriesTimerInfo, ILiveTvService>>();
+ }
+ });
+ var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+ var timers = results.SelectMany(i => i.ToList());
if (string.Equals(query.SortBy, "Priority", StringComparison.OrdinalIgnoreCase))
{
timers = query.SortOrder == SortOrder.Descending ?
- timers.OrderBy(i => i.Priority).ThenByStringDescending(i => i.Name) :
- timers.OrderByDescending(i => i.Priority).ThenByString(i => i.Name);
+ timers.OrderBy(i => i.Item1.Priority).ThenByStringDescending(i => i.Item1.Name) :
+ timers.OrderByDescending(i => i.Item1.Priority).ThenByString(i => i.Item1.Name);
}
else
{
timers = query.SortOrder == SortOrder.Descending ?
- timers.OrderByStringDescending(i => i.Name) :
- timers.OrderByString(i => i.Name);
+ timers.OrderByStringDescending(i => i.Item1.Name) :
+ timers.OrderByString(i => i.Item1.Name);
}
var returnArray = timers
@@ -1385,14 +1447,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
string channelName = null;
- if (!string.IsNullOrEmpty(i.ChannelId))
+ if (!string.IsNullOrEmpty(i.Item1.ChannelId))
{
- var internalChannelId = _tvDtoService.GetInternalChannelId(service.Name, i.ChannelId);
+ var internalChannelId = _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId);
var channel = GetInternalChannel(internalChannelId);
channelName = channel == null ? null : channel.Name;
}
- return _tvDtoService.GetSeriesTimerInfoDto(i, service, channelName);
+ return _tvDtoService.GetSeriesTimerInfoDto(i.Item1, i.Item2, channelName);
})
.ToArray();
@@ -1433,7 +1495,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return program;
}
- private async Task<Tuple<SeriesTimerInfo,ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
+ private async Task<Tuple<SeriesTimerInfo, ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
{
var service = program != null && !string.IsNullOrWhiteSpace(program.ServiceName) ?
GetService(program) :
@@ -1679,7 +1741,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
class LiveStreamData
{
- internal ChannelMediaInfo Info;
+ internal MediaSourceInfo Info;
internal int ConsumerCount;
internal string ItemId;
internal bool IsChannel;