2
0
Эх сурвалжийг харах

Merge pull request #10682 from barronpm/livetv-warnings

Fix some warnings in LiveTV
Bond-009 1 жил өмнө
parent
commit
053c3392f4

+ 6 - 1
Emby.Server.Implementations/Library/ExclusiveLiveStream.cs

@@ -12,7 +12,7 @@ using MediaBrowser.Model.Dto;
 
 namespace Emby.Server.Implementations.Library
 {
-    public class ExclusiveLiveStream : ILiveStream
+    public sealed class ExclusiveLiveStream : ILiveStream
     {
         private readonly Func<Task> _closeFn;
 
@@ -51,5 +51,10 @@ namespace Emby.Server.Implementations.Library
         {
             return Task.CompletedTask;
         }
+
+        /// <inheritdoc />
+        public void Dispose()
+        {
+        }
     }
 }

+ 30 - 15
Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs

@@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging;
 
 namespace Emby.Server.Implementations.LiveTv.EmbyTV
 {
-    public class DirectRecorder : IRecorder
+    public sealed class DirectRecorder : IRecorder
     {
         private readonly ILogger _logger;
         private readonly IHttpClientFactory _httpClientFactory;
@@ -46,7 +46,15 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
         {
             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,31 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 
             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);
+            var output = new FileStream(targetFile, FileMode.CreateNew, FileAccess.Write, FileShare.Read, IODefaults.CopyToBufferSize, FileOptions.Asynchronous);
+            await using (output.ConfigureAwait(false))
+            {
+                onStarted();
 
-            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);
+        /// <inheritdoc />
+        public void Dispose()
+        {
         }
     }
 }

+ 4 - 14
Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -37,12 +37,11 @@ using MediaBrowser.Model.IO;
 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 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 
         private readonly SemaphoreSlim _recordingDeleteSemaphore = new SemaphoreSlim(1, 1);
 
-        private bool _disposed = false;
+        private bool _disposed;
 
         public EmbyTV(
             IServerApplicationHost appHost,
@@ -1270,7 +1269,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                     directStreamProvider = liveStreamResponse.Item2;
                 }
 
-                var recorder = GetRecorder(mediaStreamInfo);
+                using var recorder = GetRecorder(mediaStreamInfo);
 
                 recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
                 recordPath = EnsureFileUnique(recordPath, timer.Id);
@@ -2524,22 +2523,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
 
         /// <inheritdoc />
         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())
             {

+ 4 - 4
Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs

@@ -25,7 +25,7 @@ using Microsoft.Extensions.Logging;
 
 namespace Emby.Server.Implementations.LiveTv.EmbyTV
 {
-    public class EncodedRecorder : IRecorder, IDisposable
+    public class EncodedRecorder : IRecorder
     {
         private readonly ILogger _logger;
         private readonly IMediaEncoder _mediaEncoder;
@@ -34,10 +34,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
         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;
+        private bool _disposed;
 
         public EncodedRecorder(
             ILogger logger,
@@ -308,7 +308,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
             }
         }
 
-        private async Task StartStreamingLog(Stream source, Stream target)
+        private async Task StartStreamingLog(Stream source, FileStream target)
         {
             try
             {

+ 1 - 1
Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs

@@ -8,7 +8,7 @@ using MediaBrowser.Model.Dto;
 
 namespace Emby.Server.Implementations.LiveTv.EmbyTV
 {
-    public interface IRecorder
+    public interface IRecorder : IDisposable
     {
         /// <summary>
         /// Records the specified media source.

+ 2 - 2
Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -287,7 +287,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                 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 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                 return null;
             }
 
-            if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1)
+            if (uri.Contains("http", StringComparison.OrdinalIgnoreCase))
             {
                 return uri;
             }

+ 33 - 18
Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs

@@ -84,38 +84,53 @@ namespace Emby.Server.Implementations.LiveTv.Listings
                 _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<string> 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<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)

+ 1 - 1
Emby.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -1101,7 +1101,7 @@ namespace Emby.Server.Implementations.LiveTv
             progress.Report(100);
         }
 
-        private async Task<Tuple<List<Guid>, List<Guid>>> RefreshChannelsInternal(ILiveTvService service, IProgress<double> progress, CancellationToken cancellationToken)
+        private async Task<Tuple<List<Guid>, List<Guid>>> RefreshChannelsInternal(ILiveTvService service, ActionableProgress<double> progress, CancellationToken cancellationToken)
         {
             progress.Report(10);
 

+ 16 - 9
Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs

@@ -67,7 +67,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             return list;
         }
 
-        protected virtual List<TunerHostInfo> GetTunerHosts()
+        protected virtual IList<TunerHostInfo> GetTunerHosts()
         {
             return GetConfiguration().TunerHosts
                 .Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase))
@@ -96,8 +96,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                         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 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                     {
                         try
                         {
-                            await using var readStream = AsyncFile.OpenRead(channelCacheFile);
-                            var channels = await JsonSerializer.DeserializeAsync<List<ChannelInfo>>(readStream, cancellationToken: cancellationToken)
-                                .ConfigureAwait(false);
-                            list.AddRange(channels);
+                            var readStream = AsyncFile.OpenRead(channelCacheFile);
+                            await using (readStream.ConfigureAwait(false))
+                            {
+                                var channels = await JsonSerializer
+                                    .DeserializeAsync<List<ChannelInfo>>(readStream, cancellationToken: cancellationToken)
+                                    .ConfigureAwait(false);
+                                list.AddRange(channels);
+                            }
                         }
                         catch (IOException)
                         {
@@ -159,9 +166,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             return new List<MediaSourceInfo>();
         }
 
-        protected abstract Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
+        protected abstract Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, IList<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
 
-        public async Task<ILiveStream> GetChannelStream(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
+        public async Task<ILiveStream> GetChannelStream(string channelId, string streamId, IList<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
         {
             ArgumentException.ThrowIfNullOrEmpty(channelId);
 

+ 1 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs

@@ -30,7 +30,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             {
                 var model = ModelNumber ?? string.Empty;
 
-                if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)
+                if (model.Contains("hdtc", StringComparison.OrdinalIgnoreCase))
                 {
                     return true;
                 }

+ 1 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs

@@ -527,7 +527,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
             return list;
         }
 
-        protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
+        protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, IList<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
         {
             var tunerCount = tunerHost.TunerCount;
 

+ 16 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs

@@ -112,6 +112,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             return stream;
         }
 
+        /// <inheritdoc />
+        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)
@@ -134,7 +149,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             }
         }
 
-        private void TrySeek(Stream stream, long offset)
+        private void TrySeek(FileStream stream, long offset)
         {
             if (!stream.CanSeek)
             {

+ 1 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs

@@ -96,7 +96,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             return Task.FromResult(list);
         }
 
-        protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
+        protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo tunerHost, ChannelInfo channel, string streamId, IList<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
         {
             var tunerCount = tunerHost.TunerCount;
 

+ 1 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs

@@ -66,7 +66,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 .ConfigureAwait(false);
             response.EnsureSuccessStatusCode();
 
-            return await response.Content.ReadAsStreamAsync(cancellationToken);
+            return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
         }
 
         private async Task<List<ChannelInfo>> GetChannelsAsync(TextReader reader, string channelIdPrefix, string tunerHostId)

+ 21 - 8
Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs

@@ -83,14 +83,27 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                         Logger.LogInformation("Beginning {StreamType} stream to {FilePath}", GetType().Name, TempFilePath);
                         using (response)
                         {
-                            await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
-                            await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
-                            await StreamHelper.CopyToAsync(
-                                stream,
-                                fileStream,
-                                IODefaults.CopyToBufferSize,
-                                () => 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)

+ 2 - 1
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 @@ using MediaBrowser.Model.Dto;
 
 namespace MediaBrowser.Controller.Library
 {
-    public interface ILiveStream
+    public interface ILiveStream : IDisposable
     {
         int ConsumerCount { get; set; }
 

+ 1 - 1
MediaBrowser.Controller/LiveTv/ITunerHost.cs

@@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="currentLiveStreams">The current live streams.</param>
         /// <param name="cancellationToken">The cancellation token to cancel operation.</param>
         /// <returns>Live stream wrapped in a task.</returns>
-        Task<ILiveStream> GetChannelStream(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
+        Task<ILiveStream> GetChannelStream(string channelId, string streamId, IList<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
 
         /// <summary>
         /// Gets the channel stream media sources.