Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix some warnings in LiveTV #10682

Merged
merged 11 commits into from
Dec 18, 2023
7 changes: 6 additions & 1 deletion Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace Emby.Server.Implementations.Library
{
public class ExclusiveLiveStream : ILiveStream
public sealed class ExclusiveLiveStream : ILiveStream
{
private readonly Func<Task> _closeFn;

Expand Down Expand Up @@ -51,5 +51,10 @@ public Task Open(CancellationToken openCancellationToken)
{
return Task.CompletedTask;
}

/// <inheritdoc />
public void Dispose()
{
}
}
}
45 changes: 30 additions & 15 deletions Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -80,24 +88,31 @@ 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);
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()
{
}
}
}
18 changes: 4 additions & 14 deletions Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1270,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);
Expand Down Expand Up @@ -2524,22 +2523,13 @@ private bool IsProgramAlreadyInLibrary(TimerInfo program)

/// <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())
{
Expand Down
8 changes: 4 additions & 4 deletions Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,10 +34,10 @@ 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;
private bool _disposed;

public EncodedRecorder(
ILogger logger,
Expand Down Expand Up @@ -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
{
Expand Down
2 changes: 1 addition & 1 deletion Emby.Server.Implementations/LiveTv/EmbyTV/IRecorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
public interface IRecorder
public interface IRecorder : IDisposable
{
/// <summary>
/// Records the specified media source.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -414,7 +414,7 @@ private static string GetProgramImage(string apiUrl, IEnumerable<ImageDataDto> i
return null;
}

if (uri.IndexOf("http", StringComparison.OrdinalIgnoreCase) != -1)
if (uri.Contains("http", StringComparison.OrdinalIgnoreCase))
{
return uri;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,38 +84,53 @@ private async Task<string> 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<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)
Expand Down
2 changes: 1 addition & 1 deletion Emby.Server.Implementations/LiveTv/LiveTvManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ private async Task RefreshChannelsInternal(IProgress<double> progress, Cancellat
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);

Expand Down
25 changes: 16 additions & 9 deletions Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public async Task<List<ChannelInfo>> GetChannels(TunerHostInfo tuner, bool enabl
return list;
}

protected virtual List<TunerHostInfo> GetTunerHosts()
protected virtual IList<TunerHostInfo> GetTunerHosts()
{
return GetConfiguration().TunerHosts
.Where(i => string.Equals(i.Type, Type, StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -96,8 +96,11 @@ public async Task<List<ChannelInfo>> 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)
{
Expand All @@ -112,10 +115,14 @@ public async Task<List<ChannelInfo>> GetChannels(bool enableCache, CancellationT
{
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)
{
Expand Down Expand Up @@ -159,9 +166,9 @@ public async Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string cha
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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ protected override async Task<List<MediaSourceInfo>> GetChannelStreamMediaSource
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;

Expand Down
17 changes: 16 additions & 1 deletion Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,21 @@ public Stream GetStream()
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)
Expand All @@ -134,7 +149,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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationT
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;

Expand Down