diff options
| author | David <daullmer@gmail.com> | 2020-07-03 19:12:44 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-03 19:12:44 +0200 |
| commit | c675a9bec972adf627e209e5a24302a3a984f5ec (patch) | |
| tree | 89bd891b49fe13665cf97b14346ea737b333be89 /Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | |
| parent | 3306639c9b4cd12444ea35545b671413b494fe6c (diff) | |
| parent | 68cc075ddaf1f604182ad21d7d00ee9940522c4e (diff) | |
Merge pull request #3405 from crobibero/api-livetv
Move LiveTvService.cs to Jellyfin.Api
Diffstat (limited to 'Jellyfin.Api/Helpers/ProgressiveFileCopier.cs')
| -rw-r--r-- | Jellyfin.Api/Helpers/ProgressiveFileCopier.cs | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs new file mode 100644 index 000000000..e8e6966f4 --- /dev/null +++ b/Jellyfin.Api/Helpers/ProgressiveFileCopier.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.IO; + +namespace Jellyfin.Api.Helpers +{ + /// <summary> + /// Progressive file copier. + /// </summary> + public class ProgressiveFileCopier + { + private readonly string? _path; + private readonly IDirectStreamProvider? _directStreamProvider; + private readonly IStreamHelper _streamHelper; + + /// <summary> + /// Initializes a new instance of the <see cref="ProgressiveFileCopier"/> class. + /// </summary> + /// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param> + /// <param name="path">Filepath to stream from.</param> + public ProgressiveFileCopier(IStreamHelper streamHelper, string path) + { + _path = path; + _streamHelper = streamHelper; + _directStreamProvider = null; + } + + /// <summary> + /// Initializes a new instance of the <see cref="ProgressiveFileCopier"/> class. + /// </summary> + /// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param> + /// <param name="directStreamProvider">Instance of the <see cref="IDirectStreamProvider"/> interface.</param> + public ProgressiveFileCopier(IStreamHelper streamHelper, IDirectStreamProvider directStreamProvider) + { + _directStreamProvider = directStreamProvider; + _streamHelper = streamHelper; + _path = null; + } + + /// <summary> + /// Write source stream to output. + /// </summary> + /// <param name="outputStream">Output stream.</param> + /// <param name="cancellationToken">Cancellation token.</param> + /// <returns>A <see cref="Task"/>.</returns> + public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken) + { + if (_directStreamProvider != null) + { + await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); + return; + } + + var fileOptions = FileOptions.SequentialScan; + + // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + { + fileOptions |= FileOptions.Asynchronous; + } + + await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, fileOptions); + const int emptyReadLimit = 100; + var eofCount = 0; + while (eofCount < emptyReadLimit) + { + var bytesRead = await _streamHelper.CopyToAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false); + + if (bytesRead == 0) + { + eofCount++; + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + } + else + { + eofCount = 0; + } + } + } + } +} |
