/// <inheritdoc />
        public async Task <MediaStream> GetMediaStreamAsync(MediaStreamInfo info)
        {
            info.EnsureNotNull(nameof(info));

            // Get stream
            var stream = await _httpClient.GetStreamAsync(info.Url).ConfigureAwait(false);

            return(new MediaStream(info, stream));
        }
        /// <inheritdoc />
        public async Task DownloadMediaStreamAsync(MediaStreamInfo info, Stream output,
                                                   IProgress <double> progress = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            info.EnsureNotNull(nameof(info));
            output.EnsureNotNull(nameof(output));

            // 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);

                // Keep track of bytes copied for progress reporting
                var totalBytesCopied = 0L;

                for (var i = 0; i < segmentCount; i++)
                {
                    // Determine segment range
                    var from = i * segmentSize;
                    var to   = (i + 1) * segmentSize - 1;

                    // Download segment
                    using (var input = await _httpClient.GetStreamAsync(info.Url, from, to).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 input = await GetMediaStreamAsync(info).ConfigureAwait(false))
                    await input.CopyToAsync(output, progress, cancellationToken).ConfigureAwait(false);
            }
        }