diff options
| author | Luke <luke.pulverenti@gmail.com> | 2017-09-20 13:22:39 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-09-20 13:22:39 -0400 |
| commit | eb2a1330045d802bfe0366df7105c220a36f111f (patch) | |
| tree | 2c1638c424ee9c0837c5de6d6e08a2398da69cdb /Emby.Server.Implementations/LiveTv | |
| parent | ec426d5c92875639ceac64477ce10fab3e639335 (diff) | |
| parent | a015e1208885bc6a8788db683c4fe47e93dc26b7 (diff) | |
Merge pull request #2897 from MediaBrowser/beta
Beta
Diffstat (limited to 'Emby.Server.Implementations/LiveTv')
13 files changed, 328 insertions, 379 deletions
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 2a2e1886f..f0578d9ef 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -42,6 +42,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private async Task RecordFromDirectStreamProvider(IDirectStreamProvider directStreamProvider, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) { + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile)); + using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) { onStarted(); @@ -76,6 +78,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { _logger.Info("Opened recording stream from tuner provider"); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile)); + using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) { onStarted(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 2e12f46bf..1975a6b01 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -305,26 +305,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var seriesTimers = await GetSeriesTimersAsync(cancellationToken).ConfigureAwait(false); - List<ChannelInfo> channels = null; - foreach (var timer in seriesTimers) { - List<ProgramInfo> epgData; - - if (timer.RecordAnyChannel) - { - if (channels == null) - { - channels = (await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false)).ToList(); - } - var channelIds = channels.Select(i => i.Id).ToList(); - epgData = GetEpgDataForChannels(channelIds); - } - else - { - epgData = GetEpgDataForChannel(timer.ChannelId); - } - await UpdateTimersForSeriesTimer(epgData, timer, false, true).ConfigureAwait(false); + await UpdateTimersForSeriesTimer(timer, false, true).ConfigureAwait(false); } } @@ -332,6 +315,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var timers = await GetTimersAsync(cancellationToken).ConfigureAwait(false); + var tempChannelCache = new Dictionary<string, LiveTvChannel>(); + foreach (var timer in timers) { if (DateTime.UtcNow > timer.EndDate && !_activeRecordings.ContainsKey(timer.Id)) @@ -345,15 +330,14 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV continue; } - var epg = GetEpgDataForChannel(timer.ChannelId); - var program = epg.FirstOrDefault(i => string.Equals(i.Id, timer.ProgramId, StringComparison.OrdinalIgnoreCase)); + var program = GetProgramInfoFromCache(timer); if (program == null) { OnTimerOutOfDate(timer); continue; } - RecordingHelper.CopyProgramInfoToTimerInfo(program, timer); + CopyProgramInfoToTimerInfo(program, timer, tempChannelCache); _timerProvider.Update(timer); } } @@ -621,7 +605,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV ActiveRecordingInfo activeRecordingInfo; if (_activeRecordings.TryGetValue(timerId, out activeRecordingInfo)) - { + { activeRecordingInfo.Timer = timer; activeRecordingInfo.CancellationTokenSource.Cancel(); } @@ -672,11 +656,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV timer.Id = Guid.NewGuid().ToString("N"); - ProgramInfo programInfo = null; + LiveTvProgram programInfo = null; if (!string.IsNullOrWhiteSpace(timer.ProgramId)) { - programInfo = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId); + programInfo = GetProgramInfoFromCache(timer); } if (programInfo == null) { @@ -686,7 +670,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (programInfo != null) { - RecordingHelper.CopyProgramInfoToTimerInfo(programInfo, timer); + CopyProgramInfoToTimerInfo(programInfo, timer); } timer.IsManual = true; @@ -698,24 +682,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { info.Id = Guid.NewGuid().ToString("N"); - List<ProgramInfo> epgData; - if (info.RecordAnyChannel) - { - var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false); - var channelIds = channels.Select(i => i.Id).ToList(); - epgData = GetEpgDataForChannels(channelIds); - } - else - { - epgData = GetEpgDataForChannel(info.ChannelId); - } - // populate info.seriesID - var program = epgData.FirstOrDefault(i => string.Equals(i.Id, info.ProgramId, StringComparison.OrdinalIgnoreCase)); + var program = GetProgramInfoFromCache(info.ProgramId); if (program != null) { - info.SeriesId = program.SeriesId; + info.SeriesId = program.ExternalSeriesId; } else { @@ -750,7 +722,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _timerProvider.AddOrUpdate(timer, false); } - await UpdateTimersForSeriesTimer(epgData, info, true, false).ConfigureAwait(false); + await UpdateTimersForSeriesTimer(info, true, false).ConfigureAwait(false); return info.Id; } @@ -779,19 +751,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _seriesTimerProvider.Update(instance); - List<ProgramInfo> epgData; - if (instance.RecordAnyChannel) - { - var channels = await GetChannelsAsync(true, CancellationToken.None).ConfigureAwait(false); - var channelIds = channels.Select(i => i.Id).ToList(); - epgData = GetEpgDataForChannels(channelIds); - } - else - { - epgData = GetEpgDataForChannel(instance.ChannelId); - } - - await UpdateTimersForSeriesTimer(epgData, instance, true, true).ConfigureAwait(false); + await UpdateTimersForSeriesTimer(instance, true, true).ConfigureAwait(false); } } @@ -962,23 +922,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return Task.FromResult((IEnumerable<SeriesTimerInfo>)_seriesTimerProvider.GetAll()); } - public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) - { - try - { - return await GetProgramsAsyncInternal(channelId, startDateUtc, endDateUtc, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error getting programs", ex); - return GetEpgDataForChannel(channelId).Where(i => i.StartDate <= endDateUtc && i.EndDate >= startDateUtc); - } - } - private bool IsListingProviderEnabledForTuner(ListingsProviderInfo info, string tunerHostId) { if (info.EnableAllTuners) @@ -994,7 +937,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return info.EnabledTuners.Contains(tunerHostId, StringComparer.OrdinalIgnoreCase); } - private async Task<IEnumerable<ProgramInfo>> GetProgramsAsyncInternal(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) + public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { var channels = await GetChannelsAsync(true, cancellationToken).ConfigureAwait(false); var channel = channels.First(i => string.Equals(i.Id, channelId, StringComparison.OrdinalIgnoreCase)); @@ -1037,8 +980,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (programs.Count > 0) { - SaveEpgDataForChannel(channelId, programs); - return programs; } } @@ -1464,11 +1405,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV throw new ArgumentNullException("timer"); } - ProgramInfo programInfo = null; + LiveTvProgram programInfo = null; if (!string.IsNullOrWhiteSpace(timer.ProgramId)) { - programInfo = GetProgramInfoFromCache(timer.ChannelId, timer.ProgramId); + programInfo = GetProgramInfoFromCache(timer); } if (programInfo == null) { @@ -1478,8 +1419,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (programInfo != null) { - RecordingHelper.CopyProgramInfoToTimerInfo(programInfo, timer); - activeRecordingInfo.Program = programInfo; + CopyProgramInfoToTimerInfo(programInfo, timer); + //activeRecordingInfo.Program = programInfo; } string seriesPath = null; @@ -1488,14 +1429,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV string liveStreamId = null; - OnRecordingStatusChanged(); - try { var recorder = await GetRecorder().ConfigureAwait(false); var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); + _logger.Info("Opening recording stream from tuner provider"); var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None) .ConfigureAwait(false); @@ -1509,23 +1449,20 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV recordPath = EnsureFileUnique(recordPath, timer.Id); _libraryMonitor.ReportFileSystemChangeBeginning(recordPath); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(recordPath)); activeRecordingInfo.Path = recordPath; var duration = recordingEndDate - DateTime.UtcNow; - _logger.Info("Beginning recording. Will record for {0} minutes.", - duration.TotalMinutes.ToString(CultureInfo.InvariantCulture)); + _logger.Info("Beginning recording. Will record for {0} minutes.", duration.TotalMinutes.ToString(CultureInfo.InvariantCulture)); _logger.Info("Writing file to path: " + recordPath); - _logger.Info("Opening recording stream from tuner provider"); - Action onStarted = () => + Action onStarted = async () => { timer.Status = RecordingStatus.InProgress; _timerProvider.AddOrUpdate(timer, false); - SaveRecordingMetadata(timer, recordPath, seriesPath); + await SaveRecordingMetadata(timer, recordPath, seriesPath).ConfigureAwait(false); TriggerRefresh(recordPath); EnforceKeepUpTo(timer, seriesPath); }; @@ -1559,7 +1496,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } TriggerRefresh(recordPath); - _libraryMonitor.ReportFileSystemChangeComplete(recordPath, true); + _libraryMonitor.ReportFileSystemChangeComplete(recordPath, false); ActiveRecordingInfo removed; _activeRecordings.TryRemove(timer.Id, out removed); @@ -1585,17 +1522,29 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { _timerProvider.Delete(timer); } - - OnRecordingStatusChanged(); } private void TriggerRefresh(string path) { + _logger.Debug("Triggering refresh on {0}", path); + var item = GetAffectedBaseItem(_fileSystem.GetDirectoryName(path)); if (item != null) { - item.ChangedExternally(); + _logger.Debug("Refreshing recording parent {0}", item.Path); + + _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem) + { + ValidateChildren = true, + RefreshPaths = new List<string> + { + path, + _fileSystem.GetDirectoryName(path), + _fileSystem.GetDirectoryName(_fileSystem.GetDirectoryName(path)) + } + + }, RefreshPriority.High); } } @@ -1603,6 +1552,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { BaseItem item = null; + var parentPath = _fileSystem.GetDirectoryName(path); + while (item == null && !string.IsNullOrEmpty(path)) { item = _libraryManager.FindByPath(path, null); @@ -1612,14 +1563,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (item != null) { - // If the item has been deleted find the first valid parent that still exists - while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path)) + if (item.GetType() == typeof(Folder) && string.Equals(item.Path, parentPath, StringComparison.OrdinalIgnoreCase)) { - item = item.GetParent(); - - if (item == null) + var parentItem = item.GetParent(); + if (parentItem != null && !(parentItem is AggregateFolder)) { - break; + item = parentItem; } } } @@ -1627,14 +1576,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return item; } - private void OnRecordingStatusChanged() - { - EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs - { - - }, _logger); - } - private async void EnforceKeepUpTo(TimerInfo timer, string seriesPath) { if (string.IsNullOrWhiteSpace(timer.SeriesTimerId)) @@ -1687,8 +1628,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var episodesToDelete = (librarySeries.GetItemList(new InternalItemsQuery { - SortBy = new[] { ItemSortBy.DateCreated }, - SortOrder = SortOrder.Descending, + OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) }, IsVirtualItem = false, IsFolder = false, Recursive = true, @@ -1810,7 +1750,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var config = GetConfiguration(); - var regInfo = await _liveTvManager.GetRegistrationInfo("embytvrecordingconversion").ConfigureAwait(false); + var regInfo = await _liveTvManager.GetRegistrationInfo("dvr").ConfigureAwait(false); if (regInfo.IsValid) { @@ -2020,7 +1960,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } } - private async void SaveRecordingMetadata(TimerInfo timer, string recordingPath, string seriesPath) + private async Task SaveRecordingMetadata(TimerInfo timer, string recordingPath, string seriesPath) { try { @@ -2337,18 +2277,49 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } } - private ProgramInfo GetProgramInfoFromCache(string channelId, string programId) + private LiveTvProgram GetProgramInfoFromCache(string programId) { - var epgData = GetEpgDataForChannel(channelId); - return epgData.FirstOrDefault(p => string.Equals(p.Id, programId, StringComparison.OrdinalIgnoreCase)); + var query = new InternalItemsQuery + { + ItemIds = new[] { _liveTvManager.GetInternalProgramId(Name, programId).ToString("N") }, + Limit = 1, + DtoOptions = new DtoOptions() + }; + + return _libraryManager.GetItemList(query).Cast<LiveTvProgram>().FirstOrDefault(); } - private ProgramInfo GetProgramInfoFromCache(string channelId, DateTime startDateUtc) + private LiveTvProgram GetProgramInfoFromCache(TimerInfo timer) { - var epgData = GetEpgDataForChannel(channelId); - var startDateTicks = startDateUtc.Ticks; - // Find the first program that starts within 3 minutes - return epgData.FirstOrDefault(p => Math.Abs(startDateTicks - p.StartDate.Ticks) <= TimeSpan.FromMinutes(3).Ticks); + return GetProgramInfoFromCache(timer.ProgramId, timer.ChannelId); + } + + private LiveTvProgram GetProgramInfoFromCache(string programId, string channelId) + { + return GetProgramInfoFromCache(programId); + } + + private LiveTvProgram GetProgramInfoFromCache(string channelId, DateTime startDateUtc) + { + var query = new InternalItemsQuery + { + IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name }, + Limit = 1, + DtoOptions = new DtoOptions(true) + { + EnableImages = false + }, + MinStartDate = startDateUtc.AddMinutes(-3), + MaxStartDate = startDateUtc.AddMinutes(3), + OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) } + }; + + if (!string.IsNullOrWhiteSpace(channelId)) + { + query.ChannelIds = new[] { _liveTvManager.GetInternalChannelId(Name, channelId).ToString("N") }; + } + + return _libraryManager.GetItemList(query).Cast<LiveTvProgram>().FirstOrDefault(); } private LiveTvOptions GetConfiguration() @@ -2422,9 +2393,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } } - private async Task UpdateTimersForSeriesTimer(List<ProgramInfo> epgData, SeriesTimerInfo seriesTimer, bool updateTimerSettings, bool deleteInvalidTimers) + private async Task UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer, bool updateTimerSettings, bool deleteInvalidTimers) { - var allTimers = GetTimersForSeries(seriesTimer, epgData) + var allTimers = GetTimersForSeries(seriesTimer) .ToList(); var registration = await _liveTvManager.GetRegistrationInfo("seriesrecordings").ConfigureAwait(false); @@ -2521,23 +2492,160 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } } - private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms) + private IEnumerable<TimerInfo> GetTimersForSeries(SeriesTimerInfo seriesTimer) { if (seriesTimer == null) { throw new ArgumentNullException("seriesTimer"); } - if (allPrograms == null) + + if (string.IsNullOrWhiteSpace(seriesTimer.SeriesId)) { - throw new ArgumentNullException("allPrograms"); + return new List<TimerInfo>(); } - // Exclude programs that have already ended - allPrograms = allPrograms.Where(i => i.EndDate > DateTime.UtcNow); + var query = new InternalItemsQuery + { + IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name }, + ExternalSeriesId = seriesTimer.SeriesId, + DtoOptions = new DtoOptions(true) + { + EnableImages = false + }, + MinEndDate = DateTime.UtcNow + }; - allPrograms = GetProgramsForSeries(seriesTimer, allPrograms); + if (!seriesTimer.RecordAnyChannel) + { + query.ChannelIds = new[] { _liveTvManager.GetInternalChannelId(Name, seriesTimer.ChannelId).ToString("N") }; + } - return allPrograms.Select(i => RecordingHelper.CreateTimer(i, seriesTimer)); + var tempChannelCache = new Dictionary<string, LiveTvChannel>(); + + return _libraryManager.GetItemList(query).Cast<LiveTvProgram>().Select(i => CreateTimer(i, seriesTimer, tempChannelCache)); + } + + private TimerInfo CreateTimer(LiveTvProgram parent, SeriesTimerInfo seriesTimer, Dictionary<string, LiveTvChannel> tempChannelCache) + { + string channelId = seriesTimer.RecordAnyChannel ? null : seriesTimer.ChannelId; + + if (string.IsNullOrWhiteSpace(channelId) && !string.IsNullOrWhiteSpace(parent.ChannelId)) + { + LiveTvChannel channel; + + if (!tempChannelCache.TryGetValue(parent.ChannelId, out channel)) + { + channel = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new string[] { typeof(LiveTvChannel).Name }, + ItemIds = new[] { parent.ChannelId }, + DtoOptions = new DtoOptions() + + }).Cast<LiveTvChannel>().FirstOrDefault(); + + if (channel != null && !string.IsNullOrWhiteSpace(channel.ExternalId)) + { + tempChannelCache[parent.ChannelId] = channel; + } + } + + if (channel != null || tempChannelCache.TryGetValue(parent.ChannelId, out channel)) + { + channelId = channel.ExternalId; + } + } + + var timer = new TimerInfo + { + ChannelId = channelId, + Id = (seriesTimer.Id + parent.ExternalId).GetMD5().ToString("N"), + StartDate = parent.StartDate, + EndDate = parent.EndDate.Value, + ProgramId = parent.ExternalId, + PrePaddingSeconds = seriesTimer.PrePaddingSeconds, + PostPaddingSeconds = seriesTimer.PostPaddingSeconds, + IsPostPaddingRequired = seriesTimer.IsPostPaddingRequired, + IsPrePaddingRequired = seriesTimer.IsPrePaddingRequired, + KeepUntil = seriesTimer.KeepUntil, + Priority = seriesTimer.Priority, + Name = parent.Name, + Overview = parent.Overview, + SeriesId = parent.ExternalSeriesId, + SeriesTimerId = seriesTimer.Id, + ShowId = parent.ShowId + }; + + CopyProgramInfoToTimerInfo(parent, timer, tempChannelCache); + + return timer; + } + + private void CopyProgramInfoToTimerInfo(LiveTvProgram programInfo, TimerInfo timerInfo) + { + var tempChannelCache = new Dictionary<string, LiveTvChannel>(); + CopyProgramInfoToTimerInfo(programInfo, timerInfo, tempChannelCache); + } + + private void CopyProgramInfoToTimerInfo(LiveTvProgram programInfo, TimerInfo timerInfo, Dictionary<string, LiveTvChannel> tempChannelCache) + { + string channelId = null; + + if (!string.IsNullOrWhiteSpace(programInfo.ChannelId)) + { + LiveTvChannel channel; + + if (!tempChannelCache.TryGetValue(programInfo.ChannelId, out channel)) + { + channel = _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = new string[] { typeof(LiveTvChannel).Name }, + ItemIds = new[] { programInfo.ChannelId }, + DtoOptions = new DtoOptions() + + }).Cast<LiveTvChannel>().FirstOrDefault(); + + if (channel != null && !string.IsNullOrWhiteSpace(channel.ExternalId)) + { + tempChannelCache[programInfo.ChannelId] = channel; + } + } + + if (channel != null || tempChannelCache.TryGetValue(programInfo.ChannelId, out channel)) + { + channelId = channel.ExternalId; + } + } + + timerInfo.Name = programInfo.Name; + timerInfo.StartDate = programInfo.StartDate; + timerInfo.EndDate = programInfo.EndDate.Value; + + if (!string.IsNullOrWhiteSpace(channelId)) + { + timerInfo.ChannelId = channelId; + } + + timerInfo.SeasonNumber = programInfo.ParentIndexNumber; + timerInfo.EpisodeNumber = programInfo.IndexNumber; + timerInfo.IsMovie = programInfo.IsMovie; + timerInfo.IsKids = programInfo.IsKids; + timerInfo.IsNews = programInfo.IsNews; + timerInfo.IsSports = programInfo.IsSports; + timerInfo.ProductionYear = programInfo.ProductionYear; + timerInfo.EpisodeTitle = programInfo.EpisodeTitle; + timerInfo.OriginalAirDate = programInfo.PremiereDate; + timerInfo.IsProgramSeries = programInfo.IsSeries; + + timerInfo.IsSeries = programInfo.IsSeries; + timerInfo.IsLive = programInfo.IsLive; + timerInfo.IsPremiere = programInfo.IsPremiere; + + timerInfo.HomePageUrl = programInfo.HomePageUrl; + timerInfo.CommunityRating = programInfo.CommunityRating; + timerInfo.Overview = programInfo.Overview; + timerInfo.OfficialRating = programInfo.OfficialRating; + timerInfo.IsRepeat = programInfo.IsRepeat; + timerInfo.SeriesId = programInfo.ExternalSeriesId; } private bool IsProgramAlreadyInLibrary(TimerInfo program) @@ -2578,51 +2686,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return false; } - private IEnumerable<ProgramInfo> GetProgramsForSeries(SeriesTimerInfo seriesTimer, IEnumerable<ProgramInfo> allPrograms) - { - if (string.IsNullOrWhiteSpace(seriesTimer.SeriesId)) - { - _logger.Error("seriesTimer.SeriesId is null. Cannot find programs for series"); - return new List<ProgramInfo>(); - } - - return allPrograms.Where(i => string.Equals(i.SeriesId, seriesTimer.SeriesId, StringComparison.OrdinalIgnoreCase)); - } - - private string GetChannelEpgCachePath(string channelId) - { - return Path.Combine(_config.CommonApplicationPaths.CachePath, "embytvepg", channelId + ".json"); - } - - private readonly object _epgLock = new object(); - private void SaveEpgDataForChannel(string channelId, List<ProgramInfo> epgData) - { - var path = GetChannelEpgCachePath(channelId); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); - lock (_epgLock) - { - _jsonSerializer.SerializeToFile(epgData, path); - } - } - private List<ProgramInfo> GetEpgDataForChannel(string channelId) - { - try - { - lock (_epgLock) - { - return _jsonSerializer.DeserializeFromFile<List<ProgramInfo>>(GetChannelEpgCachePath(channelId)); - } - } - catch - { - return new List<ProgramInfo>(); - } - } - private List<ProgramInfo> GetEpgDataForChannels(List<string> channelIds) - { - return channelIds.SelectMany(GetEpgDataForChannel).ToList(); - } - private bool _disposed; public void Dispose() { @@ -2631,6 +2694,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { pair.Value.CancellationTokenSource.Cancel(); } + GC.SuppressFinalize(this); } public List<VirtualFolderInfo> GetRecordingFolders() diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 48eba4117..149f69e5b 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -284,8 +284,15 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV protected string GetOutputSizeParam() { var filters = new List<string>(); - - filters.Add("yadif=0:-1:0"); + + if (string.Equals(GetEncodingOptions().DeinterlaceMethod, "bobandweave", StringComparison.OrdinalIgnoreCase)) + { + filters.Add("yadif=1:-1:0"); + } + else + { + filters.Add("yadif=0:-1:0"); + } var output = string.Empty; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs index 139cf570e..7c5f630a7 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EntryPoint.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Plugins; +using System; +using MediaBrowser.Controller.Plugins; namespace Emby.Server.Implementations.LiveTv.EmbyTV { @@ -11,6 +12,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV public void Dispose() { + GC.SuppressFinalize(this); } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs index b5de6ef01..a5712b480 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs @@ -1,8 +1,6 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.LiveTv; using System; using System.Globalization; -using MediaBrowser.Model.LiveTv; namespace Emby.Server.Implementations.LiveTv.EmbyTV { @@ -13,63 +11,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return timer.StartDate.AddSeconds(-timer.PrePaddingSeconds); } - public static TimerInfo CreateTimer(ProgramInfo parent, SeriesTimerInfo seriesTimer) - { - var timer = new TimerInfo - { - ChannelId = parent.ChannelId, - Id = (seriesTimer.Id + parent.Id).GetMD5().ToString("N"), - StartDate = parent.StartDate, - EndDate = parent.EndDate, - ProgramId = parent.Id, - PrePaddingSeconds = seriesTimer.PrePaddingSeconds, - PostPaddingSeconds = seriesTimer.PostPaddingSeconds, - IsPostPaddingRequired = seriesTimer.IsPostPaddingRequired, - IsPrePaddingRequired = seriesTimer.IsPrePaddingRequired, - KeepUntil = seriesTimer.KeepUntil, - Priority = seriesTimer.Priority, - Name = parent.Name, - Overview = parent.Overview, - SeriesId = parent.SeriesId, - SeriesTimerId = seriesTimer.Id, - ShowId = parent.ShowId - }; - - CopyProgramInfoToTimerInfo(parent, timer); - - return timer; - } - - public static void CopyProgramInfoToTimerInfo(ProgramInfo programInfo, TimerInfo timerInfo) - { - timerInfo.Name = programInfo.Name; - timerInfo.StartDate = programInfo.StartDate; - timerInfo.EndDate = programInfo.EndDate; - timerInfo.ChannelId = programInfo.ChannelId; - - timerInfo.SeasonNumber = programInfo.SeasonNumber; - timerInfo.EpisodeNumber = programInfo.EpisodeNumber; - timerInfo.IsMovie = programInfo.IsMovie; - timerInfo.IsKids = programInfo.IsKids; - timerInfo.IsNews = programInfo.IsNews; - timerInfo.IsSports = programInfo.IsSports; - timerInfo.ProductionYear = programInfo.ProductionYear; - timerInfo.EpisodeTitle = programInfo.EpisodeTitle; - timerInfo.OriginalAirDate = programInfo.OriginalAirDate; - timerInfo.IsProgramSeries = programInfo.IsSeries; - - timerInfo.IsSeries = programInfo.IsSeries; - timerInfo.IsLive = programInfo.IsLive; - timerInfo.IsPremiere = programInfo.IsPremiere; - - timerInfo.HomePageUrl = programInfo.HomePageUrl; - timerInfo.CommunityRating = programInfo.CommunityRating; - timerInfo.Overview = programInfo.Overview; - timerInfo.OfficialRating = programInfo.OfficialRating; - timerInfo.IsRepeat = programInfo.IsRepeat; - timerInfo.SeriesId = programInfo.SeriesId; - } - public static string GetRecordingName(TimerInfo info) { var name = info.Name; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs index eff2909fd..e6479feaa 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -9,14 +9,12 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; using System; -using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Extensions; -using MediaBrowser.Model.Querying; namespace Emby.Server.Implementations.LiveTv { @@ -25,15 +23,13 @@ namespace Emby.Server.Implementations.LiveTv private readonly ILogger _logger; private readonly IImageProcessor _imageProcessor; - private readonly IUserDataManager _userDataManager; private readonly IDtoService _dtoService; private readonly IApplicationHost _appHost; private readonly ILibraryManager _libraryManager; - public LiveTvDtoService(IDtoService dtoService, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILogger logger, IApplicationHost appHost, ILibraryManager libraryManager) + public LiveTvDtoService(IDtoService dtoService, IImageProcessor imageProcessor, ILogger logger, IApplicationHost appHost, ILibraryManager libraryManager) { _dtoService = dtoService; - _userDataManager = userDataManager; _imageProcessor = imageProcessor; _logger = logger; _appHost = appHost; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index ac98d1043..38d2fd3c6 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -99,7 +99,7 @@ namespace Emby.Server.Implementations.LiveTv _dtoService = dtoService; _userDataManager = userDataManager; - _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger, appHost, _libraryManager); + _tvDtoService = new LiveTvDtoService(dtoService, imageProcessor, logger, appHost, _libraryManager); } /// <summary> @@ -187,7 +187,6 @@ namespace Emby.Server.Implementations.LiveTv IsSports = query.IsSports, IsSeries = query.IsSeries, IncludeItemTypes = new[] { typeof(LiveTvChannel).Name }, - SortOrder = query.SortOrder ?? SortOrder.Ascending, TopParentIds = new[] { topFolder.Id.ToString("N") }, IsFavorite = query.IsFavorite, IsLiked = query.IsLiked, @@ -196,18 +195,22 @@ namespace Emby.Server.Implementations.LiveTv DtoOptions = dtoOptions }; - internalQuery.OrderBy.AddRange(query.SortBy.Select(i => new Tuple<string, SortOrder>(i, query.SortOrder ?? SortOrder.Ascending))); + var orderBy = internalQuery.OrderBy.ToList(); + + orderBy.AddRange(query.SortBy.Select(i => new Tuple<string, SortOrder>(i, query.SortOrder ?? SortOrder.Ascending))); if (query.EnableFavoriteSorting) { - internalQuery.OrderBy.Insert(0, new Tuple<string, SortOrder>(ItemSortBy.IsFavoriteOrLiked, SortOrder.Descending)); + orderBy.Insert(0, new Tuple<string, SortOrder>(ItemSortBy.IsFavoriteOrLiked, SortOrder.Descending)); } if (!internalQuery.OrderBy.Any(i => string.Equals(i.Item1, ItemSortBy.SortName, StringComparison.OrdinalIgnoreCase))) { - internalQuery.OrderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending)); + orderBy.Add(new Tuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending)); } + internalQuery.OrderBy = orderBy.ToArray(); + return _libraryManager.GetItemsResult(internalQuery); } @@ -597,6 +600,12 @@ namespace Emby.Server.Implementations.LiveTv }; } + if (!string.Equals(info.ShowId, item.ShowId, StringComparison.OrdinalIgnoreCase)) + { + item.ShowId = info.ShowId; + forceUpdate = true; + } + var seriesId = info.SeriesId; if (!item.ParentId.Equals(channel.Id)) @@ -743,6 +752,11 @@ namespace Emby.Server.Implementations.LiveTv } } + if (isNew || isUpdated) + { + item.OnMetadataChanged(); + } + return new Tuple<LiveTvProgram, bool, bool>(item, isNew, isUpdated); } @@ -829,8 +843,7 @@ namespace Emby.Server.Implementations.LiveTv item.SetImage(new ItemImageInfo { Path = info.ImagePath, - Type = ImageType.Primary, - IsPlaceholder = true + Type = ImageType.Primary }, 0); } else if (!string.IsNullOrWhiteSpace(info.ImageUrl)) @@ -838,8 +851,7 @@ namespace Emby.Server.Implementations.LiveTv item.SetImage(new ItemImageInfo { Path = info.ImageUrl, - Type = ImageType.Primary, - IsPlaceholder = true + Type = ImageType.Primary }, 0); } } @@ -918,10 +930,10 @@ namespace Emby.Server.Implementations.LiveTv var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); - if (query.SortBy.Length == 0) + if (query.OrderBy.Length == 0) { // Unless something else was specified, order by start date to take advantage of a specialized index - query.SortBy = new[] { ItemSortBy.StartDate }; + query.OrderBy = new Tuple<string, SortOrder>[] { new Tuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) }; } RemoveFields(options); @@ -942,8 +954,7 @@ namespace Emby.Server.Implementations.LiveTv Genres = query.Genres, StartIndex = query.StartIndex, Limit = query.Limit, - SortBy = query.SortBy, - SortOrder = query.SortOrder ?? SortOrder.Ascending, + OrderBy = query.OrderBy, EnableTotalRecordCount = query.EnableTotalRecordCount, TopParentIds = new[] { topFolder.Id.ToString("N") }, Name = query.Name, @@ -985,8 +996,7 @@ namespace Emby.Server.Implementations.LiveTv var queryResult = _libraryManager.QueryItems(internalQuery); - var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(queryResult.Items, options, user); var result = new QueryResult<BaseItemDto> { @@ -1013,7 +1023,7 @@ namespace Emby.Server.Implementations.LiveTv IsSports = query.IsSports, IsKids = query.IsKids, EnableTotalRecordCount = query.EnableTotalRecordCount, - SortBy = new[] { ItemSortBy.StartDate }, + OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) }, TopParentIds = new[] { topFolder.Id.ToString("N") }, DtoOptions = options }; @@ -1070,8 +1080,7 @@ namespace Emby.Server.Implementations.LiveTv var user = _userManager.GetUserById(query.UserId); - var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user); var result = new QueryResult<BaseItemDto> { @@ -1646,8 +1655,7 @@ namespace Emby.Server.Implementations.LiveTv IsVirtualItem = false, Limit = query.Limit, StartIndex = query.StartIndex, - SortBy = new[] { ItemSortBy.DateCreated }, - SortOrder = SortOrder.Descending, + OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) }, EnableTotalRecordCount = query.EnableTotalRecordCount, IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count), ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count), @@ -1656,7 +1664,7 @@ namespace Emby.Server.Implementations.LiveTv }); } - public async Task<QueryResult<BaseItemDto>> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken) + public QueryResult<BaseItemDto> GetRecordingSeries(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); if (user != null && !IsLiveTvEnabled(user)) @@ -1694,16 +1702,14 @@ namespace Emby.Server.Implementations.LiveTv Recursive = true, AncestorIds = folders.Select(i => i.Id.ToString("N")).ToArray(folders.Count), Limit = query.Limit, - SortBy = new[] { ItemSortBy.DateCreated }, - SortOrder = SortOrder.Descending, + OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) }, EnableTotalRecordCount = query.EnableTotalRecordCount, IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count), ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count), DtoOptions = options }); - var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user); return new QueryResult<BaseItemDto> { @@ -1930,11 +1936,11 @@ namespace Emby.Server.Implementations.LiveTv var info = recording; - dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) + dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) || service == null ? null : _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N"); - dto.TimerId = string.IsNullOrEmpty(info.TimerId) + dto.TimerId = string.IsNullOrEmpty(info.TimerId) || service == null ? null : _tvDtoService.GetInternalTimerId(service.Name, info.TimerId).ToString("N"); @@ -2040,8 +2046,7 @@ namespace Emby.Server.Implementations.LiveTv var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false); - var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) - .ConfigureAwait(false)); + var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user); return new QueryResult<BaseItemDto> { @@ -2368,7 +2373,7 @@ namespace Emby.Server.Implementations.LiveTv }; } - public async Task AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> tuples, DtoOptions options, User user) + public void AddChannelInfo(List<Tuple<BaseItemDto, LiveTvChannel>> tuples, DtoOptions options, User user) { var now = DateTime.UtcNow; @@ -2381,7 +2386,7 @@ namespace Emby.Server.Implementations.LiveTv MaxStartDate = now, MinEndDate = now, Limit = channelIds.Length, - SortBy = new[] { "StartDate" }, + OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) }, TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") }, DtoOptions = options @@ -2425,7 +2430,7 @@ namespace Emby.Server.Implementations.LiveTv if (addCurrentProgram) { - var currentProgramDtos = await _dtoService.GetBaseItemDtos(currentProgramsList, options, user).ConfigureAwait(false); + var currentProgramDtos = _dtoService.GetBaseItemDtos(currentProgramsList, options, user); foreach (var programDto in currentProgramDtos) { @@ -2783,6 +2788,7 @@ namespace Emby.Server.Implementations.LiveTv public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } private bool _isDisposed = false; @@ -3146,5 +3152,15 @@ namespace Emby.Server.Implementations.LiveTv var provider = _listingProviders.First(i => string.Equals(i.Type, info.Type, StringComparison.OrdinalIgnoreCase)); return provider.GetChannels(info, cancellationToken); } + + public Guid GetInternalChannelId(string serviceName, string externalId) + { + return _tvDtoService.GetInternalChannelId(serviceName, externalId); + } + + public Guid GetInternalProgramId(string serviceName, string externalId) + { + return _tvDtoService.GetInternalProgramId(serviceName, externalId); + } } }
\ No newline at end of file diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs index 0e52f874d..ed8b3074b 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs @@ -142,6 +142,8 @@ namespace Emby.Server.Implementations.LiveTv var info = await _liveTvManager.GetChannelStream(keys[1], mediaSourceId, cancellationToken).ConfigureAwait(false); stream = info.Item1; directStreamProvider = info.Item2; + + //allowLiveStreamProbe = false; } else { diff --git a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs index cad28c809..225360159 100644 --- a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs +++ b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs @@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.LiveTv return new[] { // Every so often - new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(12).Ticks} + new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks} }; } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index eae29bee7..f974b5c2c 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun SupportsTranscoding = true, IsInfiniteStream = true, IgnoreDts = true, - //SupportsProbing = false, + SupportsProbing = false, //AnalyzeDurationMs = 2000000 //IgnoreIndex = true, //ReadAtNativeFramerate = true diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs index d2e9c8bf0..af064755d 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs @@ -26,10 +26,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource(); private readonly TaskCompletionSource<bool> _liveStreamTaskCompletionSource = new TaskCompletionSource<bool>(); - private readonly MulticastStream _multicastStream; - private readonly string _tempFilePath; - private bool _enableFileBuffer = false; public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment) : base(mediaSource, environment, fileSystem) @@ -39,7 +36,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun _appHost = appHost; OriginalStreamId = originalStreamId; - _multicastStream = new MulticastStream(_logger); _tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts"); } @@ -63,6 +59,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts"; OpenedMediaSource.Protocol = MediaProtocol.Http; + + //OpenedMediaSource.Path = _tempFilePath; + //OpenedMediaSource.Protocol = MediaProtocol.File; //OpenedMediaSource.SupportsDirectPlay = false; //OpenedMediaSource.SupportsDirectStream = true; //OpenedMediaSource.SupportsTranscoding = true; @@ -107,19 +106,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { _logger.Info("Beginning multicastStream.CopyUntilCancelled"); - if (_enableFileBuffer) + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath)); + using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) { - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath)); - using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) - { - StreamHelper.CopyTo(response.Content, fileStream, 81920, () => Resolve(openTaskCompletionSource), cancellationToken); - } - } - else - { - Resolve(openTaskCompletionSource); - - await _multicastStream.CopyUntilCancelled(response.Content, null, cancellationToken).ConfigureAwait(false); + StreamHelper.CopyTo(response.Content, fileStream, 81920, () => Resolve(openTaskCompletionSource), cancellationToken); } } } @@ -144,7 +134,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } _liveStreamTaskCompletionSource.TrySetResult(true); - //await DeleteTempFile(_tempFilePath).ConfigureAwait(false); + await DeleteTempFile(_tempFilePath).ConfigureAwait(false); }); } @@ -158,56 +148,31 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun public Task CopyToAsync(Stream stream, CancellationToken cancellationToken) { - if (_enableFileBuffer) - { - return CopyFileTo(_tempFilePath, stream, cancellationToken); - } - return _multicastStream.CopyToAsync(stream, cancellationToken); - //return CopyFileTo(_tempFilePath, stream, cancellationToken); + return CopyFileTo(_tempFilePath, stream, cancellationToken); } protected async Task CopyFileTo(string path, Stream outputStream, CancellationToken cancellationToken) { long startPosition = -20000; - if (startPosition < 0) - { - var length = FileSystem.GetFileInfo(path).Length; - startPosition = Math.Max(length - startPosition, 0); - } _logger.Info("Live stream starting position is {0} bytes", startPosition.ToString(CultureInfo.InvariantCulture)); - var allowAsync = Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; + var allowAsync = false;//Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - using (var inputStream = GetInputStream(path, startPosition, allowAsync)) + using (var inputStream = (FileStream)GetInputStream(path, allowAsync)) { if (startPosition > 0) { - inputStream.Position = startPosition; + inputStream.Seek(-20000, SeekOrigin.End); } while (!cancellationToken.IsCancellationRequested) { - long bytesRead; - - if (allowAsync) - { - bytesRead = await AsyncStreamCopier.CopyStream(inputStream, outputStream, 81920, 2, cancellationToken).ConfigureAwait(false); - } - else - { - StreamHelper.CopyTo(inputStream, outputStream, 81920, cancellationToken); - bytesRead = 1; - } + StreamHelper.CopyTo(inputStream, outputStream, 81920, cancellationToken); //var position = fs.Position; //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); - - if (bytesRead == 0) - { - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - } } } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index 41b058baf..c737c4cba 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -99,6 +99,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var task = StopStreaming(); Task.WaitAll(task); + GC.SuppressFinalize(this); } public async Task<bool> CheckTunerAvailability(IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 5ad6e2e16..6c21066fb 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -34,8 +34,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly INetworkManager _networkManager; private readonly string _tempFilePath; - private bool _enableFileBuffer = false; - private readonly MulticastStream _multicastStream; public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager, IEnvironmentInfo environment) : base(mediaSource, environment, fileSystem) @@ -48,7 +46,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun _channelCommands = channelCommands; _numTuners = numTuners; _tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts"); - _multicastStream = new MulticastStream(_logger); } protected override async Task OpenInternal(CancellationToken openCancellationToken) @@ -126,17 +123,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun if (!cancellationToken.IsCancellationRequested) { - if (_enableFileBuffer) + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath)); + using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) { - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath)); - using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) - { - CopyTo(udpClient, fileStream, openTaskCompletionSource, cancellationToken); - } - } - else - { - await _multicastStream.CopyUntilCancelled(new UdpClientStream(udpClient), () => Resolve(openTaskCompletionSource), cancellationToken).ConfigureAwait(false); + CopyTo(udpClient, fileStream, openTaskCompletionSource, cancellationToken); } } } @@ -178,56 +168,33 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun }); } - public async Task CopyToAsync(Stream outputStream, CancellationToken cancellationToken) + public Task CopyToAsync(Stream stream, CancellationToken cancellationToken) { - if (!_enableFileBuffer) - { - await _multicastStream.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); - return; - } - - var path = _tempFilePath; + return CopyFileTo(_tempFilePath, stream, cancellationToken); + } + protected async Task CopyFileTo(string path, Stream outputStream, CancellationToken cancellationToken) + { long startPosition = -20000; - if (startPosition < 0) - { - var length = FileSystem.GetFileInfo(path).Length; - startPosition = Math.Max(length - startPosition, 0); - } _logger.Info("Live stream starting position is {0} bytes", startPosition.ToString(CultureInfo.InvariantCulture)); - var allowAsync = Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; + var allowAsync = false;//Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - using (var inputStream = GetInputStream(path, startPosition, allowAsync)) + using (var inputStream = (FileStream)GetInputStream(path, allowAsync)) { if (startPosition > 0) { - inputStream.Position = startPosition; + inputStream.Seek(-20000, SeekOrigin.End); } while (!cancellationToken.IsCancellationRequested) { - long bytesRead; - - if (allowAsync) - { - bytesRead = await AsyncStreamCopier.CopyStream(inputStream, outputStream, 81920, 2, cancellationToken).ConfigureAwait(false); - } - else - { - StreamHelper.CopyTo(inputStream, outputStream, 81920, cancellationToken); - bytesRead = 1; - } + StreamHelper.CopyTo(inputStream, outputStream, 81920, cancellationToken); //var position = fs.Position; //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); - - if (bytesRead == 0) - { - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - } } } } @@ -285,22 +252,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun //return taskCompletion.Task; } - private void StreamCopyCallback(IAsyncResult result) - { - var copier = (AsyncStreamCopier)result.AsyncState; - var taskCompletion = copier.TaskCompletionSource; - - try - { - copier.EndCopy(result); - taskCompletion.TrySetResult(0); - } - catch (Exception ex) - { - taskCompletion.TrySetException(ex); - } - } - public class UdpClientStream : Stream { private static int RtpHeaderBytes = 12; |
