diff options
34 files changed, 209 insertions, 148 deletions
diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs index 868071a99..b1649afad 100644 --- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs +++ b/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() + { + } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 49833de73..ddf7b882a 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/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() + { } } } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 74b62ca3f..abe3ff349 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/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); @@ -2525,21 +2524,12 @@ 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()) { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 5369c9b3d..9a9fd0273 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/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 { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs index 7705132da..de14d6d08 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs +++ b/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. diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 6b0520ad0..5be3a7488 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/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; } diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 066afb956..e60e9dcc1 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/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) diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index db06e4784..0544e2a4b 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/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); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index ff25ee585..da597056a 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/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); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs index 42068cd34..39b357142 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/DiscoverResponse.cs +++ b/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; } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 8cd0c4ffb..79e15a82e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/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; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 767b94136..c18594a29 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/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) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index db5e81df5..11bf03b18 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/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; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 341782d9d..0b5575b99 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/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) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 51f46f4da..efb84a515 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/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) diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs index 4c44a17fd..bf64aca0f 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 @@ using MediaBrowser.Model.Dto; namespace MediaBrowser.Controller.Library { - public interface ILiveStream + public interface ILiveStream : IDisposable { int ConsumerCount { get; set; } diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 24820abb9..b98309158 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/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. diff --git a/deployment/build.centos.amd64 b/deployment/build.centos.amd64 index 0374624d8..a0ab93e4e 100755 --- a/deployment/build.centos.amd64 +++ b/deployment/build.centos.amd64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" if [[ ${IS_DOCKER} == YES ]]; then # Remove BuildRequires for dotnet, since it's installed manually @@ -39,10 +39,10 @@ make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS rpmbuild --rebuild -bb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm # Move the artifacts out -mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/ +mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi rm -f fedora/jellyfin*.tar.gz @@ -51,7 +51,7 @@ if [[ ${IS_DOCKER} == YES ]]; then pushd fedora cp -a /tmp/spec.orig jellyfin.spec - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" popd fi diff --git a/deployment/build.debian.amd64 b/deployment/build.debian.amd64 index 7e968192b..1a59d02e9 100755 --- a/deployment/build.debian.amd64 +++ b/deployment/build.debian.amd64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" if [[ ${IS_DOCKER} == YES ]]; then # Remove build-dep for dotnet-sdk-8.0, since it's installed manually @@ -32,12 +32,12 @@ fi # Build DEB dpkg-buildpackage -us -uc --pre-clean --post-clean -mkdir -p ${ARTIFACT_DIR}/ -mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then cp -a /tmp/control.orig debian/control - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.debian.arm64 b/deployment/build.debian.arm64 index 7b7b603d6..e1e30fab4 100755 --- a/deployment/build.debian.arm64 +++ b/deployment/build.debian.arm64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" if [[ ${IS_DOCKER} == YES ]]; then # Remove build-dep for dotnet-sdk-8.0, since it's installed manually @@ -33,12 +33,12 @@ fi export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH} dpkg-buildpackage -us -uc -a arm64 --pre-clean --post-clean -mkdir -p ${ARTIFACT_DIR}/ -mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then cp -a /tmp/control.orig debian/control - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.debian.armhf b/deployment/build.debian.armhf index 3d894ba20..e3e8ae004 100755 --- a/deployment/build.debian.armhf +++ b/deployment/build.debian.armhf @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" if [[ ${IS_DOCKER} == YES ]]; then # Remove build-dep for dotnet-sdk-8.0, since it's installed manually @@ -33,12 +33,12 @@ fi export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH} dpkg-buildpackage -us -uc -a armhf --pre-clean --post-clean -mkdir -p ${ARTIFACT_DIR}/ -mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then cp -a /tmp/control.orig debian/control - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.fedora.amd64 b/deployment/build.fedora.amd64 index 1b629289f..da345ec08 100755 --- a/deployment/build.fedora.amd64 +++ b/deployment/build.fedora.amd64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" if [[ ${IS_DOCKER} == YES ]]; then # Remove BuildRequires for dotnet, since it's installed manually @@ -39,10 +39,10 @@ make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS rpmbuild -rb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm # Move the artifacts out -mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/ +mv /root/rpmbuild/RPMS/x86_64/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi rm -f fedora/jellyfin*.tar.gz @@ -51,7 +51,7 @@ if [[ ${IS_DOCKER} == YES ]]; then pushd fedora cp -a /tmp/spec.orig jellyfin.spec - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" popd fi diff --git a/deployment/build.linux.amd64 b/deployment/build.linux.amd64 index 05059e4ed..c6baa61f6 100755 --- a/deployment/build.linux.amd64 +++ b/deployment/build.linux.amd64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -21,11 +21,11 @@ tar -czf jellyfin-server_${version}_linux-amd64.tar.gz -C dist jellyfin-server_$ rm -rf dist/jellyfin-server_${version} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv jellyfin[-_]*.tar.gz "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.linux.amd64-musl b/deployment/build.linux.amd64-musl index 0ee4b05fb..6523f8319 100755 --- a/deployment/build.linux.amd64-musl +++ b/deployment/build.linux.amd64-musl @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -21,11 +21,11 @@ tar -czf jellyfin-server_${version}_linux-amd64-musl.tar.gz -C dist jellyfin-ser rm -rf dist/jellyfin-server_${version} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv jellyfin[-_]*.tar.gz "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.linux.arm64 b/deployment/build.linux.arm64 index 6e36db0eb..6d6a8f803 100755 --- a/deployment/build.linux.arm64 +++ b/deployment/build.linux.arm64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -21,11 +21,11 @@ tar -czf jellyfin-server_${version}_linux-arm64.tar.gz -C dist jellyfin-server_$ rm -rf dist/jellyfin-server_${version} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv jellyfin[-_]*.tar.gz "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.linux.armhf b/deployment/build.linux.armhf index f83eeebf1..5167dfcb8 100755 --- a/deployment/build.linux.armhf +++ b/deployment/build.linux.armhf @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -21,11 +21,11 @@ tar -czf jellyfin-server_${version}_linux-armhf.tar.gz -C dist jellyfin-server_$ rm -rf dist/jellyfin-server_${version} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv jellyfin[-_]*.tar.gz "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.linux.musl-linux-arm64 b/deployment/build.linux.musl-linux-arm64 index 38826ae7f..57980314d 100755 --- a/deployment/build.linux.musl-linux-arm64 +++ b/deployment/build.linux.musl-linux-arm64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -21,11 +21,11 @@ tar -czf jellyfin-server_${version}_linux-arm64-musl.tar.gz -C dist jellyfin-ser rm -rf dist/jellyfin-server_${version} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv jellyfin[-_]*.tar.gz "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.macos.amd64 b/deployment/build.macos.amd64 index eac353877..c7711e82c 100755 --- a/deployment/build.macos.amd64 +++ b/deployment/build.macos.amd64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -21,11 +21,11 @@ tar -czf jellyfin-server_${version}_macos-amd64.tar.gz -C dist jellyfin-server_$ rm -rf dist/jellyfin-server_${version} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv jellyfin[-_]*.tar.gz "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.macos.arm64 b/deployment/build.macos.arm64 index 42da07e2f..b07eaad4e 100755 --- a/deployment/build.macos.arm64 +++ b/deployment/build.macos.arm64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -21,11 +21,11 @@ tar -czf jellyfin-server_${version}_macos-arm64.tar.gz -C dist jellyfin-server_$ rm -rf dist/jellyfin-server_${version} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv jellyfin[-_]*.tar.gz "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.portable b/deployment/build.portable index 27e5e987f..ec151d295 100755 --- a/deployment/build.portable +++ b/deployment/build.portable @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -21,11 +21,11 @@ tar -czf jellyfin-server_${version}_portable.tar.gz -C dist jellyfin-server_${ve rm -rf dist/jellyfin-server_${version} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv jellyfin[-_]*.tar.gz "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.ubuntu.amd64 b/deployment/build.ubuntu.amd64 index 5f25cb610..17968a6e9 100755 --- a/deployment/build.ubuntu.amd64 +++ b/deployment/build.ubuntu.amd64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" if [[ ${IS_DOCKER} == YES ]]; then # Remove build-dep for dotnet-sdk-8.0, since it's installed manually @@ -32,12 +32,12 @@ fi # Build DEB dpkg-buildpackage -us -uc --pre-clean --post-clean -mkdir -p ${ARTIFACT_DIR}/ -mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then cp -a /tmp/control.orig debian/control - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.ubuntu.arm64 b/deployment/build.ubuntu.arm64 index 334ced997..ee7da9bb9 100755 --- a/deployment/build.ubuntu.arm64 +++ b/deployment/build.ubuntu.arm64 @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" if [[ ${IS_DOCKER} == YES ]]; then # Remove build-dep for dotnet-sdk-8.0, since it's installed manually @@ -33,12 +33,12 @@ fi export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH} dpkg-buildpackage -us -uc -a arm64 --pre-clean --post-clean -mkdir -p ${ARTIFACT_DIR}/ -mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then cp -a /tmp/control.orig debian/control - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.ubuntu.armhf b/deployment/build.ubuntu.armhf index 77e33c307..85c993282 100755 --- a/deployment/build.ubuntu.armhf +++ b/deployment/build.ubuntu.armhf @@ -6,7 +6,7 @@ set -o errexit set -o xtrace # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" if [[ ${IS_DOCKER} == YES ]]; then # Remove build-dep for dotnet-sdk-8.0, since it's installed manually @@ -33,12 +33,12 @@ fi export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH} dpkg-buildpackage -us -uc -a armhf --pre-clean --post-clean -mkdir -p ${ARTIFACT_DIR}/ -mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then cp -a /tmp/control.orig debian/control - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd diff --git a/deployment/build.windows.amd64 b/deployment/build.windows.amd64 index 0786358bd..20f976365 100755 --- a/deployment/build.windows.amd64 +++ b/deployment/build.windows.amd64 @@ -11,7 +11,7 @@ NSSM_URL="http://files.evilt.win/nssm/${NSSM_VERSION}.zip" FFMPEG_URL="https://repo.jellyfin.org/releases/server/windows/ffmpeg/jellyfin-ffmpeg-portable_win64.zip"; # Move to source directory -pushd ${SOURCE_DIR} +pushd "${SOURCE_DIR}" # Get version if [[ ${IS_UNSTABLE} == 'yes' ]]; then @@ -42,11 +42,11 @@ popd rm -rf ${output_dir} # Move the artifacts out -mkdir -p ${ARTIFACT_DIR}/ -mv dist/jellyfin[-_]*.zip ${ARTIFACT_DIR}/ +mkdir -p "${ARTIFACT_DIR}/" +mv dist/jellyfin[-_]*.zip "${ARTIFACT_DIR}/" if [[ ${IS_DOCKER} == YES ]]; then - chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} + chown -Rc $(stat -c %u:%g "${ARTIFACT_DIR}") "${ARTIFACT_DIR}" fi popd |
