From 12a7fda0a6216c506853941eeabaca6367e0a8a8 Mon Sep 17 00:00:00 2001 From: cvium Date: Tue, 17 Aug 2021 19:18:26 +0200 Subject: Add timeout to ProgressiveFileStream --- Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Api/Helpers/ProgressiveFileStream.cs') diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index 824870c7e..499dbe84d 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Threading; @@ -16,6 +17,7 @@ namespace Jellyfin.Api.Helpers private readonly FileStream _fileStream; private readonly TranscodingJobDto? _job; private readonly TranscodingJobHelper _transcodingJobHelper; + private readonly int _timeoutMs; private readonly bool _allowAsyncFileRead; private int _bytesWritten; private bool _disposed; @@ -26,10 +28,12 @@ namespace Jellyfin.Api.Helpers /// The path to the transcoded file. /// The transcoding job information. /// The transcoding job helper. - public ProgressiveFileStream(string filePath, TranscodingJobDto? job, TranscodingJobHelper transcodingJobHelper) + /// The timeout duration in milliseconds. + public ProgressiveFileStream(string filePath, TranscodingJobDto? job, TranscodingJobHelper transcodingJobHelper, int timeoutMs = 30000) { _job = job; _transcodingJobHelper = transcodingJobHelper; + _timeoutMs = timeoutMs; _bytesWritten = 0; var fileOptions = FileOptions.SequentialScan; @@ -81,6 +85,7 @@ namespace Jellyfin.Api.Helpers { int totalBytesRead = 0; int remainingBytesToRead = count; + var stopwatch = Stopwatch.StartNew(); int newOffset = offset; while (remainingBytesToRead > 0) @@ -111,8 +116,8 @@ namespace Jellyfin.Api.Helpers } else { - // If the job is null it's a live stream and will require user action to close - if (_job?.HasExited ?? false) + // If the job is null it's a live stream and will require user action to close, but don't keep it open indefinitely + if (_job?.HasExited ?? stopwatch.ElapsedMilliseconds > _timeoutMs) { break; } -- cgit v1.2.3 From e3dac4fda2033801085eb7086a3a534c473a00a0 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 12 Jun 2021 22:20:35 +0200 Subject: Use async FileStreams where it makes sense --- Emby.Dlna/DlnaManager.cs | 2 +- Emby.Drawing/ImageProcessor.cs | 2 +- .../Channels/ChannelManager.cs | 4 +- .../IO/ManagedFileSystem.cs | 2 +- .../Library/LiveStreamHelper.cs | 5 +- .../Library/MediaSourceManager.cs | 2 +- .../LiveTv/EmbyTV/DirectRecorder.cs | 4 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 2 +- .../LiveTv/TunerHosts/BaseTunerHost.cs | 4 +- .../LiveTv/TunerHosts/LiveStream.cs | 4 +- .../LiveTv/TunerHosts/M3uParser.cs | 3 +- .../LiveTv/TunerHosts/SharedHttpStream.cs | 62 +++++++++++----------- .../Plugins/PluginManager.cs | 3 +- .../Serialization/MyXmlSerializer.cs | 2 +- Jellyfin.Api/Controllers/ImageByNameController.cs | 2 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 2 +- Jellyfin.Api/Controllers/SystemController.cs | 2 +- Jellyfin.Api/Helpers/HlsHelpers.cs | 2 +- Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | 3 +- Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 2 +- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 2 +- .../Users/DefaultPasswordResetProvider.cs | 5 +- Jellyfin.Server/Program.cs | 3 +- .../Attachments/AttachmentExtractor.cs | 2 +- .../BdInfo/BdInfoFileInfo.cs | 6 +-- .../Probing/ProbeResultNormalizer.cs | 2 +- .../Subtitles/SubtitleEncoder.cs | 8 +-- MediaBrowser.Model/IO/AsyncFile.cs | 34 ++++++++++++ MediaBrowser.Providers/Manager/ImageSaver.cs | 2 +- .../Manager/ItemImageProvider.cs | 2 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- .../Plugins/AudioDb/AudioDbAlbumImageProvider.cs | 3 +- .../Plugins/AudioDb/AudioDbAlbumProvider.cs | 4 +- .../Plugins/AudioDb/AudioDbArtistImageProvider.cs | 3 +- .../Plugins/AudioDb/AudioDbArtistProvider.cs | 4 +- .../Plugins/Omdb/OmdbProvider.cs | 22 ++------ .../Studios/StudiosImageProvider.cs | 2 +- .../Subtitles/SubtitleManager.cs | 2 +- .../FFprobeParserTests.cs | 3 +- 40 files changed, 127 insertions(+), 100 deletions(-) create mode 100644 MediaBrowser.Model/IO/AsyncFile.cs (limited to 'Jellyfin.Api/Helpers/ProgressiveFileStream.cs') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index af70793cc..68fc80c0a 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -366,7 +366,7 @@ namespace Emby.Dlna Directory.CreateDirectory(systemProfilesPath); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) { await stream.CopyToAsync(fileStream).ConfigureAwait(false); } diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 7d952aa23..0ad8bca31 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -102,7 +102,7 @@ namespace Emby.Drawing { var file = await ProcessImage(options).ConfigureAwait(false); - using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, true)) + using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index aa54510a7..1478e9313 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -815,7 +815,7 @@ namespace Emby.Server.Implementations.Channels { if (_fileSystem.GetLastWriteTimeUtc(cachePath).Add(cacheLength) > DateTime.UtcNow) { - await using FileStream jsonStream = File.OpenRead(cachePath); + await using FileStream jsonStream = AsyncFile.OpenRead(cachePath); var cachedResult = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (cachedResult != null) { @@ -838,7 +838,7 @@ namespace Emby.Server.Implementations.Channels { if (_fileSystem.GetLastWriteTimeUtc(cachePath).Add(cacheLength) > DateTime.UtcNow) { - await using FileStream jsonStream = File.OpenRead(cachePath); + await using FileStream jsonStream = AsyncFile.OpenRead(cachePath); var cachedResult = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (cachedResult != null) { diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 7c3c7da23..af0d88ea5 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -248,7 +248,7 @@ namespace Emby.Server.Implementations.IO { try { - using (Stream thisFileStream = File.OpenRead(fileInfo.FullName)) + using (Stream thisFileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, 1)) { result.Length = thisFileStream.Length; } diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs index 806269182..16b45161f 100644 --- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs +++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs @@ -17,6 +17,7 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging; @@ -49,7 +50,7 @@ namespace Emby.Server.Implementations.Library { try { - await using FileStream jsonStream = File.OpenRead(cacheFilePath); + await using FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath); mediaInfo = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Found cached media info"); @@ -86,7 +87,7 @@ namespace Emby.Server.Implementations.Library if (cacheFilePath != null) { Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); - await using FileStream createStream = File.OpenWrite(cacheFilePath); + await using FileStream createStream = AsyncFile.OpenWrite(cacheFilePath); await JsonSerializer.SerializeAsync(createStream, mediaInfo, _jsonOptions, cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Saved media info to {0}", cacheFilePath); diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 91c9e61cf..4e0434b92 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -638,7 +638,7 @@ namespace Emby.Server.Implementations.Library { try { - await using FileStream jsonStream = File.OpenRead(cacheFilePath); + await using FileStream jsonStream = AsyncFile.OpenRead(cacheFilePath); mediaInfo = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); // _logger.LogDebug("Found cached media info"); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index bb3d635d1..c5a9a92ec 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -46,7 +46,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) { onStarted(); @@ -72,7 +72,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None); + await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO); onStarted(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index e10bc7647..d806a0295 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); + _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index ebad4eddf..8202fab86 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew)) + await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO)) { await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 5941613cf..f87212cf3 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts try { Directory.CreateDirectory(Path.GetDirectoryName(channelCacheFile)); - await using var writeStream = File.OpenWrite(channelCacheFile); + await using var writeStream = AsyncFile.OpenWrite(channelCacheFile); await JsonSerializer.SerializeAsync(writeStream, channels, cancellationToken: cancellationToken).ConfigureAwait(false); } catch (IOException) @@ -108,7 +108,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { try { - await using var readStream = File.OpenRead(channelCacheFile); + await using var readStream = AsyncFile.OpenRead(channelCacheFile); var channels = await JsonSerializer.DeserializeAsync>(readStream, cancellationToken: cancellationToken) .ConfigureAwait(false); list.AddRange(channels); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 96a678c1d..2c21a4a89 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -155,15 +155,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, LiveStreamCancellationTokenSource.Token); cancellationToken = linkedCancellationTokenSource.Token; - // use non-async filestream on windows along with read due to https://github.com/dotnet/corefx/issues/6039 - var allowAsync = Environment.OSVersion.Platform != PlatformID.Win32NT; - bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; var nextFileInfo = GetNextFile(null); var nextFile = nextFileInfo.file; var isLastFile = nextFileInfo.isLastFile; + var allowAsync = AsyncFile.UseAsyncIO; while (!string.IsNullOrEmpty(nextFile)) { var emptyReadLimit = isLastFile ? EmptyReadLimit : 1; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index d28c39e21..23071a430 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -14,6 +14,7 @@ using Jellyfin.Extensions; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; using Microsoft.Extensions.Logging; @@ -50,7 +51,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts if (!info.Url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { - return File.OpenRead(info.Url); + return AsyncFile.OpenRead(info.Url); } using var requestMessage = new HttpRequestMessage(HttpMethod.Get, info.Url); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index f572151b8..862993877 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -129,37 +129,39 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts private Task StartStreaming(HttpResponseMessage response, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) { - return Task.Run(async () => - { - try - { - Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath); - using var message = 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); - await StreamHelper.CopyToAsync( - stream, - fileStream, - IODefaults.CopyToBufferSize, - () => Resolve(openTaskCompletionSource), - cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException ex) - { - Logger.LogInformation("Copying of {0} to {1} was canceled", GetType().Name, TempFilePath); - openTaskCompletionSource.TrySetException(ex); - } - catch (Exception ex) + return Task.Run( + async () => { - Logger.LogError(ex, "Error copying live stream {0} to {1}.", GetType().Name, TempFilePath); - openTaskCompletionSource.TrySetException(ex); - } - - openTaskCompletionSource.TrySetResult(false); - - EnableStreamSharing = false; - await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false); - }, CancellationToken.None); + try + { + Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath); + using var message = 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, AsyncFile.UseAsyncIO); + await StreamHelper.CopyToAsync( + stream, + fileStream, + IODefaults.CopyToBufferSize, + () => Resolve(openTaskCompletionSource), + cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException ex) + { + Logger.LogInformation("Copying of {0} to {1} was canceled", GetType().Name, TempFilePath); + openTaskCompletionSource.TrySetException(ex); + } + catch (Exception ex) + { + Logger.LogError(ex, "Error copying live stream {0} to {1}.", GetType().Name, TempFilePath); + openTaskCompletionSource.TrySetException(ex); + } + + openTaskCompletionSource.TrySetResult(false); + + EnableStreamSharing = false; + await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false); + }, + CancellationToken.None); } private void Resolve(TaskCompletionSource openTaskCompletionSource) diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs index fc0920edf..b8e1dc2c0 100644 --- a/Emby.Server.Implementations/Plugins/PluginManager.cs +++ b/Emby.Server.Implementations/Plugins/PluginManager.cs @@ -15,6 +15,7 @@ using Jellyfin.Extensions.Json.Converters; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.IO; using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Updates; using Microsoft.Extensions.DependencyInjection; @@ -371,7 +372,7 @@ namespace Emby.Server.Implementations.Plugins var url = new Uri(packageInfo.ImageUrl); imagePath = Path.Join(path, url.Segments[^1]); - await using var fileStream = File.OpenWrite(imagePath); + await using var fileStream = AsyncFile.OpenWrite(imagePath); try { diff --git a/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs b/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs index 5ff73de81..059211a0b 100644 --- a/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs +++ b/Emby.Server.Implementations/Serialization/MyXmlSerializer.cs @@ -72,7 +72,7 @@ namespace Emby.Server.Implementations.Serialization /// The file. public void SerializeToFile(object obj, string file) { - using (var stream = new FileStream(file, FileMode.Create)) + using (var stream = new FileStream(file, FileMode.Create, FileAccess.Write)) { SerializeToStream(obj, stream); } diff --git a/Jellyfin.Api/Controllers/ImageByNameController.cs b/Jellyfin.Api/Controllers/ImageByNameController.cs index e1b808098..99ab7f232 100644 --- a/Jellyfin.Api/Controllers/ImageByNameController.cs +++ b/Jellyfin.Api/Controllers/ImageByNameController.cs @@ -88,7 +88,7 @@ namespace Jellyfin.Api.Controllers } var contentType = MimeTypes.GetMimeType(path); - return File(System.IO.File.OpenRead(path), contentType); + return File(AsyncFile.OpenRead(path), contentType); } /// diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index ec836f43e..8fec7d6df 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -208,7 +208,7 @@ namespace Jellyfin.Api.Controllers var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid."); Directory.CreateDirectory(fullCacheDirectory); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, true); + await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath)); diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index bbbe5fb8d..e6584f0fe 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -201,7 +201,7 @@ namespace Jellyfin.Api.Controllers // For older files, assume fully static var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite; - FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare); + FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); return File(stream, "text/plain; charset=utf-8"); } diff --git a/Jellyfin.Api/Helpers/HlsHelpers.cs b/Jellyfin.Api/Helpers/HlsHelpers.cs index d1cdaf867..0c226f429 100644 --- a/Jellyfin.Api/Helpers/HlsHelpers.cs +++ b/Jellyfin.Api/Helpers/HlsHelpers.cs @@ -39,7 +39,7 @@ namespace Jellyfin.Api.Helpers FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, - FileOptions.SequentialScan); + (AsyncFile.UseAsyncIO ? FileOptions.Asynchronous : FileOptions.None) | FileOptions.SequentialScan); await using (fileStream.ConfigureAwait(false)) { using var reader = new StreamReader(fileStream); diff --git a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs index 963e17724..1fb4798ee 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs @@ -85,8 +85,7 @@ namespace Jellyfin.Api.Helpers var fileOptions = FileOptions.SequentialScan; var allowAsyncFileRead = false; - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (AsyncFile.UseAsyncIO) { fileOptions |= FileOptions.Asynchronous; allowAsyncFileRead = true; diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index 499dbe84d..82f35fc35 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Api.Helpers _allowAsyncFileRead = false; // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (AsyncFile.UseAsyncIO) { fileOptions |= FileOptions.Asynchronous; _allowAsyncFileRead = true; diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 05fa5b135..b168e6d00 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -557,7 +557,7 @@ namespace Jellyfin.Api.Helpers $"{logFilePrefix}{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{state.Request.MediaSourceId}_{Guid.NewGuid().ToString()[..8]}.log"); // FFmpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); + Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(request.Path + Environment.NewLine + Environment.NewLine + JsonSerializer.Serialize(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); diff --git a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs index c99c5e4ef..6e98ad863 100644 --- a/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs +++ b/Jellyfin.Server.Implementations/Users/DefaultPasswordResetProvider.cs @@ -10,6 +10,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.IO; using MediaBrowser.Model.Users; namespace Jellyfin.Server.Implementations.Users @@ -53,7 +54,7 @@ namespace Jellyfin.Server.Implementations.Users foreach (var resetFile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{BaseResetFileName}*")) { SerializablePasswordReset spr; - await using (var str = File.OpenRead(resetFile)) + await using (var str = AsyncFile.OpenRead(resetFile)) { spr = await JsonSerializer.DeserializeAsync(str).ConfigureAwait(false) ?? throw new ResourceNotFoundException($"Provided path ({resetFile}) is not valid."); @@ -110,7 +111,7 @@ namespace Jellyfin.Server.Implementations.Users UserName = user.Username }; - await using (FileStream fileStream = File.OpenWrite(filePath)) + await using (FileStream fileStream = AsyncFile.OpenWrite(filePath)) { await JsonSerializer.SerializeAsync(fileStream, spr).ConfigureAwait(false); await fileStream.FlushAsync().ConfigureAwait(false); diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 7018d537f..6e87c8939 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -15,6 +15,7 @@ using Jellyfin.Server.Implementations; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Extensions; +using MediaBrowser.Model.IO; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -546,7 +547,7 @@ namespace Jellyfin.Server ?? throw new InvalidOperationException($"Invalid resource path: '{ResourcePath}'"); // Copy the resource contents to the expected file path for the config file - await using Stream dst = File.Open(configPath, FileMode.CreateNew); + await using Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await resource.CopyToAsync(dst).ConfigureAwait(false); } diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index a0ec3bd90..a524aeaa9 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -89,7 +89,7 @@ namespace MediaBrowser.MediaEncoding.Attachments CancellationToken cancellationToken) { var attachmentPath = await GetReadableFile(mediaSource.Path, mediaSource.Path, mediaSource, mediaAttachment, cancellationToken).ConfigureAwait(false); - return File.OpenRead(attachmentPath); + return AsyncFile.OpenRead(attachmentPath); } private async Task GetReadableFile( diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs index 41143c259..d55688e3d 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs @@ -24,7 +24,7 @@ namespace MediaBrowser.MediaEncoding.BdInfo public bool IsDir => _impl.IsDirectory; - public System.IO.Stream OpenRead() + public Stream OpenRead() { return new FileStream( FullName, @@ -33,9 +33,9 @@ namespace MediaBrowser.MediaEncoding.BdInfo FileShare.Read); } - public System.IO.StreamReader OpenText() + public StreamReader OpenText() { - return new System.IO.StreamReader(OpenRead()); + return new StreamReader(OpenRead()); } } } diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 93093bb18..8510a2f54 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1498,7 +1498,7 @@ namespace MediaBrowser.MediaEncoding.Probing { var packetBuffer = new byte[197]; - using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1)) { fs.Read(packetBuffer); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 608ebf443..6f6178af2 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -192,7 +192,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - return File.OpenRead(fileInfo.Path); + return AsyncFile.OpenRead(fileInfo.Path); } private async Task GetReadableFile( @@ -671,7 +671,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles string text; Encoding encoding; - using (var fileStream = File.OpenRead(file)) + using (var fileStream = AsyncFile.OpenRead(file)) using (var reader = new StreamReader(fileStream, true)) { encoding = reader.CurrentEncoding; @@ -684,7 +684,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!string.Equals(text, newText, StringComparison.Ordinal)) { // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None)) + using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) using (var writer = new StreamWriter(fileStream, encoding)) { await writer.WriteAsync(newText.AsMemory(), cancellationToken).ConfigureAwait(false); @@ -750,7 +750,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } case MediaProtocol.File: - return File.OpenRead(path); + return AsyncFile.OpenRead(path); default: throw new ArgumentOutOfRangeException(nameof(protocol)); } diff --git a/MediaBrowser.Model/IO/AsyncFile.cs b/MediaBrowser.Model/IO/AsyncFile.cs new file mode 100644 index 000000000..b888a4163 --- /dev/null +++ b/MediaBrowser.Model/IO/AsyncFile.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; + +namespace MediaBrowser.Model.IO +{ + /// + /// Helper class to create async s. + /// + public static class AsyncFile + { + /// + /// Gets a value indicating whether we should use async IO on this platform. + /// . + /// + /// Returns false on Windows; otherwise true. + public static bool UseAsyncIO => !OperatingSystem.IsWindows(); + + /// + /// Opens an existing file for reading. + /// + /// The file to be opened for reading. + /// A read-only on the specified path. + public static FileStream OpenRead(string path) + => new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, UseAsyncIO); + + /// + /// Opens an existing file for writing. + /// + /// The file to be opened for writing. + /// An unshared object on the specified path with Write access. + public static FileStream OpenWrite(string path) + => new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, UseAsyncIO); + } +} diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index fb1d4f490..3763c6d14 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -264,7 +264,7 @@ namespace MediaBrowser.Providers.Manager _fileSystem.SetAttributes(path, false, false); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) { await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 607fd127b..ce3ce66fa 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -164,7 +164,7 @@ namespace MediaBrowser.Providers.Manager { var mimeType = MimeTypes.GetMimeType(response.Path); - var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, true); + var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 2dfaa372c..84d71f0b1 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -209,7 +209,7 @@ namespace MediaBrowser.Providers.Manager throw new ArgumentNullException(nameof(source)); } - var fileStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, true); + var fileStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs index 36d8eeb40..81bbc26b8 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumImageProvider.cs @@ -13,6 +13,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Plugins.AudioDb @@ -57,7 +58,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = AudioDbAlbumProvider.GetAlbumInfoPath(_config.ApplicationPaths, id); - await using FileStream jsonStream = File.OpenRead(path); + await using FileStream jsonStream = AsyncFile.OpenRead(path); var obj = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (obj != null && obj.album != null && obj.album.Count > 0) diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs index 9f2f7fc11..c1226febf 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetAlbumInfoPath(_config.ApplicationPaths, id); - await using FileStream jsonStream = File.OpenRead(path); + await using FileStream jsonStream = AsyncFile.OpenRead(path); var obj = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (obj != null && obj.album != null && obj.album.Count > 0) @@ -173,7 +173,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, true); + await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs index aa61a56f6..3ffdcdbeb 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistImageProvider.cs @@ -13,6 +13,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; namespace MediaBrowser.Providers.Plugins.AudioDb @@ -59,7 +60,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = AudioDbArtistProvider.GetArtistInfoPath(_config.ApplicationPaths, id); - await using FileStream jsonStream = File.OpenRead(path); + await using FileStream jsonStream = AsyncFile.OpenRead(path); var obj = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (obj != null && obj.artists != null && obj.artists.Count > 0) diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs index 2857c6c13..8572b3413 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs @@ -65,7 +65,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetArtistInfoPath(_config.ApplicationPaths, id); - await using FileStream jsonStream = File.OpenRead(path); + await using FileStream jsonStream = AsyncFile.OpenRead(path); var obj = await JsonSerializer.DeserializeAsync(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false); if (obj != null && obj.artists != null && obj.artists.Count > 0) @@ -155,7 +155,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb Directory.CreateDirectory(Path.GetDirectoryName(path)); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, true); + await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 1ae712e9e..1dea3dece 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -236,31 +236,17 @@ namespace MediaBrowser.Providers.Plugins.Omdb internal async Task GetRootObject(string imdbId, CancellationToken cancellationToken) { var path = await EnsureItemInfo(imdbId, cancellationToken).ConfigureAwait(false); - await using var stream = File.OpenRead(path); + await using var stream = AsyncFile.OpenRead(path); return await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); } internal async Task GetSeasonRootObject(string imdbId, int seasonId, CancellationToken cancellationToken) { var path = await EnsureSeasonInfo(imdbId, seasonId, cancellationToken).ConfigureAwait(false); - await using var stream = File.OpenRead(path); + await using var stream = AsyncFile.OpenRead(path); return await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false); } - internal static bool IsValidSeries(Dictionary seriesProviderIds) - { - if (seriesProviderIds.TryGetValue(MetadataProvider.Imdb.ToString(), out string id)) - { - // This check should ideally never be necessary but we're seeing some cases of this and haven't tracked them down yet. - if (!string.IsNullOrWhiteSpace(id)) - { - return true; - } - } - - return false; - } - /// Gets OMDB URL. /// Appends query string to URL. /// OMDB URL with optional query string. @@ -309,7 +295,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb imdbParam)); var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); + await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); return path; @@ -349,7 +335,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb seasonId)); var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); + await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); return path; diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 63e78d15e..7a057c065 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -146,7 +146,7 @@ namespace MediaBrowser.Providers.Studios Directory.CreateDirectory(Path.GetDirectoryName(file)); await using var response = await httpClient.GetStreamAsync(url, cancellationToken).ConfigureAwait(false); - await using var fileStream = new FileStream(file, FileMode.Create); + await using var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); await response.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 0c791a2fe..d6c346ba1 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -245,7 +245,7 @@ namespace MediaBrowser.Providers.Subtitles Directory.CreateDirectory(Path.GetDirectoryName(savePath)); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, true); + using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, AsyncFile.UseAsyncIO); await stream.CopyToAsync(fs).ConfigureAwait(false); return; diff --git a/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs index 2955104a2..97dbb3be0 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs @@ -3,6 +3,7 @@ using System.Text.Json; using System.Threading.Tasks; using Jellyfin.Extensions.Json; using MediaBrowser.MediaEncoding.Probing; +using MediaBrowser.Model.IO; using Xunit; namespace Jellyfin.MediaEncoding.Tests @@ -14,7 +15,7 @@ namespace Jellyfin.MediaEncoding.Tests public async Task Test(string fileName) { var path = Path.Join("Test Data", fileName); - await using (var stream = File.OpenRead(path)) + await using (var stream = AsyncFile.OpenRead(path)) { var res = await JsonSerializer.DeserializeAsync(stream, JsonDefaults.Options).ConfigureAwait(false); Assert.NotNull(res); -- cgit v1.2.3 From 3d0b1ccae661704371041aadafc9816a223b1ea0 Mon Sep 17 00:00:00 2001 From: Fernando Fernández Date: Mon, 6 Sep 2021 21:15:21 +0200 Subject: Remove all unused usings --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 2 -- Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs | 1 - Emby.Server.Implementations/IO/ManagedFileSystem.cs | 2 -- Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs | 1 - Jellyfin.Api/Controllers/ApiKeyController.cs | 1 - Jellyfin.Api/Controllers/DynamicHlsController.cs | 1 - Jellyfin.Api/Controllers/ItemLookupController.cs | 4 ---- Jellyfin.Api/Controllers/LiveTvController.cs | 1 - Jellyfin.Api/Controllers/MoviesController.cs | 1 - Jellyfin.Api/Controllers/RemoteImageController.cs | 3 --- Jellyfin.Api/Controllers/SuggestionsController.cs | 1 - Jellyfin.Api/Controllers/VideoHlsController.cs | 3 --- Jellyfin.Api/Controllers/VideosController.cs | 2 -- Jellyfin.Api/Helpers/AudioHelper.cs | 2 -- Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 2 -- Jellyfin.Api/Helpers/HlsHelpers.cs | 1 - Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | 1 - Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 1 - MediaBrowser.Controller/IServerApplicationHost.cs | 1 - MediaBrowser.Controller/Library/NameExtensions.cs | 1 - MediaBrowser.Controller/MediaEncoding/JobLogger.cs | 1 - MediaBrowser.Controller/Security/IAuthenticationManager.cs | 1 - MediaBrowser.Controller/Session/ISessionManager.cs | 2 -- MediaBrowser.Model/Dlna/DirectPlayProfile.cs | 1 - MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs | 1 - MediaBrowser.Model/Dlna/TranscodingProfile.cs | 1 - MediaBrowser.Providers/Manager/ItemImageProvider.cs | 1 - MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs | 1 - MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs | 1 - .../Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs | 1 - MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs | 1 - RSSDP/SsdpCommunicationsServer.cs | 1 - src/Jellyfin.Extensions/DictionaryExtensions.cs | 1 - .../Json/Converters/JsonCommaDelimitedArrayConverter.cs | 7 +------ .../Json/Converters/JsonPipeDelimitedArrayConverter.cs | 7 +------ tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs | 7 ------- .../Json/Converters/JsonBoolNumberTests.cs | 1 - .../Probing/ProbeResultNormalizerTests.cs | 1 - tests/Jellyfin.Server.Tests/ParseNetworkTests.cs | 3 --- tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs | 1 - 40 files changed, 2 insertions(+), 71 deletions(-) (limited to 'Jellyfin.Api/Helpers/ProgressiveFileStream.cs') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 30f88c796..88fc5018d 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -16,7 +16,6 @@ using Emby.Server.Implementations.Playlists; using Jellyfin.Data.Enums; using Jellyfin.Extensions; using Jellyfin.Extensions.Json; -using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -25,7 +24,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Persistence; diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 0a4efd73c..640754af4 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -9,7 +9,6 @@ using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Data.Events; using Jellyfin.Networking.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index f2f950ecb..1bc229b0c 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -5,11 +5,9 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Model.IO; -using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.IO diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index a1562abd3..4d8a6494c 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -8,7 +8,6 @@ using System.IO; using Emby.Naming.TV; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index 720b22b1d..8e0332d3e 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -1,4 +1,3 @@ -using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index fbfb47215..a54003357 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index 9fa307858..448510c06 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -1,13 +1,10 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.IO; using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; -using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -17,7 +14,6 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index b20eae750..93dc76729 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Linq; using System.Net.Http; using System.Net.Mime; diff --git a/Jellyfin.Api/Controllers/MoviesController.cs b/Jellyfin.Api/Controllers/MoviesController.cs index 010a3b19a..99c90d19e 100644 --- a/Jellyfin.Api/Controllers/MoviesController.cs +++ b/Jellyfin.Api/Controllers/MoviesController.cs @@ -18,7 +18,6 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Jellyfin.Api.Controllers diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index 8fec7d6df..7a2c23991 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -4,10 +4,8 @@ using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using System.Net.Http; -using System.Net.Mime; using System.Threading; using System.Threading.Tasks; -using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; @@ -16,7 +14,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index a811a29c3..97eec4bd2 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel.DataAnnotations; -using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.ModelBinders; diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 8560df2ea..9c5e968dd 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.IO; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Attributes; @@ -20,12 +19,10 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Controllers diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 5c5057c83..bc6fc904a 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -25,14 +25,12 @@ using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Net; using MediaBrowser.Model.Querying; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; namespace Jellyfin.Api.Controllers { diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index 264131905..ddcde1cf6 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -11,12 +11,10 @@ using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; -using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Net; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; namespace Jellyfin.Api.Helpers { diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index dc5d6715b..4abe4c5d5 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -18,11 +18,9 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; diff --git a/Jellyfin.Api/Helpers/HlsHelpers.cs b/Jellyfin.Api/Helpers/HlsHelpers.cs index 0c226f429..f36769dc2 100644 --- a/Jellyfin.Api/Helpers/HlsHelpers.cs +++ b/Jellyfin.Api/Helpers/HlsHelpers.cs @@ -1,7 +1,6 @@ using System; using System.Globalization; using System.IO; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Models.StreamingDtos; diff --git a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs index 1fb4798ee..81970b041 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs @@ -1,7 +1,6 @@ using System; using System.Buffers; using System.IO; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Models.PlaybackDtos; diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index 82f35fc35..d4cc0172d 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Models.PlaybackDtos; diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index b0abca367..3da0a5875 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -2,7 +2,6 @@ #pragma warning disable CS1591 -using System; using System.Collections.Generic; using System.Net; using MediaBrowser.Common; diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs index a49dcacc1..d2ed3465a 100644 --- a/MediaBrowser.Controller/Library/NameExtensions.cs +++ b/MediaBrowser.Controller/Library/NameExtensions.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; using Diacritics.Extensions; -using MediaBrowser.Controller.Extensions; namespace MediaBrowser.Controller.Library { diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index b23c95112..aa5e2c403 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -6,7 +6,6 @@ using System; using System.Globalization; using System.IO; using System.Text; -using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; diff --git a/MediaBrowser.Controller/Security/IAuthenticationManager.cs b/MediaBrowser.Controller/Security/IAuthenticationManager.cs index 29621b73e..e3d18c8c0 100644 --- a/MediaBrowser.Controller/Security/IAuthenticationManager.cs +++ b/MediaBrowser.Controller/Security/IAuthenticationManager.cs @@ -1,6 +1,5 @@ #nullable enable -using System; using System.Collections.Generic; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index cc12cb102..1f34d2bf1 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -10,8 +10,6 @@ using Jellyfin.Data.Entities.Security; using Jellyfin.Data.Events; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Security; -using MediaBrowser.Model.Devices; using MediaBrowser.Model.Session; using MediaBrowser.Model.SyncPlay; diff --git a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs index fa3ad098f..03c3a7265 100644 --- a/MediaBrowser.Model/Dlna/DirectPlayProfile.cs +++ b/MediaBrowser.Model/Dlna/DirectPlayProfile.cs @@ -1,6 +1,5 @@ #pragma warning disable CS1591 -using System.ComponentModel.DataAnnotations; using System.Xml.Serialization; namespace MediaBrowser.Model.Dlna diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index 7ce248509..93a9ae615 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs index 214578a85..709bdad31 100644 --- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs @@ -1,7 +1,6 @@ #pragma warning disable CS1591 using System.ComponentModel; -using System.ComponentModel.DataAnnotations; using System.Xml.Serialization; namespace MediaBrowser.Model.Dlna diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index a3002fc8d..4b325f2cf 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Net; diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs b/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs index aa0743bd0..449f0d259 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleDownloader.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs index b3d065929..d7f6a5fac 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs index c97affdbf..93f8902de 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs @@ -12,7 +12,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; -using MediaBrowser.Common; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs index ca3ec79b7..3a305024e 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs @@ -1,7 +1,6 @@ using System; using System.Globalization; using System.IO; -using System.Text; using System.Threading; using System.Xml; using MediaBrowser.Common.Configuration; diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs index e49c0e77b..e0116c068 100644 --- a/RSSDP/SsdpCommunicationsServer.cs +++ b/RSSDP/SsdpCommunicationsServer.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Http; diff --git a/src/Jellyfin.Extensions/DictionaryExtensions.cs b/src/Jellyfin.Extensions/DictionaryExtensions.cs index 43ed41ab1..5bb828d01 100644 --- a/src/Jellyfin.Extensions/DictionaryExtensions.cs +++ b/src/Jellyfin.Extensions/DictionaryExtensions.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace Jellyfin.Extensions diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs index 44980ec02..0d0cc2d06 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonCommaDelimitedArrayConverter.cs @@ -1,9 +1,4 @@ -using System; -using System.ComponentModel; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Jellyfin.Extensions.Json.Converters +namespace Jellyfin.Extensions.Json.Converters { /// /// Convert comma delimited string to array of type. diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs index e3e492e24..6e59fe464 100644 --- a/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs +++ b/src/Jellyfin.Extensions/Json/Converters/JsonPipeDelimitedArrayConverter.cs @@ -1,9 +1,4 @@ -using System; -using System.ComponentModel; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Jellyfin.Extensions.Json.Converters +namespace Jellyfin.Extensions.Json.Converters { /// /// Convert Pipe delimited string to array of type. diff --git a/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs b/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs index 117083815..59a6b52d1 100644 --- a/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs +++ b/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs @@ -1,13 +1,6 @@ using System; using System.Collections.Generic; -using AutoFixture; -using AutoFixture.AutoMoq; using Jellyfin.Api.Controllers; -using Jellyfin.Api.Helpers; -using Jellyfin.Api.Models.StreamingDtos; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using Moq; using Xunit; namespace Jellyfin.Api.Tests.Controllers diff --git a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs index d0e3e9456..125229ff9 100644 --- a/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs +++ b/tests/Jellyfin.Extensions.Tests/Json/Converters/JsonBoolNumberTests.cs @@ -1,4 +1,3 @@ -using System.Globalization; using System.Text.Json; using FsCheck; using FsCheck.Xunit; diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index fcb85a3ac..d002d5a34 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -4,7 +4,6 @@ using System.IO; using System.Text.Json; using Jellyfin.Extensions.Json; using MediaBrowser.MediaEncoding.Probing; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging.Abstractions; diff --git a/tests/Jellyfin.Server.Tests/ParseNetworkTests.cs b/tests/Jellyfin.Server.Tests/ParseNetworkTests.cs index b92cb165c..a1bdfa31b 100644 --- a/tests/Jellyfin.Server.Tests/ParseNetworkTests.cs +++ b/tests/Jellyfin.Server.Tests/ParseNetworkTests.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Net; -using System.Text; using Jellyfin.Networking.Configuration; using Jellyfin.Networking.Manager; using Jellyfin.Server.Extensions; diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs index ef3ca15d5..7ea45d14d 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs +++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs @@ -11,7 +11,6 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.System; using MediaBrowser.Providers.Plugins.Tmdb.Movies; using MediaBrowser.XbmcMetadata.Parsers; using Microsoft.Extensions.Logging.Abstractions; -- cgit v1.2.3 From 1603d1928e888abeccc6a5fab2e1f13aa65eea6c Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 10 Sep 2021 09:29:14 +0200 Subject: Kill ProgressiveFileCopier and seek to end for ongoing livetv --- .../Library/ExclusiveLiveStream.cs | 6 + .../Library/MediaSourceManager.cs | 18 +- .../LiveTv/EmbyTV/DirectRecorder.cs | 16 +- .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 7 +- .../LiveTv/TunerHosts/LiveStream.cs | 117 +++---------- .../LiveTv/TunerHosts/SharedHttpStream.cs | 49 ++---- Jellyfin.Api/Controllers/LiveTvController.cs | 6 +- Jellyfin.Api/Controllers/VideosController.cs | 19 +-- Jellyfin.Api/Helpers/AudioHelper.cs | 19 +-- Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | 187 --------------------- Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 37 ++-- Jellyfin.Api/Models/StreamingDtos/StreamState.cs | 3 + .../Library/IDirectStreamProvider.cs | 20 +++ MediaBrowser.Controller/Library/ILiveStream.cs | 3 + .../Library/IMediaSourceManager.cs | 15 +- 15 files changed, 136 insertions(+), 386 deletions(-) delete mode 100644 Jellyfin.Api/Helpers/ProgressiveFileCopier.cs create mode 100644 MediaBrowser.Controller/Library/IDirectStreamProvider.cs (limited to 'Jellyfin.Api/Helpers/ProgressiveFileStream.cs') diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs index 6c65b5899..9ba9f2115 100644 --- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs +++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs @@ -4,6 +4,7 @@ using System; using System.Globalization; +using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Library; @@ -41,6 +42,11 @@ namespace Emby.Server.Implementations.Library return _closeFn(); } + public Stream GetStream(bool seekNearEnd) + { + throw new NotSupportedException(); + } + public Task Open(CancellationToken openCancellationToken) { return Task.CompletedTask; diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 6f83973ba..8e4b32a9c 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -602,7 +602,7 @@ namespace Emby.Server.Implementations.Library public async Task GetLiveStreamMediaInfo(string id, CancellationToken cancellationToken) { - var liveStreamInfo = await GetLiveStreamInfo(id, cancellationToken).ConfigureAwait(false); + var liveStreamInfo = GetLiveStreamInfo(id); var mediaSource = liveStreamInfo.MediaSource; @@ -771,18 +771,18 @@ namespace Emby.Server.Implementations.Library mediaSource.InferTotalBitrate(true); } - public async Task> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken) + public Task> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(id)) { throw new ArgumentNullException(nameof(id)); } - var info = await GetLiveStreamInfo(id, cancellationToken).ConfigureAwait(false); - return new Tuple(info.MediaSource, info as IDirectStreamProvider); + var info = GetLiveStreamInfo(id); + return Task.FromResult(new Tuple(info.MediaSource, info as IDirectStreamProvider)); } - private Task GetLiveStreamInfo(string id, CancellationToken cancellationToken) + public ILiveStream GetLiveStreamInfo(string id) { if (string.IsNullOrEmpty(id)) { @@ -791,12 +791,10 @@ namespace Emby.Server.Implementations.Library if (_openStreams.TryGetValue(id, out ILiveStream info)) { - return Task.FromResult(info); - } - else - { - return Task.FromException(new ResourceNotFoundException()); + return info; } + + throw new ResourceNotFoundException(); } public async Task GetLiveStream(string id, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index c5a9a92ec..fdefa2679 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -5,6 +5,7 @@ using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Api.Helpers; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; @@ -50,16 +51,23 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { onStarted(); - _logger.LogInformation("Copying recording stream to file {0}", targetFile); + _logger.LogInformation("Copying recording to file {FilePath}", targetFile); // The media source is infinite so we need to handle stopping ourselves using var durationToken = new CancellationTokenSource(duration); using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); - - await directStreamProvider.CopyToAsync(output, cancellationTokenSource.Token).ConfigureAwait(false); + var linkedCancellationToken = cancellationTokenSource.Token; + + await using var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream(), null, null); + await _streamHelper.CopyToAsync( + fileStream, + output, + IODefaults.CopyToBufferSize, + 1000, + linkedCancellationToken).ConfigureAwait(false); } - _logger.LogInformation("Recording completed to file {0}", targetFile); + _logger.LogInformation("Recording completed: {FilePath}", targetFile); } private async Task RecordFromMediaSource(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 58e0c7448..a8f761fde 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -156,11 +156,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun await taskCompletionSource.Task.ConfigureAwait(false); } - public string GetFilePath() - { - return TempFilePath; - } - private async Task StartStreaming(UdpClient udpClient, HdHomerunManager hdHomerunManager, IPAddress remoteAddress, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) { using (udpClient) @@ -184,7 +179,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun EnableStreamSharing = false; } - await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false); + await DeleteTempFiles(TempFilePath).ConfigureAwait(false); } private async Task CopyTo(UdpClient udpClient, string file, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 2c21a4a89..4f9d34327 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -3,10 +3,8 @@ #pragma warning disable CS1591 using System; -using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; @@ -97,6 +95,18 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return Task.CompletedTask; } + public Stream GetStream(bool seekNearEnd = true) + { + var stream = GetInputStream(TempFilePath, AsyncFile.UseAsyncIO); + bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; + if (seekFile) + { + TrySeek(stream, -20000); + } + + return stream; + } + protected FileStream GetInputStream(string path, bool allowAsyncFileRead) => new FileStream( path, @@ -106,112 +116,29 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts IODefaults.FileStreamBufferSize, allowAsyncFileRead ? FileOptions.SequentialScan | FileOptions.Asynchronous : FileOptions.SequentialScan); - public Task DeleteTempFiles() - { - return DeleteTempFiles(GetStreamFilePaths()); - } - - protected async Task DeleteTempFiles(IEnumerable paths, int retryCount = 0) + protected async Task DeleteTempFiles(string path, int retryCount = 0) { if (retryCount == 0) { - Logger.LogInformation("Deleting temp files {0}", paths); - } - - var failedFiles = new List(); - - foreach (var path in paths) - { - if (!File.Exists(path)) - { - continue; - } - - try - { - FileSystem.DeleteFile(path); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error deleting file {path}", path); - failedFiles.Add(path); - } - } - - if (failedFiles.Count > 0 && retryCount <= 40) - { - await Task.Delay(500).ConfigureAwait(false); - await DeleteTempFiles(failedFiles, retryCount + 1).ConfigureAwait(false); + Logger.LogInformation("Deleting temp file {FilePath}", path); } - } - protected virtual List GetStreamFilePaths() - { - return new List { TempFilePath }; - } - - public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken) - { - using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, LiveStreamCancellationTokenSource.Token); - cancellationToken = linkedCancellationTokenSource.Token; - - bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; - - var nextFileInfo = GetNextFile(null); - var nextFile = nextFileInfo.file; - var isLastFile = nextFileInfo.isLastFile; - - var allowAsync = AsyncFile.UseAsyncIO; - while (!string.IsNullOrEmpty(nextFile)) - { - var emptyReadLimit = isLastFile ? EmptyReadLimit : 1; - - await CopyFile(nextFile, seekFile, emptyReadLimit, allowAsync, stream, cancellationToken).ConfigureAwait(false); - - seekFile = false; - nextFileInfo = GetNextFile(nextFile); - nextFile = nextFileInfo.file; - isLastFile = nextFileInfo.isLastFile; - } - - Logger.LogInformation("Live Stream ended."); - } - - private (string file, bool isLastFile) GetNextFile(string currentFile) - { - var files = GetStreamFilePaths(); - - if (string.IsNullOrEmpty(currentFile)) + try { - return (files[^1], true); + FileSystem.DeleteFile(path); } - - var nextIndex = files.FindIndex(i => string.Equals(i, currentFile, StringComparison.OrdinalIgnoreCase)) + 1; - - var isLastFile = nextIndex == files.Count - 1; - - return (files.ElementAtOrDefault(nextIndex), isLastFile); - } - - private async Task CopyFile(string path, bool seekFile, int emptyReadLimit, bool allowAsync, Stream stream, CancellationToken cancellationToken) - { - using (var inputStream = GetInputStream(path, allowAsync)) + catch (Exception ex) { - if (seekFile) + Logger.LogError(ex, "Error deleting file {FilePath}", path); + if (retryCount <= 40) { - TrySeek(inputStream, -20000); + await Task.Delay(500).ConfigureAwait(false); + await DeleteTempFiles(path, retryCount + 1).ConfigureAwait(false); } - - await StreamHelper.CopyToAsync( - inputStream, - stream, - IODefaults.CopyToBufferSize, - emptyReadLimit, - cancellationToken).ConfigureAwait(false); } } - private void TrySeek(FileStream stream, long offset) + private void TrySeek(Stream stream, long offset) { if (!stream.CanSeek) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 862993877..84a878e51 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -3,7 +3,6 @@ #pragma warning disable CS1591 using System; -using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net.Http; @@ -55,39 +54,26 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts Directory.CreateDirectory(Path.GetDirectoryName(TempFilePath)); var typeName = GetType().Name; - Logger.LogInformation("Opening " + typeName + " Live stream from {0}", url); + Logger.LogInformation("Opening {StreamType} Live stream from {Url}", typeName, url); // Response stream is disposed manually. var response = await _httpClientFactory.CreateClient(NamedClient.Default) .GetAsync(url, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None) .ConfigureAwait(false); - var extension = "ts"; - var requiresRemux = false; - var contentType = response.Content.Headers.ContentType?.ToString() ?? string.Empty; - if (contentType.IndexOf("matroska", StringComparison.OrdinalIgnoreCase) != -1) - { - requiresRemux = true; - } - else if (contentType.IndexOf("mp4", StringComparison.OrdinalIgnoreCase) != -1 || - contentType.IndexOf("dash", StringComparison.OrdinalIgnoreCase) != -1 || - contentType.IndexOf("mpegURL", StringComparison.OrdinalIgnoreCase) != -1 || - contentType.IndexOf("text/", StringComparison.OrdinalIgnoreCase) != -1) - { - requiresRemux = true; - } - - // Close the stream without any sharing features - if (requiresRemux) + if (contentType.Contains("matroska", StringComparison.OrdinalIgnoreCase) + || contentType.Contains("mp4", StringComparison.OrdinalIgnoreCase) + || contentType.Contains("dash", StringComparison.OrdinalIgnoreCase) + || contentType.Contains("mpegURL", StringComparison.OrdinalIgnoreCase) + || contentType.Contains("text/", StringComparison.OrdinalIgnoreCase)) { - using (response) - { - return; - } + // Close the stream without any sharing features + response.Dispose(); + return; } - SetTempFilePath(extension); + SetTempFilePath("ts"); var taskCompletionSource = new TaskCompletionSource(); @@ -117,16 +103,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts if (!taskCompletionSource.Task.Result) { - Logger.LogWarning("Zero bytes copied from stream {0} to {1} but no exception raised", GetType().Name, TempFilePath); + Logger.LogWarning("Zero bytes copied from stream {StreamType} to {FilePath} but no exception raised", GetType().Name, TempFilePath); throw new EndOfStreamException(string.Format(CultureInfo.InvariantCulture, "Zero bytes copied from stream {0}", GetType().Name)); } } - public string GetFilePath() - { - return TempFilePath; - } - private Task StartStreaming(HttpResponseMessage response, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) { return Task.Run( @@ -134,7 +115,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { try { - Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath); + Logger.LogInformation("Beginning {StreamType} stream to {FilePath}", GetType().Name, TempFilePath); using var message = 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, AsyncFile.UseAsyncIO); @@ -147,19 +128,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts } catch (OperationCanceledException ex) { - Logger.LogInformation("Copying of {0} to {1} was canceled", GetType().Name, TempFilePath); + Logger.LogInformation("Copying of {StreamType} to {FilePath} was canceled", GetType().Name, TempFilePath); openTaskCompletionSource.TrySetException(ex); } catch (Exception ex) { - Logger.LogError(ex, "Error copying live stream {0} to {1}.", GetType().Name, TempFilePath); + Logger.LogError(ex, "Error copying live stream {StreamType} to {FilePath}", GetType().Name, TempFilePath); openTaskCompletionSource.TrySetException(ex); } openTaskCompletionSource.TrySetResult(false); EnableStreamSharing = false; - await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false); + await DeleteTempFiles(TempFilePath).ConfigureAwait(false); }, CancellationToken.None); } diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 93dc76729..c3856b882 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1199,15 +1199,15 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesVideoFile] - public async Task GetLiveStreamFile([FromRoute, Required] string streamId, [FromRoute, Required] string container) + public ActionResult GetLiveStreamFile([FromRoute, Required] string streamId, [FromRoute, Required] string container) { - var liveStreamInfo = await _mediaSourceManager.GetDirectStreamProviderByUniqueId(streamId, CancellationToken.None).ConfigureAwait(false); + var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamId); if (liveStreamInfo == null) { return NotFound(); } - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetFilePath(), null, _transcodingJobHelper); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file." + container)); } diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index bc6fc904a..0af10ceef 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -453,14 +453,10 @@ namespace Jellyfin.Api.Controllers { StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager); - await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(Response.Body, CancellationToken.None) - .ConfigureAwait(false); - + var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType - return File(Response.Body, MimeTypes.GetMimeType("file.ts")!); + return File(liveStream, MimeTypes.GetMimeType("file.ts")!); } // Static remote stream @@ -492,13 +488,8 @@ namespace Jellyfin.Api.Controllers if (state.MediaSource.IsInfiniteStream) { - await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(Response.Body, CancellationToken.None) - .ConfigureAwait(false); - - return File(Response.Body, contentType); + var liveStream = new ProgressiveFileStream(state.MediaPath, null, _transcodingJobHelper); + return File(liveStream, contentType); } return FileStreamResponseHelpers.GetStaticFileResult( diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index ddcde1cf6..19da180e5 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -120,14 +120,10 @@ namespace Jellyfin.Api.Helpers { StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); - await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(_httpContextAccessor.HttpContext.Response.Body, CancellationToken.None) - .ConfigureAwait(false); - + var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType - return new FileStreamResult(_httpContextAccessor.HttpContext.Response.Body, MimeTypes.GetMimeType("file.ts")!); + return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file.ts")); } // Static remote stream @@ -159,13 +155,8 @@ namespace Jellyfin.Api.Helpers if (state.MediaSource.IsInfiniteStream) { - await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None) - { - AllowEndOfFile = false - }.WriteToAsync(_httpContextAccessor.HttpContext.Response.Body, CancellationToken.None) - .ConfigureAwait(false); - - return new FileStreamResult(_httpContextAccessor.HttpContext.Response.Body, contentType); + var stream = new ProgressiveFileStream(state.MediaPath, null, _transcodingJobHelper); + return new FileStreamResult(stream, contentType); } return FileStreamResponseHelpers.GetStaticFileResult( diff --git a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs deleted file mode 100644 index 81970b041..000000000 --- a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Api.Models.PlaybackDtos; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.IO; - -namespace Jellyfin.Api.Helpers -{ - /// - /// Progressive file copier. - /// - public class ProgressiveFileCopier - { - private readonly TranscodingJobDto? _job; - private readonly string? _path; - private readonly CancellationToken _cancellationToken; - private readonly IDirectStreamProvider? _directStreamProvider; - private readonly TranscodingJobHelper _transcodingJobHelper; - private long _bytesWritten; - - /// - /// Initializes a new instance of the class. - /// - /// The path to copy from. - /// The transcoding job. - /// Instance of the . - /// The cancellation token. - public ProgressiveFileCopier(string path, TranscodingJobDto? job, TranscodingJobHelper transcodingJobHelper, CancellationToken cancellationToken) - { - _path = path; - _job = job; - _cancellationToken = cancellationToken; - _transcodingJobHelper = transcodingJobHelper; - } - - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// The transcoding job. - /// Instance of the . - /// The cancellation token. - public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, TranscodingJobDto? job, TranscodingJobHelper transcodingJobHelper, CancellationToken cancellationToken) - { - _directStreamProvider = directStreamProvider; - _job = job; - _cancellationToken = cancellationToken; - _transcodingJobHelper = transcodingJobHelper; - } - - /// - /// Gets or sets a value indicating whether allow read end of file. - /// - public bool AllowEndOfFile { get; set; } = true; - - /// - /// Gets or sets copy start position. - /// - public long StartPosition { get; set; } - - /// - /// Write source stream to output. - /// - /// Output stream. - /// Cancellation token. - /// A . - public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken) - { - using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken); - cancellationToken = linkedCancellationTokenSource.Token; - - try - { - if (_directStreamProvider != null) - { - await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); - return; - } - - var fileOptions = FileOptions.SequentialScan; - var allowAsyncFileRead = false; - - if (AsyncFile.UseAsyncIO) - { - fileOptions |= FileOptions.Asynchronous; - allowAsyncFileRead = true; - } - - if (_path == null) - { - throw new ResourceNotFoundException(nameof(_path)); - } - - await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); - - var eofCount = 0; - const int EmptyReadLimit = 20; - if (StartPosition > 0) - { - inputStream.Position = StartPosition; - } - - while (eofCount < EmptyReadLimit || !AllowEndOfFile) - { - var bytesRead = await CopyToInternalAsync(inputStream, outputStream, allowAsyncFileRead, cancellationToken).ConfigureAwait(false); - - if (bytesRead == 0) - { - if (_job == null || _job.HasExited) - { - eofCount++; - } - - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - } - else - { - eofCount = 0; - } - } - } - finally - { - if (_job != null) - { - _transcodingJobHelper.OnTranscodeEndRequest(_job); - } - } - } - - private async Task CopyToInternalAsync(Stream source, Stream destination, bool readAsync, CancellationToken cancellationToken) - { - var array = ArrayPool.Shared.Rent(IODefaults.CopyToBufferSize); - try - { - int bytesRead; - int totalBytesRead = 0; - - if (readAsync) - { - bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false); - } - else - { - bytesRead = source.Read(array, 0, array.Length); - } - - while (bytesRead != 0) - { - var bytesToWrite = bytesRead; - - if (bytesToWrite > 0) - { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); - - _bytesWritten += bytesRead; - totalBytesRead += bytesRead; - - if (_job != null) - { - _job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten); - } - } - - if (readAsync) - { - bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false); - } - else - { - bytesRead = source.Read(array, 0, array.Length); - } - } - - return totalBytesRead; - } - finally - { - ArrayPool.Shared.Return(array); - } - } - } -} diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index d4cc0172d..993973417 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -13,9 +13,9 @@ namespace Jellyfin.Api.Helpers /// public class ProgressiveFileStream : Stream { - private readonly FileStream _fileStream; + private readonly Stream _stream; private readonly TranscodingJobDto? _job; - private readonly TranscodingJobHelper _transcodingJobHelper; + private readonly TranscodingJobHelper? _transcodingJobHelper; private readonly int _timeoutMs; private readonly bool _allowAsyncFileRead; private int _bytesWritten; @@ -33,7 +33,6 @@ namespace Jellyfin.Api.Helpers _job = job; _transcodingJobHelper = transcodingJobHelper; _timeoutMs = timeoutMs; - _bytesWritten = 0; var fileOptions = FileOptions.SequentialScan; _allowAsyncFileRead = false; @@ -45,11 +44,27 @@ namespace Jellyfin.Api.Helpers _allowAsyncFileRead = true; } - _fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); + _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); + } + + /// + /// Initializes a new instance of the class. + /// + /// The stream to progressively copy. + /// The transcoding job information. + /// The transcoding job helper. + /// The timeout duration in milliseconds. + public ProgressiveFileStream(Stream stream, TranscodingJobDto? job, TranscodingJobHelper? transcodingJobHelper, int timeoutMs = 30000) + { + _job = job; + _transcodingJobHelper = transcodingJobHelper; + _timeoutMs = timeoutMs; + _allowAsyncFileRead = AsyncFile.UseAsyncIO; + _stream = stream; } /// - public override bool CanRead => _fileStream.CanRead; + public override bool CanRead => _stream.CanRead; /// public override bool CanSeek => false; @@ -70,13 +85,13 @@ namespace Jellyfin.Api.Helpers /// public override void Flush() { - _fileStream.Flush(); + _stream.Flush(); } /// public override int Read(byte[] buffer, int offset, int count) { - return _fileStream.Read(buffer, offset, count); + return _stream.Read(buffer, offset, count); } /// @@ -93,11 +108,11 @@ namespace Jellyfin.Api.Helpers int bytesRead; if (_allowAsyncFileRead) { - bytesRead = await _fileStream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); + bytesRead = await _stream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); } else { - bytesRead = _fileStream.Read(buffer, newOffset, remainingBytesToRead); + bytesRead = _stream.Read(buffer, newOffset, remainingBytesToRead); } remainingBytesToRead -= bytesRead; @@ -152,11 +167,11 @@ namespace Jellyfin.Api.Helpers { if (disposing) { - _fileStream.Dispose(); + _stream.Dispose(); if (_job != null) { - _transcodingJobHelper.OnTranscodeEndRequest(_job); + _transcodingJobHelper?.OnTranscodeEndRequest(_job); } } } diff --git a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs index e95f2d1f4..0f84faeaf 100644 --- a/Jellyfin.Api/Models/StreamingDtos/StreamState.cs +++ b/Jellyfin.Api/Models/StreamingDtos/StreamState.cs @@ -60,6 +60,9 @@ namespace Jellyfin.Api.Models.StreamingDtos /// /// Gets or sets the direct stream provicer. /// + /// + /// Deprecated. + /// public IDirectStreamProvider? DirectStreamProvider { get; set; } /// diff --git a/MediaBrowser.Controller/Library/IDirectStreamProvider.cs b/MediaBrowser.Controller/Library/IDirectStreamProvider.cs new file mode 100644 index 000000000..2939668f7 --- /dev/null +++ b/MediaBrowser.Controller/Library/IDirectStreamProvider.cs @@ -0,0 +1,20 @@ +using System.IO; + +namespace MediaBrowser.Controller.Library +{ + /// + /// The direct live TV stream provider. + /// + /// + /// Deprecated. + /// + public interface IDirectStreamProvider + { + /// + /// Gets the live stream, optionally seeks to the end of the file first. + /// + /// A value indicating whether to seek to the end of the file. + /// The stream. + Stream GetStream(bool seekNearEnd = true); + } +} diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs index 323aa4876..a29a91fe9 100644 --- a/MediaBrowser.Controller/Library/ILiveStream.cs +++ b/MediaBrowser.Controller/Library/ILiveStream.cs @@ -2,6 +2,7 @@ #pragma warning disable CA1711, CS1591 +using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Dto; @@ -25,5 +26,7 @@ namespace MediaBrowser.Controller.Library Task Open(CancellationToken openCancellationToken); Task Close(); + + Stream GetStream(bool seekNearEnd = true); } } diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index fd3631da9..0de3ccf3f 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; @@ -110,6 +109,13 @@ namespace MediaBrowser.Controller.Library Task> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken); + /// + /// Gets the live stream info. + /// + /// The identifier. + /// An instance of . + public ILiveStream GetLiveStreamInfo(string id); + /// /// Closes the media source. /// @@ -129,11 +135,4 @@ namespace MediaBrowser.Controller.Library Task GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken); } - - public interface IDirectStreamProvider - { - Task CopyToAsync(Stream stream, CancellationToken cancellationToken); - - string GetFilePath(); - } } -- cgit v1.2.3 From 1a5a74d2a95506249cf071c659e3c6cf01f28f78 Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 10 Sep 2021 10:03:42 +0200 Subject: Remove more unused args --- Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs | 2 +- Jellyfin.Api/Controllers/LiveTvController.cs | 2 +- Jellyfin.Api/Controllers/VideosController.cs | 2 +- Jellyfin.Api/Helpers/AudioHelper.cs | 2 +- Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 8 +++----- 5 files changed, 7 insertions(+), 9 deletions(-) (limited to 'Jellyfin.Api/Helpers/ProgressiveFileStream.cs') diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index fdefa2679..f6e0111b6 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -58,7 +58,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); var linkedCancellationToken = cancellationTokenSource.Token; - await using var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream(), null, null); + await using var fileStream = new ProgressiveFileStream(directStreamProvider.GetStream()); await _streamHelper.CopyToAsync( fileStream, output, diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index c3856b882..3f68b267f 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1207,7 +1207,7 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream()); return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file." + container)); } diff --git a/Jellyfin.Api/Controllers/VideosController.cs b/Jellyfin.Api/Controllers/VideosController.cs index 0af10ceef..d7d48ba3e 100644 --- a/Jellyfin.Api/Controllers/VideosController.cs +++ b/Jellyfin.Api/Controllers/VideosController.cs @@ -454,7 +454,7 @@ namespace Jellyfin.Api.Controllers StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager); var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream()); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType return File(liveStream, MimeTypes.GetMimeType("file.ts")!); } diff --git a/Jellyfin.Api/Helpers/AudioHelper.cs b/Jellyfin.Api/Helpers/AudioHelper.cs index 19da180e5..06f889f08 100644 --- a/Jellyfin.Api/Helpers/AudioHelper.cs +++ b/Jellyfin.Api/Helpers/AudioHelper.cs @@ -121,7 +121,7 @@ namespace Jellyfin.Api.Helpers StreamingHelpers.AddDlnaHeaders(state, _httpContextAccessor.HttpContext.Response.Headers, true, streamingRequest.StartTimeTicks, _httpContextAccessor.HttpContext.Request, _dlnaManager); var liveStreamInfo = _mediaSourceManager.GetLiveStreamInfo(streamingRequest.LiveStreamId); - var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream(), null, _transcodingJobHelper); + var liveStream = new ProgressiveFileStream(liveStreamInfo.GetStream()); // TODO (moved from MediaBrowser.Api): Don't hardcode contentType return new FileStreamResult(liveStream, MimeTypes.GetMimeType("file.ts")); } diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index 993973417..c57018351 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -51,13 +51,11 @@ namespace Jellyfin.Api.Helpers /// Initializes a new instance of the class. /// /// The stream to progressively copy. - /// The transcoding job information. - /// The transcoding job helper. /// The timeout duration in milliseconds. - public ProgressiveFileStream(Stream stream, TranscodingJobDto? job, TranscodingJobHelper? transcodingJobHelper, int timeoutMs = 30000) + public ProgressiveFileStream(Stream stream, int timeoutMs = 30000) { - _job = job; - _transcodingJobHelper = transcodingJobHelper; + _job = null; + _transcodingJobHelper = null; _timeoutMs = timeoutMs; _allowAsyncFileRead = AsyncFile.UseAsyncIO; _stream = stream; -- cgit v1.2.3 From f31224fa8f1dccb730703c048c26e14b5d14fa55 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 25 Sep 2021 19:44:40 +0200 Subject: Remove sync FileStream hack --- Emby.Dlna/DlnaManager.cs | 2 +- Emby.Drawing/ImageProcessor.cs | 2 +- .../LiveTv/EmbyTV/DirectRecorder.cs | 4 ++-- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 2 +- .../LiveTv/TunerHosts/LiveStream.cs | 6 +++--- .../LiveTv/TunerHosts/SharedHttpStream.cs | 2 +- Jellyfin.Api/Controllers/RemoteImageController.cs | 2 +- Jellyfin.Api/Controllers/SystemController.cs | 2 +- Jellyfin.Api/Helpers/HlsHelpers.cs | 2 +- Jellyfin.Api/Helpers/ProgressiveFileStream.cs | 24 ++-------------------- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 2 +- .../SymlinkFollowingPhysicalFileResultExecutor.cs | 2 +- Jellyfin.Server/Program.cs | 2 +- .../Subtitles/SubtitleEncoder.cs | 2 +- MediaBrowser.Model/IO/AsyncFile.cs | 11 ++-------- MediaBrowser.Providers/Manager/ImageSaver.cs | 2 +- .../Manager/ItemImageProvider.cs | 2 +- .../Plugins/AudioDb/AudioDbAlbumProvider.cs | 2 +- .../Plugins/AudioDb/AudioDbArtistProvider.cs | 2 +- .../Plugins/Omdb/OmdbProvider.cs | 4 ++-- .../Studios/StudiosImageProvider.cs | 2 +- .../Subtitles/SubtitleManager.cs | 2 +- 23 files changed, 29 insertions(+), 56 deletions(-) (limited to 'Jellyfin.Api/Helpers/ProgressiveFileStream.cs') diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index 305e43a3c..8fe9d484e 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -366,7 +366,7 @@ namespace Emby.Dlna Directory.CreateDirectory(systemProfilesPath); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { await stream.CopyToAsync(fileStream).ConfigureAwait(false); } diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 0ad8bca31..9b130fdfd 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -102,7 +102,7 @@ namespace Emby.Drawing { var file = await ProcessImage(options).ConfigureAwait(false); - using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index f6e0111b6..41381d55b 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { onStarted(); @@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO); + await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); onStarted(); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index a943efcc7..3633fa3e1 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index cb9801c17..2e51ac807 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -82,7 +82,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO)) + await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous)) { await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 817b1f804..20a9a705b 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts public Stream GetStream() { - var stream = GetInputStream(TempFilePath, AsyncFile.UseAsyncIO); + var stream = GetInputStream(TempFilePath); bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; if (seekFile) { @@ -107,14 +107,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return stream; } - protected FileStream GetInputStream(string path, bool allowAsyncFileRead) + protected FileStream GetInputStream(string path) => new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, - allowAsyncFileRead ? FileOptions.SequentialScan | FileOptions.Asynchronous : FileOptions.SequentialScan); + FileOptions.SequentialScan | FileOptions.Asynchronous); protected async Task DeleteTempFiles(string path, int retryCount = 0) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 84a878e51..3b69e55b0 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -118,7 +118,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts Logger.LogInformation("Beginning {StreamType} stream to {FilePath}", GetType().Name, TempFilePath); using var message = 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, AsyncFile.UseAsyncIO); + await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await StreamHelper.CopyToAsync( stream, fileStream, diff --git a/Jellyfin.Api/Controllers/RemoteImageController.cs b/Jellyfin.Api/Controllers/RemoteImageController.cs index bcb2b50c7..8a33b12f4 100644 --- a/Jellyfin.Api/Controllers/RemoteImageController.cs +++ b/Jellyfin.Api/Controllers/RemoteImageController.cs @@ -206,7 +206,7 @@ namespace Jellyfin.Api.Controllers var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid."); Directory.CreateDirectory(fullCacheDirectory); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath)); diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index e6584f0fe..741bdfee9 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -201,7 +201,7 @@ namespace Jellyfin.Api.Controllers // For older files, assume fully static var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite; - FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); return File(stream, "text/plain; charset=utf-8"); } diff --git a/Jellyfin.Api/Helpers/HlsHelpers.cs b/Jellyfin.Api/Helpers/HlsHelpers.cs index f36769dc2..456762147 100644 --- a/Jellyfin.Api/Helpers/HlsHelpers.cs +++ b/Jellyfin.Api/Helpers/HlsHelpers.cs @@ -38,7 +38,7 @@ namespace Jellyfin.Api.Helpers FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, - (AsyncFile.UseAsyncIO ? FileOptions.Asynchronous : FileOptions.None) | FileOptions.SequentialScan); + FileOptions.Asynchronous | FileOptions.SequentialScan); await using (fileStream.ConfigureAwait(false)) { using var reader = new StreamReader(fileStream); diff --git a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs index c57018351..61e18220a 100644 --- a/Jellyfin.Api/Helpers/ProgressiveFileStream.cs +++ b/Jellyfin.Api/Helpers/ProgressiveFileStream.cs @@ -17,7 +17,6 @@ namespace Jellyfin.Api.Helpers private readonly TranscodingJobDto? _job; private readonly TranscodingJobHelper? _transcodingJobHelper; private readonly int _timeoutMs; - private readonly bool _allowAsyncFileRead; private int _bytesWritten; private bool _disposed; @@ -34,17 +33,7 @@ namespace Jellyfin.Api.Helpers _transcodingJobHelper = transcodingJobHelper; _timeoutMs = timeoutMs; - var fileOptions = FileOptions.SequentialScan; - _allowAsyncFileRead = false; - - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - if (AsyncFile.UseAsyncIO) - { - fileOptions |= FileOptions.Asynchronous; - _allowAsyncFileRead = true; - } - - _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); + _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); } /// @@ -57,7 +46,6 @@ namespace Jellyfin.Api.Helpers _job = null; _transcodingJobHelper = null; _timeoutMs = timeoutMs; - _allowAsyncFileRead = AsyncFile.UseAsyncIO; _stream = stream; } @@ -103,15 +91,7 @@ namespace Jellyfin.Api.Helpers while (remainingBytesToRead > 0) { cancellationToken.ThrowIfCancellationRequested(); - int bytesRead; - if (_allowAsyncFileRead) - { - bytesRead = await _stream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); - } - else - { - bytesRead = _stream.Read(buffer, newOffset, remainingBytesToRead); - } + int bytesRead = await _stream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); remainingBytesToRead -= bytesRead; newOffset += bytesRead; diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 4e1e98df0..14f287aef 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -557,7 +557,7 @@ namespace Jellyfin.Api.Helpers $"{logFilePrefix}{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{state.Request.MediaSourceId}_{Guid.NewGuid().ToString()[..8]}.log"); // FFmpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(request.Path + Environment.NewLine + Environment.NewLine + JsonSerializer.Serialize(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); diff --git a/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs b/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs index 4abd5b36d..f3fbab77e 100644 --- a/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs +++ b/Jellyfin.Server/Infrastructure/SymlinkFollowingPhysicalFileResultExecutor.cs @@ -132,7 +132,7 @@ namespace Jellyfin.Server.Infrastructure FileAccess.Read, FileShare.ReadWrite, bufferSize: BufferSize, - options: (AsyncFile.UseAsyncIO ? FileOptions.Asynchronous : FileOptions.None) | FileOptions.SequentialScan); + options: FileOptions.Asynchronous | FileOptions.SequentialScan); fileStream.Seek(offset, SeekOrigin.Begin); await StreamCopyOperation diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 1300ce3b6..f36675b95 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -547,7 +547,7 @@ namespace Jellyfin.Server ?? throw new InvalidOperationException($"Invalid resource path: '{ResourcePath}'"); // Copy the resource contents to the expected file path for the config file - await using Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await resource.CopyToAsync(dst).ConfigureAwait(false); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index f8451e92c..022cdbe9d 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -680,7 +680,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!string.Equals(text, newText, StringComparison.Ordinal)) { // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) using (var writer = new StreamWriter(fileStream, encoding)) { await writer.WriteAsync(newText.AsMemory(), cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Model/IO/AsyncFile.cs b/MediaBrowser.Model/IO/AsyncFile.cs index b888a4163..f38ed9ae3 100644 --- a/MediaBrowser.Model/IO/AsyncFile.cs +++ b/MediaBrowser.Model/IO/AsyncFile.cs @@ -8,20 +8,13 @@ namespace MediaBrowser.Model.IO /// public static class AsyncFile { - /// - /// Gets a value indicating whether we should use async IO on this platform. - /// . - /// - /// Returns false on Windows; otherwise true. - public static bool UseAsyncIO => !OperatingSystem.IsWindows(); - /// /// Opens an existing file for reading. /// /// The file to be opened for reading. /// A read-only on the specified path. public static FileStream OpenRead(string path) - => new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, UseAsyncIO); + => new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); /// /// Opens an existing file for writing. @@ -29,6 +22,6 @@ namespace MediaBrowser.Model.IO /// The file to be opened for writing. /// An unshared object on the specified path with Write access. public static FileStream OpenWrite(string path) - => new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, UseAsyncIO); + => new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); } } diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 6c14c8de1..7d259a9d3 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -264,7 +264,7 @@ namespace MediaBrowser.Providers.Manager _fileSystem.SetAttributes(path, false, false); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) + await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 81529e984..73bca5aa5 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -163,7 +163,7 @@ namespace MediaBrowser.Providers.Manager { var mimeType = MimeTypes.GetMimeType(response.Path); - var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs index c1226febf..3e0b0014e 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs @@ -173,7 +173,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs index 8572b3413..e0b2f9c58 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AudioDbArtistProvider.cs @@ -155,7 +155,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb Directory.CreateDirectory(Path.GetDirectoryName(path)); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 1dea3dece..479ae0f39 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -295,7 +295,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb imdbParam)); var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); return path; @@ -335,7 +335,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb seasonId)); var rootObject = await GetDeserializedOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); return path; diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 7a057c065..7b2454efc 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -146,7 +146,7 @@ namespace MediaBrowser.Providers.Studios Directory.CreateDirectory(Path.GetDirectoryName(file)); await using var response = await httpClient.GetStreamAsync(url, cancellationToken).ConfigureAwait(false); - await using var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); + await using var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); await response.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index d6c346ba1..772e617ab 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -245,7 +245,7 @@ namespace MediaBrowser.Providers.Subtitles Directory.CreateDirectory(Path.GetDirectoryName(savePath)); // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . - using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, AsyncFile.UseAsyncIO); + using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, FileOptions.Asynchronous); await stream.CopyToAsync(fs).ConfigureAwait(false); return; -- cgit v1.2.3