|  | @@ -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; }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 |