Example #1
0
        /// <inheritdoc />
        public async Task <MediaStreamInfoSet> GetVideoMediaStreamInfosAsync(string videoId)
        {
            videoId.GuardNotNull(nameof(videoId));

            if (!ValidateVideoId(videoId))
            {
                throw new ArgumentException($"Invalid YouTube video ID [{videoId}].", nameof(videoId));
            }

            // Register the time at which the request was made to calculate expiry date later on
            var requestedAt = DateTimeOffset.Now;

            // Get parser
            var parser = await GetPlayerResponseParserAsync(videoId, true);

            // Prepare stream info maps
            var muxedStreamInfoMap = new Dictionary <int, MuxedStreamInfo>();
            var audioStreamInfoMap = new Dictionary <int, AudioStreamInfo>();
            var videoStreamInfoMap = new Dictionary <int, VideoStreamInfo>();

            // Parse muxed stream infos
            foreach (var streamInfoParser in parser.GetMuxedStreamInfos())
            {
                // Parse info
                var itag = streamInfoParser.ParseItag();
                var url  = streamInfoParser.ParseUrl();

                // Try to parse content length, otherwise get it manually
                var contentLength = streamInfoParser.ParseContentLength();
                if (contentLength <= 0)
                {
                    // Send HEAD request and get content length
                    contentLength = await _httpClient.GetContentLengthAsync(url, false) ?? -1;

                    // If content length is still not available - stream is gone or faulty
                    if (contentLength <= 0)
                    {
                        continue;
                    }
                }

                // Parse container
                var containerStr = streamInfoParser.ParseContainer();
                var container    = ContainerHelper.ContainerFromString(containerStr);

                // Parse audio encoding
                var audioEncodingStr = streamInfoParser.ParseAudioEncoding();
                var audioEncoding    = AudioEncodingHelper.AudioEncodingFromString(audioEncodingStr);

                // Parse video encoding
                var videoEncodingStr = streamInfoParser.ParseVideoEncoding();
                var videoEncoding    = VideoEncodingHelper.VideoEncodingFromString(videoEncodingStr);

                // Parse video quality label and video quality
                var videoQualityLabel = streamInfoParser.ParseVideoQualityLabel();
                var videoQuality      = VideoQualityHelper.VideoQualityFromLabel(videoQualityLabel);

                // Parse resolution
                var width      = streamInfoParser.ParseWidth();
                var height     = streamInfoParser.ParseHeight();
                var resolution = new VideoResolution(width, height);

                // Add stream
                var streamInfo = new MuxedStreamInfo(itag, url, container, contentLength, audioEncoding, videoEncoding,
                                                     videoQualityLabel, videoQuality, resolution);
                muxedStreamInfoMap[itag] = streamInfo;
            }

            // Parse adaptive stream infos
            foreach (var streamInfoParser in parser.GetAdaptiveStreamInfos())
            {
                // Parse info
                var itag    = streamInfoParser.ParseItag();
                var url     = streamInfoParser.ParseUrl();
                var bitrate = streamInfoParser.ParseBitrate();

                // Try to parse content length, otherwise get it manually
                var contentLength = streamInfoParser.ParseContentLength();
                if (contentLength <= 0)
                {
                    // Send HEAD request and get content length
                    contentLength = await _httpClient.GetContentLengthAsync(url, false) ?? -1;

                    // If content length is still not available - stream is gone or faulty
                    if (contentLength <= 0)
                    {
                        continue;
                    }
                }

                // Parse container
                var containerStr = streamInfoParser.ParseContainer();
                var container    = ContainerHelper.ContainerFromString(containerStr);

                // If audio-only
                if (streamInfoParser.ParseIsAudioOnly())
                {
                    // Parse audio encoding
                    var audioEncodingStr = streamInfoParser.ParseAudioEncoding();
                    var audioEncoding    = AudioEncodingHelper.AudioEncodingFromString(audioEncodingStr);

                    // Add stream
                    var streamInfo = new AudioStreamInfo(itag, url, container, contentLength, bitrate, audioEncoding);
                    audioStreamInfoMap[itag] = streamInfo;
                }
                // If video-only
                else
                {
                    // Parse video encoding
                    var videoEncodingStr = streamInfoParser.ParseVideoEncoding();
                    var videoEncoding    = VideoEncodingHelper.VideoEncodingFromString(videoEncodingStr);

                    // Parse video quality label and video quality
                    var videoQualityLabel = streamInfoParser.ParseVideoQualityLabel();
                    var videoQuality      = VideoQualityHelper.VideoQualityFromLabel(videoQualityLabel);

                    // Parse resolution
                    var width      = streamInfoParser.ParseWidth();
                    var height     = streamInfoParser.ParseHeight();
                    var resolution = new VideoResolution(width, height);

                    // Parse framerate
                    var framerate = streamInfoParser.ParseFramerate();

                    // Add stream
                    var streamInfo = new VideoStreamInfo(itag, url, container, contentLength, bitrate, videoEncoding,
                                                         videoQualityLabel, videoQuality, resolution, framerate);
                    videoStreamInfoMap[itag] = streamInfo;
                }
            }

            // Parse dash manifest
            var dashManifestUrl = parser.ParseDashManifestUrl();

            if (!dashManifestUrl.IsNullOrWhiteSpace())
            {
                // Get the dash manifest parser
                var dashManifestParser = await GetDashManifestParserAsync(dashManifestUrl);

                // Parse dash stream infos
                foreach (var streamInfoParser in dashManifestParser.GetStreamInfos())
                {
                    // Parse info
                    var itag          = streamInfoParser.ParseItag();
                    var url           = streamInfoParser.ParseUrl();
                    var contentLength = streamInfoParser.ParseContentLength();
                    var bitrate       = streamInfoParser.ParseBitrate();

                    // Parse container
                    var containerStr = streamInfoParser.ParseContainer();
                    var container    = ContainerHelper.ContainerFromString(containerStr);

                    // If audio-only
                    if (streamInfoParser.ParseIsAudioOnly())
                    {
                        // Parse audio encoding
                        var audioEncodingStr = streamInfoParser.ParseEncoding();
                        var audioEncoding    = AudioEncodingHelper.AudioEncodingFromString(audioEncodingStr);

                        // Add stream
                        var streamInfo =
                            new AudioStreamInfo(itag, url, container, contentLength, bitrate, audioEncoding);
                        audioStreamInfoMap[itag] = streamInfo;
                    }
                    // If video-only
                    else
                    {
                        // Parse video encoding
                        var videoEncodingStr = streamInfoParser.ParseEncoding();
                        var videoEncoding    = VideoEncodingHelper.VideoEncodingFromString(videoEncodingStr);

                        // Parse resolution
                        var width      = streamInfoParser.ParseWidth();
                        var height     = streamInfoParser.ParseHeight();
                        var resolution = new VideoResolution(width, height);

                        // Parse framerate
                        var framerate = streamInfoParser.ParseFramerate();

                        // Determine video quality from height
                        var videoQuality = VideoQualityHelper.VideoQualityFromHeight(height);

                        // Determine video quality label from video quality and framerate
                        var videoQualityLabel = VideoQualityHelper.VideoQualityToLabel(videoQuality, framerate);

                        // Add stream
                        var streamInfo = new VideoStreamInfo(itag, url, container, contentLength, bitrate,
                                                             videoEncoding, videoQualityLabel, videoQuality, resolution, framerate);
                        videoStreamInfoMap[itag] = streamInfo;
                    }
                }
            }

            // Finalize stream info collections
            var muxedStreamInfos = muxedStreamInfoMap.Values.OrderByDescending(s => s.VideoQuality).ToArray();
            var audioStreamInfos = audioStreamInfoMap.Values.OrderByDescending(s => s.Bitrate).ToArray();
            var videoStreamInfos = videoStreamInfoMap.Values.OrderByDescending(s => s.VideoQuality).ToArray();

            // Get the HLS manifest URL if available
            var hlsManifestUrl = parser.ParseHlsManifestUrl();

            // Get expiry date
            var expiresIn  = parser.ParseStreamInfoSetExpiresIn();
            var validUntil = requestedAt.Add(expiresIn);

            return(new MediaStreamInfoSet(muxedStreamInfos, audioStreamInfos, videoStreamInfos, hlsManifestUrl,
                                          validUntil));
        }