From 67b4cef77a4b391d5dcf0769d0c70762128ddfd1 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 11:59:51 -0500 Subject: [PATCH 01/11] Use implementation types in LiveTv --- Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs | 4 ++-- Emby.Server.Implementations/LiveTv/LiveTvManager.cs | 2 +- Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 5369c9b3d1d..b548a92b19c 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -34,7 +34,7 @@ public class EncodedRecorder : IRecorder, IDisposable private readonly IServerConfigurationManager _serverConfigurationManager; private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; private bool _hasExited; - private Stream _logFileStream; + private FileStream _logFileStream; private string _targetPath; private Process _process; private bool _disposed = false; @@ -308,7 +308,7 @@ private void OnFfMpegProcessExited(Process process) } } - private async Task StartStreamingLog(Stream source, Stream target) + private async Task StartStreamingLog(Stream source, FileStream target) { try { diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index dd427c73689..dcd1e8613cc 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1101,7 +1101,7 @@ private async Task RefreshChannelsInternal(IProgress progress, Cancellat progress.Report(100); } - private async Task, List>> RefreshChannelsInternal(ILiveTvService service, IProgress progress, CancellationToken cancellationToken) + private async Task, List>> RefreshChannelsInternal(ILiveTvService service, ActionableProgress progress, CancellationToken cancellationToken) { progress.Report(10); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 767b9413660..c0ba8710ffc 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -134,7 +134,7 @@ protected async Task DeleteTempFiles(string path, int retryCount = 0) } } - private void TrySeek(Stream stream, long offset) + private void TrySeek(FileStream stream, long offset) { if (!stream.CanSeek) { From f1a5bc955b6a182aaa19a80831560d43c50ede2a Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:01:59 -0500 Subject: [PATCH 02/11] Use string.Contains in LiveTv --- .../LiveTv/Listings/SchedulesDirect.cs | 4 ++-- .../LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 6b0520ad0fb..5be3a7488ae 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -287,7 +287,7 @@ private ProgramInfo GetProgram(string channelId, ProgramDto programInfo, Program IsMovie = IsMovie(details), Etag = programInfo.Md5, IsLive = string.Equals(programInfo.LiveTapeDelay, "live", StringComparison.OrdinalIgnoreCase), - IsPremiere = programInfo.Premiere || (programInfo.IsPremiereOrFinale ?? string.Empty).IndexOf("premiere", StringComparison.OrdinalIgnoreCase) != -1 + IsPremiere = programInfo.Premiere || (programInfo.IsPremiereOrFinale ?? string.Empty).Contains("premiere", StringComparison.OrdinalIgnoreCase) }; var showId = programId; @@ -414,7 +414,7 @@ private static string GetProgramImage(string apiUrl, IEnumerable i return null; } - if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1) + if (uri.Contains("http", StringComparison.OrdinalIgnoreCase)) { return uri; } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs index 42068cd340d..39b35714228 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs @@ -30,7 +30,7 @@ public bool SupportsTranscoding { var model = ModelNumber ?? string.Empty; - if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1) + if (model.Contains("hdtc", StringComparison.OrdinalIgnoreCase)) { return true; } From 01480c7f209654a992be6c3d3ad360e9bd343090 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:03:53 -0500 Subject: [PATCH 03/11] Fix disposable warnings in EmbyTV --- .../LiveTv/EmbyTV/EmbyTV.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 74b62ca3f22..cba24ca459f 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -37,12 +37,11 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Querying; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.LiveTv.EmbyTV { - public class EmbyTV : ILiveTvService, ISupportsDirectStreamProvider, ISupportsNewTimerIds, IDisposable + public sealed class EmbyTV : ILiveTvService, ISupportsDirectStreamProvider, ISupportsNewTimerIds, IDisposable { public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss"; @@ -74,7 +73,7 @@ public class EmbyTV : ILiveTvService, ISupportsDirectStreamProvider, ISupportsNe private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1, 1); - private bool _disposed = false; + private bool _disposed; public EmbyTV( IServerApplicationHost appHost, @@ -2524,22 +2523,13 @@ private bool IsProgramAlreadyInLibrary(TimerInfo program) /// public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) { if (_disposed) { return; } - if (disposing) - { - _recordingDeleteSemaphore.Dispose(); - } + _recordingDeleteSemaphore.Dispose(); foreach (var pair in _activeRecordings.ToList()) { From ce6c0ad02bc77b5a43ba2f28d4a93813738d0c53 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:06:30 -0500 Subject: [PATCH 04/11] Use ConfigureAwait in DirectRecorder --- .../LiveTv/EmbyTV/DirectRecorder.cs | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 49833de7374..ec4dbde30d5 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -46,7 +46,15 @@ private async Task RecordFromDirectStreamProvider(IDirectStreamProvider directSt { Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - await using (var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + var output = new FileStream( + targetFile, + FileMode.CreateNew, + FileAccess.Write, + FileShare.Read, + IODefaults.FileStreamBufferSize, + FileOptions.Asynchronous); + + await using (output.ConfigureAwait(false)) { onStarted(); @@ -80,24 +88,26 @@ private async Task RecordFromMediaSource(MediaSourceInfo mediaSource, string tar Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); - await using var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); - - onStarted(); + var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); + await using (output.ConfigureAwait(false)) + { + onStarted(); - _logger.LogInformation("Copying recording stream to file {0}", targetFile); + _logger.LogInformation("Copying recording stream to file {0}", targetFile); - // The media source if infinite so we need to handle stopping ourselves - using var durationToken = new CancellationTokenSource(duration); - using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); - cancellationToken = linkedCancellationToken.Token; + // The media source if infinite so we need to handle stopping ourselves + using var durationToken = new CancellationTokenSource(duration); + using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); + cancellationToken = linkedCancellationToken.Token; - await _streamHelper.CopyUntilCancelled( - await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false), - output, - IODefaults.CopyToBufferSize, - cancellationToken).ConfigureAwait(false); + await _streamHelper.CopyUntilCancelled( + await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false), + output, + IODefaults.CopyToBufferSize, + cancellationToken).ConfigureAwait(false); - _logger.LogInformation("Recording completed to file {0}", targetFile); + _logger.LogInformation("Recording completed to file {0}", targetFile); + } } } } From 7bcfc5e925295d386a8bc70b47200254ae731813 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:22:23 -0500 Subject: [PATCH 05/11] Use ConfigureAwait in XmlTvListingsProvider --- .../LiveTv/Listings/XmlTvListingsProvider.cs | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 066afb956bd..e60e9dcc1cf 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -84,38 +84,53 @@ private async Task GetXml(ListingsProviderInfo info, CancellationToken c _logger.LogInformation("Downloading xmltv listings from {Path}", info.Path); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(info.Path, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - return await UnzipIfNeededAndCopy(info.Path, stream, cacheFile, cancellationToken).ConfigureAwait(false); + var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); + await using (stream.ConfigureAwait(false)) + { + return await UnzipIfNeededAndCopy(info.Path, stream, cacheFile, cancellationToken).ConfigureAwait(false); + } } else { - await using var stream = AsyncFile.OpenRead(info.Path); - return await UnzipIfNeededAndCopy(info.Path, stream, cacheFile, cancellationToken).ConfigureAwait(false); + var stream = AsyncFile.OpenRead(info.Path); + await using (stream.ConfigureAwait(false)) + { + return await UnzipIfNeededAndCopy(info.Path, stream, cacheFile, cancellationToken).ConfigureAwait(false); + } } } private async Task UnzipIfNeededAndCopy(string originalUrl, Stream stream, string file, CancellationToken cancellationToken) { - await using var fileStream = new FileStream(file, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); - - if (Path.GetExtension(originalUrl.AsSpan().LeftPart('?')).Equals(".gz", StringComparison.OrdinalIgnoreCase)) + var fileStream = new FileStream( + file, + FileMode.CreateNew, + FileAccess.Write, + FileShare.None, + IODefaults.FileStreamBufferSize, + FileOptions.Asynchronous); + + await using (fileStream.ConfigureAwait(false)) { - try + if (Path.GetExtension(originalUrl.AsSpan().LeftPart('?')).Equals(".gz", StringComparison.OrdinalIgnoreCase)) { - using var reader = new GZipStream(stream, CompressionMode.Decompress); - await reader.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); + try + { + using var reader = new GZipStream(stream, CompressionMode.Decompress); + await reader.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error extracting from gz file {File}", originalUrl); + } } - catch (Exception ex) + else { - _logger.LogError(ex, "Error extracting from gz file {File}", originalUrl); + await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } - } - else - { - await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); - } - return file; + return file; + } } public async Task> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) From 42c95da6b08a5295e1d2f98922158d0702fd8d7e Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:24:31 -0500 Subject: [PATCH 06/11] Use ConfigureAwait in BaseTunerHost --- .../LiveTv/TunerHosts/BaseTunerHost.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index ff25ee58545..a4e45f47962 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -96,8 +96,11 @@ public async Task> GetChannels(bool enableCache, CancellationT try { Directory.CreateDirectory(Path.GetDirectoryName(channelCacheFile)); - await using var writeStream = AsyncFile.OpenWrite(channelCacheFile); - await JsonSerializer.SerializeAsync(writeStream, channels, cancellationToken: cancellationToken).ConfigureAwait(false); + var writeStream = AsyncFile.OpenWrite(channelCacheFile); + await using (writeStream.ConfigureAwait(false)) + { + await JsonSerializer.SerializeAsync(writeStream, channels, cancellationToken: cancellationToken).ConfigureAwait(false); + } } catch (IOException) { @@ -112,10 +115,14 @@ public async Task> GetChannels(bool enableCache, CancellationT { try { - await using var readStream = AsyncFile.OpenRead(channelCacheFile); - var channels = await JsonSerializer.DeserializeAsync>(readStream, cancellationToken: cancellationToken) - .ConfigureAwait(false); - list.AddRange(channels); + var readStream = AsyncFile.OpenRead(channelCacheFile); + await using (readStream.ConfigureAwait(false)) + { + var channels = await JsonSerializer + .DeserializeAsync>(readStream, cancellationToken: cancellationToken) + .ConfigureAwait(false); + list.AddRange(channels); + } } catch (IOException) { From 4ec32b71f5fc765886e457ae2c626ea7227e6a37 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:26:29 -0500 Subject: [PATCH 07/11] Use ConfigureAwait in M3uParser --- Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 341782d9d38..0b5575b9947 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -66,7 +66,7 @@ public async Task GetListingsStream(TunerHostInfo info, CancellationToke .ConfigureAwait(false); response.EnsureSuccessStatusCode(); - return await response.Content.ReadAsStreamAsync(cancellationToken); + return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); } private async Task> GetChannelsAsync(TextReader reader, string channelIdPrefix, string tunerHostId) From 3ecd68d832b1849b3bebd052933ce8ad7612bad7 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:28:17 -0500 Subject: [PATCH 08/11] Use ConfigureAwait in SharedHttpStream --- .../LiveTv/TunerHosts/SharedHttpStream.cs | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 51f46f4daca..efb84a5152c 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -83,14 +83,27 @@ private Task StartStreaming(HttpResponseMessage response, TaskCompletionSource Resolve(openTaskCompletionSource), - cancellationToken).ConfigureAwait(false); + var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); + await using (stream.ConfigureAwait(false)) + { + var fileStream = new FileStream( + TempFilePath, + FileMode.Create, + FileAccess.Write, + FileShare.Read, + IODefaults.FileStreamBufferSize, + FileOptions.Asynchronous); + + await using (fileStream.ConfigureAwait(false)) + { + await StreamHelper.CopyToAsync( + stream, + fileStream, + IODefaults.CopyToBufferSize, + () => Resolve(openTaskCompletionSource), + cancellationToken).ConfigureAwait(false); + } + } } } catch (OperationCanceledException ex) From 5c593b120a5f3b90daa6305a96086eecfe546039 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:36:24 -0500 Subject: [PATCH 09/11] Don't use List directly in ITunerHost method signatures --- .../LiveTv/TunerHosts/BaseTunerHost.cs | 6 +++--- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 2 +- .../LiveTv/TunerHosts/M3UTunerHost.cs | 2 +- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index a4e45f47962..da597056a42 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -67,7 +67,7 @@ public async Task> GetChannels(TunerHostInfo tuner, bool enabl return list; } - protected virtual List GetTunerHosts() + protected virtual IList GetTunerHosts() { return GetConfiguration().TunerHosts .Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase)) @@ -166,9 +166,9 @@ public async Task> GetChannelStreamMediaSources(string cha return new List(); } - protected abstract Task GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List currentLiveStreams, CancellationToken cancellationToken); + protected abstract Task GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, IList currentLiveStreams, CancellationToken cancellationToken); - public async Task GetChannelStream(string channelId, string streamId, List currentLiveStreams, CancellationToken cancellationToken) + public async Task GetChannelStream(string channelId, string streamId, IList currentLiveStreams, CancellationToken cancellationToken) { ArgumentException.ThrowIfNullOrEmpty(channelId); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 8cd0c4ffb71..79e15a82e22 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -527,7 +527,7 @@ protected override async Task> GetChannelStreamMediaSource return list; } - protected override async Task GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List currentLiveStreams, CancellationToken cancellationToken) + protected override async Task GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, IList currentLiveStreams, CancellationToken cancellationToken) { var tunerCount = tunerHost.TunerCount; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index db5e81df5f0..11bf03b1822 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -96,7 +96,7 @@ public Task> GetTunerInfos(CancellationToken cancellationT return Task.FromResult(list); } - protected override async Task GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List currentLiveStreams, CancellationToken cancellationToken) + protected override async Task GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, IList currentLiveStreams, CancellationToken cancellationToken) { var tunerCount = tunerHost.TunerCount; diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 24820abb900..b9830915881 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -50,7 +50,7 @@ public interface ITunerHost /// The current live streams. /// The cancellation token to cancel operation. /// Live stream wrapped in a task. - Task GetChannelStream(string channelId, string streamId, List currentLiveStreams, CancellationToken cancellationToken); + Task GetChannelStream(string channelId, string streamId, IList currentLiveStreams, CancellationToken cancellationToken); /// /// Gets the channel stream media sources. From 669baf98a577094c5b038c7782045b873d468c0b Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 12:41:27 -0500 Subject: [PATCH 10/11] Make IRecorder an IDisposable --- .../LiveTv/EmbyTV/DirectRecorder.cs | 7 ++++++- Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs | 2 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 4 ++-- Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index ec4dbde30d5..ddf7b882a72 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -14,7 +14,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { - public class DirectRecorder : IRecorder + public sealed class DirectRecorder : IRecorder { private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; @@ -109,5 +109,10 @@ await using (output.ConfigureAwait(false)) _logger.LogInformation("Recording completed to file {0}", targetFile); } } + + /// + public void Dispose() + { + } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index cba24ca459f..abe3ff349f0 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1269,7 +1269,7 @@ private async Task RecordStream(TimerInfo timer, DateTime recordingEndDate, Acti directStreamProvider = liveStreamResponse.Item2; } - var recorder = GetRecorder(mediaStreamInfo); + using var recorder = GetRecorder(mediaStreamInfo); recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath); recordPath = EnsureFileUnique(recordPath, timer.Id); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index b548a92b19c..9a9fd027392 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { - public class EncodedRecorder : IRecorder, IDisposable + public class EncodedRecorder : IRecorder { private readonly ILogger _logger; private readonly IMediaEncoder _mediaEncoder; @@ -37,7 +37,7 @@ public class EncodedRecorder : IRecorder, IDisposable private FileStream _logFileStream; private string _targetPath; private Process _process; - private bool _disposed = false; + private bool _disposed; public EncodedRecorder( ILogger logger, diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs index 7705132da27..de14d6d086a 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs @@ -8,7 +8,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { - public interface IRecorder + public interface IRecorder : IDisposable { /// /// Records the specified media source. From 192559db32ef60b2a56b7acf689b6edc3cdc3487 Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Tue, 5 Dec 2023 14:26:35 -0500 Subject: [PATCH 11/11] Make ILiveStream an IDisposable --- .../Library/ExclusiveLiveStream.cs | 7 ++++++- .../LiveTv/TunerHosts/LiveStream.cs | 15 +++++++++++++++ MediaBrowser.Controller/Library/ILiveStream.cs | 3 ++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs index 868071a9922..b1649afad54 100644 --- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs +++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Library { - public class ExclusiveLiveStream : ILiveStream + public sealed class ExclusiveLiveStream : ILiveStream { private readonly Func _closeFn; @@ -51,5 +51,10 @@ public Task Open(CancellationToken openCancellationToken) { return Task.CompletedTask; } + + /// + public void Dispose() + { + } } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index c0ba8710ffc..c18594a29b4 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -112,6 +112,21 @@ public Stream GetStream() return stream; } + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + LiveStreamCancellationTokenSource?.Dispose(); + } + } + protected async Task DeleteTempFiles(string path, int retryCount = 0) { if (retryCount == 0) diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs index 4c44a17fddb..bf64aca0f0b 100644 --- a/MediaBrowser.Controller/Library/ILiveStream.cs +++ b/MediaBrowser.Controller/Library/ILiveStream.cs @@ -2,6 +2,7 @@ #pragma warning disable CA1711, CS1591 +using System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -9,7 +10,7 @@ namespace MediaBrowser.Controller.Library { - public interface ILiveStream + public interface ILiveStream : IDisposable { int ConsumerCount { get; set; }