Пример #1
0
        /// <summary>
        /// Gets the stream identified by the specified metadata.
        /// </summary>
        public async ValueTask <Stream> GetAsync(
            IStreamInfo streamInfo,
            CancellationToken cancellationToken = default)
        {
            // For most streams, YouTube limits transfer speed to match the video playback rate.
            // This helps them avoid unnecessary bandwidth, but for us it's a hindrance because
            // we want to download the stream as fast as possible.
            // To solve this, we divide the logical stream up into multiple segments and download
            // them all separately.

            var isThrottled = !Regex.IsMatch(streamInfo.Url, "ratebypass[=/]yes");

            var segmentSize = isThrottled
                ? 9_898_989    // breakpoint after which the throttling kicks in
                : (long?)null; // no segmentation for non-throttled streams

            var stream = new SegmentedHttpStream(
                _httpClient,
                streamInfo.Url,
                streamInfo.Size.Bytes,
                segmentSize
                );

            // Pre-resolve inner stream eagerly
            await stream.PreloadAsync(cancellationToken);

            return(stream);
        }
Пример #2
0
        private async Task <YoutubeMediaPacket> _fillGab(YoutubeRequestURL packetRequestURL, Range lostRange, YoutubeMediaPacketType type)
        {
            packetRequestURL.RequestPath.QueryString.SetValue("range", $"{lostRange.Start}-{lostRange.End}");
            var requestableURL = packetRequestURL.ToRequestableURL();

            // debugging
            YTrackLogger.Log("\nfilling broken range  for type " + type + " : " + lostRange.ToString() + " from : " + requestableURL);

            long httpSegmentSize = packetRequestURL.RequestPath.QueryString.HasValue("ratebypass") && packetRequestURL.RequestPath.QueryString.GetValue("ratebypass") == "yes"
                ? (long)lostRange.Length
                : 9_898_989;
            YoutubeMediaPacket packet;


            using (SegmentedHttpStream segmentedHttpStream = new SegmentedHttpStream(_client, requestableURL, (long)lostRange.Length, httpSegmentSize))
            {
                try
                {
                    string tmpFileName = Path.GetTempFileName();
                    using (Stream outputStream = new FileStream(tmpFileName, FileMode.Append))
                    {
                        IProgress <double> progressPercentage = new Progress <double>(b => packetDownloadProgressChanged(b));
                        await segmentedHttpStream.CopyToStreamAsync(outputStream, progressPercentage);
                    }
                    // no need to check whether the packetRequestURL is a valid requist URL
                    // because we requested it anyway
                    packet = new YoutubeMediaPacket(type, packetRequestURL, tmpFileName);
                    OnPacketDownloadCompleted?.Invoke(this, packet);
                }
                catch (Exception e)
                {
                    // two exception may be thrown
                    // WebException if something went wrong when fetch the new packets
                    // IOException if something went wrong when writing the packet file to disk
                    // I'll raise PacketDownloadExceptionThrown and re-throw exception
                    if (e is WebException)
                    {
                        _onGabPacketDownloadExceptionThrown?.Invoke(this, new PacketDownloadExceptionEventArgumanets()
                        {
                            Exception = e as WebException,
                            FailedPacketRequestURL = packetRequestURL,
                            Range = lostRange
                        });
                    }

                    // re-throw the error to the caller
                    Helpers.YTrackLogger.Log("Failed to download Packet : " + e.Message + "\n\n" + e.StackTrace);
                    throw;
                }
            }
            return(packet);
        }