/// <inheritdoc /> public Task <MediaStream> GetMediaStreamAsync(MediaStreamInfo info) { info.GuardNotNull(nameof(info)); // Determine if stream is rate-limited var isRateLimited = !Regex.IsMatch(info.Url, "ratebypass[=/]yes"); // Determine segment size var segmentSize = isRateLimited ? 9_898_989 // this number was carefully devised through research : long.MaxValue; // don't use segmentation for non-rate-limited streams // Get segmented stream var stream = _httpClient.CreateSegmentedStream(info.Url, info.Size, segmentSize); // This method must return a task for backwards-compatibility reasons return(Task.FromResult(new MediaStream(info, stream))); }
/// <summary> /// Gets the actual media stream associated with given metadata /// and downloads it to a file. /// </summary> public async Task DownloadMediaStreamAsync(MediaStreamInfo info, string filePath, IProgress <double> progress, CancellationToken cancellationToken) { info.GuardNotNull(nameof(info)); filePath.GuardNotNull(nameof(filePath)); // Keep track of bytes copied for progress reporting var totalBytesCopied = 0L; // Determine if stream is rate-limited var isRateLimited = !Regex.IsMatch(info.Url, @"ratebypass[=/]yes"); // Download rate-limited streams in segments if (isRateLimited) { // Determine segment count const long segmentSize = 9_898_989; // this number was carefully devised through research var segmentCount = (int)Math.Ceiling(1.0 * info.Size / segmentSize); using (var output = File.Create(filePath)) { for (var i = 0; i < segmentCount; i++) { // Determine segment range var from = i * segmentSize; var to = (i + 1) * segmentSize - 1; // Create request with range var request = new HttpRequestMessage(HttpMethod.Get, info.Url); request.Headers.Range = new RangeHeaderValue(from, to); // Download segment using (request) using (var response = await _httpService.PerformRequestAsync(request).ConfigureAwait(false)) using (var input = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) { int bytesCopied; do { // Copy bytesCopied = await input.CopyChunkToAsync(output, cancellationToken) .ConfigureAwait(false); // Report progress totalBytesCopied += bytesCopied; progress?.Report(1.0 * totalBytesCopied / info.Size); } while (bytesCopied > 0); } } } } // Download non-limited streams directly else { using (var output = File.Create(filePath)) using (var input = await GetMediaStreamAsync(info).ConfigureAwait(false)) { int bytesCopied; do { // Copy bytesCopied = await input.CopyChunkToAsync(output, cancellationToken) .ConfigureAwait(false); // Report progress totalBytesCopied += bytesCopied; progress?.Report(1.0 * totalBytesCopied / info.Size); } while (bytesCopied > 0); } } }