aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/LiveTv
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2016-10-09 03:18:43 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2016-10-09 03:18:43 -0400
commitdaaae69df575f1d7692ba29d6f5ddd4c59516f82 (patch)
tree24c818ece042d36808fd0a68834b2853bf4512e1 /MediaBrowser.Server.Implementations/LiveTv
parentb3595eab6a94fda4f81f637007b2ac79e8a85065 (diff)
add playback of in-progress recordings
Diffstat (limited to 'MediaBrowser.Server.Implementations/LiveTv')
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs104
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs29
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs43
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs4
4 files changed, 154 insertions, 26 deletions
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 23066149a..ee8d40797 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -28,6 +28,7 @@ using System.Threading.Tasks;
using System.Xml;
using CommonIO;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Configuration;
@@ -38,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
public class EmbyTV : ILiveTvService, ISupportsDirectStreamProvider, ISupportsNewTimerIds, IDisposable
{
- private readonly IApplicationHost _appHpst;
+ private readonly IServerApplicationHost _appHost;
private readonly ILogger _logger;
private readonly IHttpClient _httpClient;
private readonly IServerConfigurationManager _config;
@@ -64,11 +65,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
- public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
+ public EmbyTV(IServerApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
{
Current = this;
- _appHpst = appHost;
+ _appHost = appHost;
_logger = logger;
_httpClient = httpClient;
_config = config;
@@ -293,7 +294,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
status.Tuners = list;
status.Status = LiveTvServiceStatus.Ok;
- status.Version = _appHpst.ApplicationVersion.ToString();
+ status.Version = _appHost.ApplicationVersion.ToString();
status.IsVisible = false;
return status;
}
@@ -659,7 +660,63 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public async Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken)
{
- return new List<RecordingInfo>();
+ return _activeRecordings.Values.ToList().Select(GetRecordingInfo).ToList();
+ }
+
+ public string GetActiveRecordingPath(string id)
+ {
+ ActiveRecordingInfo info;
+
+ if (_activeRecordings.TryGetValue(id, out info))
+ {
+ return info.Path;
+ }
+ return null;
+ }
+
+ private RecordingInfo GetRecordingInfo(ActiveRecordingInfo info)
+ {
+ var timer = info.Timer;
+ var program = info.Program;
+
+ var result = new RecordingInfo
+ {
+ ChannelId = timer.ChannelId,
+ CommunityRating = timer.CommunityRating,
+ DateLastUpdated = DateTime.UtcNow,
+ EndDate = timer.EndDate,
+ EpisodeTitle = timer.EpisodeTitle,
+ Genres = timer.Genres,
+ Id = "recording" + timer.Id,
+ IsKids = timer.IsKids,
+ IsMovie = timer.IsMovie,
+ IsNews = timer.IsNews,
+ IsRepeat = timer.IsRepeat,
+ IsSeries = timer.IsProgramSeries,
+ IsSports = timer.IsSports,
+ Name = timer.Name,
+ OfficialRating = timer.OfficialRating,
+ OriginalAirDate = timer.OriginalAirDate,
+ Overview = timer.Overview,
+ ProgramId = timer.ProgramId,
+ SeriesTimerId = timer.SeriesTimerId,
+ StartDate = timer.StartDate,
+ Status = RecordingStatus.InProgress,
+ TimerId = timer.Id
+ };
+
+ if (program != null)
+ {
+ result.Audio = program.Audio;
+ result.ImagePath = program.ImagePath;
+ result.ImageUrl = program.ImageUrl;
+ result.IsHD = program.IsHD;
+ result.IsLive = program.IsLive;
+ result.IsPremiere = program.IsPremiere;
+ result.ShowId = program.ShowId;
+ }
+
+ return result;
}
public Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken)
@@ -954,7 +1011,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
{
- throw new NotImplementedException();
+ ActiveRecordingInfo info;
+
+ recordingId = recordingId.Replace("recording", string.Empty);
+
+ if (_activeRecordings.TryGetValue(recordingId, out info))
+ {
+ return Task.FromResult(new List<MediaSourceInfo>
+ {
+ new MediaSourceInfo
+ {
+ Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
+ Id = recordingId,
+ SupportsDirectPlay = false,
+ SupportsDirectStream = true,
+ SupportsTranscoding = true,
+ IsInfiniteStream = true,
+ RequiresOpening = false,
+ RequiresClosing = false,
+ Protocol = Model.MediaInfo.MediaProtocol.Http,
+ BufferMs = 0
+ }
+ });
+ }
+
+ throw new FileNotFoundException();
}
public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
@@ -1031,7 +1112,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
var activeRecordingInfo = new ActiveRecordingInfo
{
CancellationTokenSource = new CancellationTokenSource(),
- TimerId = timer.Id
+ Timer = timer
};
if (_activeRecordings.TryAdd(timer.Id, activeRecordingInfo))
@@ -1168,6 +1249,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
if (programInfo != null)
{
RecordingHelper.CopyProgramInfoToTimerInfo(programInfo, timer);
+ activeRecordingInfo.Program = programInfo;
}
string seriesPath = null;
@@ -1394,7 +1476,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
return true;
}
- var hasRecordingAtPath = _activeRecordings.Values.ToList().Any(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) && !string.Equals(i.TimerId, timerId, StringComparison.OrdinalIgnoreCase));
+ var hasRecordingAtPath = _activeRecordings
+ .Values
+ .ToList()
+ .Any(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) && !string.Equals(i.Timer.Id, timerId, StringComparison.OrdinalIgnoreCase));
if (hasRecordingAtPath)
{
@@ -1878,7 +1963,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
class ActiveRecordingInfo
{
public string Path { get; set; }
- public string TimerId { get; set; }
+ public TimerInfo Timer { get; set; }
+ public ProgramInfo Program { get; set; }
public CancellationTokenSource CancellationTokenSource { get; set; }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 2189cf627..8c46b4597 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -10,6 +10,7 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -125,6 +126,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv
dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days);
+ if (!string.IsNullOrWhiteSpace(info.SeriesId))
+ {
+ var program = _libraryManager.GetItemList(new InternalItemsQuery
+ {
+ IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
+ ExternalSeriesId = info.SeriesId,
+ Limit = 1,
+ ImageTypes = new ImageType[] { ImageType.Primary }
+
+ }).FirstOrDefault();
+
+ if (program != null)
+ {
+ var image = program.GetImageInfo(ImageType.Primary, 0);
+ if (image != null)
+ {
+ try
+ {
+ dto.ParentPrimaryImageTag = _imageProcessor.GetImageCacheTag(program, image);
+ dto.ParentPrimaryImageItemId = program.Id.ToString("N");
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ }
+ }
+
return dto;
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 93d8f8ef4..cf441f58e 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -235,20 +235,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return await GetLiveStream(id, mediaSourceId, true, cancellationToken).ConfigureAwait(false);
}
- public async Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(string id, CancellationToken cancellationToken)
+ public async Task<IEnumerable<MediaSourceInfo>> GetRecordingMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
{
- var item = await GetInternalRecording(id, cancellationToken).ConfigureAwait(false);
- var service = GetService(item);
+ var baseItem = (BaseItem)item;
+ var service = GetService(baseItem);
- return await service.GetRecordingStreamMediaSources(id, cancellationToken).ConfigureAwait(false);
+ return await service.GetRecordingStreamMediaSources(baseItem.ExternalId, cancellationToken).ConfigureAwait(false);
}
- public async Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(string id, CancellationToken cancellationToken)
+ public async Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
{
- var item = GetInternalChannel(id);
- var service = GetService(item);
+ var baseItem = (LiveTvChannel)item;
+ var service = GetService(baseItem);
- var sources = await service.GetChannelStreamMediaSources(item.ExternalId, cancellationToken).ConfigureAwait(false);
+ var sources = await service.GetChannelStreamMediaSources(baseItem.ExternalId, cancellationToken).ConfigureAwait(false);
if (sources.Count == 0)
{
@@ -259,7 +259,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
foreach (var source in list)
{
- Normalize(source, service, item.ChannelType == ChannelType.TV);
+ Normalize(source, service, baseItem.ChannelType == ChannelType.TV);
}
return list;
@@ -738,6 +738,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
recording.IsRepeat = info.IsRepeat;
recording.IsSports = info.IsSports;
recording.SeriesTimerId = info.SeriesTimerId;
+ recording.TimerId = info.TimerId;
recording.StartDate = info.StartDate;
if (!dataChanged)
@@ -1083,10 +1084,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
if (timer != null)
{
- program.TimerId = _tvDtoService.GetInternalTimerId(serviceName, timer.Id)
- .ToString("N");
+ if (timer.Status != RecordingStatus.Cancelled && timer.Status != RecordingStatus.Error)
+ {
+ program.TimerId = _tvDtoService.GetInternalTimerId(serviceName, timer.Id)
+ .ToString("N");
- program.TimerStatus = timer.Status;
+ program.Status = timer.Status.ToString();
+ }
if (!string.IsNullOrEmpty(timer.SeriesTimerId))
{
@@ -1432,7 +1436,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private DateTime _lastRecordingRefreshTime;
private async Task RefreshRecordings(CancellationToken cancellationToken)
{
- const int cacheMinutes = 5;
+ const int cacheMinutes = 3;
if ((DateTime.UtcNow - _lastRecordingRefreshTime).TotalMinutes < cacheMinutes)
{
@@ -1482,7 +1486,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
private QueryResult<BaseItem> GetEmbyRecordings(RecordingQuery query, DtoOptions dtoOptions, User user)
{
- if (user == null || (query.IsInProgress ?? false))
+ if (user == null)
+ {
+ return new QueryResult<BaseItem>();
+ }
+
+ if ((query.IsInProgress ?? false))
{
return new QueryResult<BaseItem>();
}
@@ -1628,7 +1637,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
return new QueryResult<BaseItem>();
}
- if (_services.Count == 1)
+ if (_services.Count == 1 && !(query.IsInProgress ?? false))
{
return GetEmbyRecordings(query, new DtoOptions(), user);
}
@@ -1824,6 +1833,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
? null
: _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N");
+ dto.TimerId = string.IsNullOrEmpty(info.TimerId)
+ ? null
+ : _tvDtoService.GetInternalTimerId(service.Name, info.TimerId).ToString("N");
+
dto.StartDate = info.StartDate;
dto.RecordingStatus = info.Status;
dto.IsRepeat = info.IsRepeat;
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index ff9b2a143..521f33e1c 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -65,12 +65,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
if (item is ILiveTvRecording)
{
- sources = await _liveTvManager.GetRecordingMediaSources(item.Id.ToString("N"), cancellationToken)
+ sources = await _liveTvManager.GetRecordingMediaSources(item, cancellationToken)
.ConfigureAwait(false);
}
else
{
- sources = await _liveTvManager.GetChannelMediaSources(item.Id.ToString("N"), cancellationToken)
+ sources = await _liveTvManager.GetChannelMediaSources(item, cancellationToken)
.ConfigureAwait(false);
}
}