コード例 #1
0
        /// <summary>
        /// Downloads metadata for the YouTube video with the specified ID.
        /// </summary>
        protected virtual async Task <YouTubeMetadata> DownloadMetadata(string id, CancellationToken cancellationToken)
        {
            IDictionary <string, string> rawMetadata;

            Status.Update(null, "Downloading metadata...", WorkStatusType.DownloadingFile);

            // make http client
            var client = HttpHelper.CreateClient();

            // send http request
            using (var response = await client.GetAsync(GetYouTubeVideoInfoUri(id), cancellationToken))
            {
                // decode metadata into rawMetadata
                var content = await response.Content.ReadAsStringAsync();

                rawMetadata = YouTubeUtils.ExtractUrlEncodedParamMap(content);
            }

            // extract metadata
            var metadata = new YouTubeMetadata
            {
                FormatList = rawMetadata.ContainsKey("fmt_list") ? rawMetadata["fmt_list"] : null,
                Status     = rawMetadata["status"],
            };

            // extract player response
            var rawPlayerResponse = rawMetadata["player_response"]
                                    ?? throw new GrabParseException("Failed to fetch player_response from metadata.");
            var playerResponse = JToken.Parse(rawPlayerResponse);

            metadata.PlayerResponse = ExtractPlayerResponseMetadata(playerResponse);

            // extract muxed streams
            if (metadata.PlayerResponse.MuxedStreams != null)
            {
                metadata.MuxedStreams = metadata.PlayerResponse.MuxedStreams;
            }
            if (metadata.MuxedStreams == null)
            {
                var urlEncodedFmtStreamMap = rawMetadata.GetOrDefault("url_encoded_fmt_stream_map")
                                             ?? throw new GrabParseException("Failed to fetch url_encoded_fmt_stream_map from metadata.");
                var fmtStreamMap = YouTubeUtils.ExtractUrlEncodedParamList(urlEncodedFmtStreamMap);
                metadata.MuxedStreams = ExtractMuxedStreamsMetadata(fmtStreamMap);
            }

            // extract adaptive streams
            if (metadata.PlayerResponse.AdaptiveStreams != null)
            {
                metadata.AdaptiveStreams = metadata.PlayerResponse.AdaptiveStreams;
            }
            if (metadata.AdaptiveStreams == null)
            {
                var urlEncodedAdaptiveFormats = rawMetadata["adaptive_fmts"]
                                                ?? throw new GrabParseException("Failed to fetch adaptive_fmts from metadata.");
                var adaptiveFmts = YouTubeUtils.ExtractUrlEncodedParamList(urlEncodedAdaptiveFormats);
                metadata.AdaptiveStreams = ExtractAdaptiveFormatsMetadata(adaptiveFmts);
            }

            return(metadata);
        }
コード例 #2
0
        /// <summary>
        /// Updates <see cref="GrabResult"/> according to the information obtained from metadata.
        /// </summary>
        private void UpdateResult(GrabResult result, YouTubeMetadata md)
        {
            var response = md.PlayerResponse;

            result.Title        = response.Title;
            result.CreationDate = response.UploadedAt;
            result.Description  = response.ShortDescription;

            result.Statistics = new GrabStatisticInfo
            {
                Author    = response.Author,
                Length    = response.Length,
                ViewCount = response.ViewCount
            };
        }
コード例 #3
0
        /// <summary>
        /// Invoked by <see cref="GrabAsync"/> method when the target video has a signature.
        /// This method downloads the necessary script (base.js) and decipher all grabbed links.
        /// </summary>
        protected virtual async Task Decipher(YouTubeEmbedPageData embedPageData, YouTubeMetadata metaData, CancellationToken cancellationToken)
        {
            // download base.js
            var client = HttpHelper.CreateClient();

            using var response = await client.GetAsync(embedPageData.BaseJsUri, cancellationToken);

            var scriptContent = await response.Content.ReadAsStringAsync();

            var script = new YouTubeScript(scriptContent);

            // find decipher function name
            var match = DecipherFunctionRegex.Match(scriptContent);

            if (!match.Success)
            {
                throw new GrabParseException("Failed to locate decipher function.");
            }
            var fn = match.Groups[1].Value;

            // prepare script host to execute the decipher function along with its used functions
            script.PrepareDecipherFunctionCall(fn);

            // call decipher function
            foreach (var streamInfo in metaData.AllStreams)
            {
                if (string.IsNullOrEmpty(streamInfo.Signature))
                {
                    continue;
                }

                // calculate decipher
                streamInfo.Decipher = script.CallDecipherFunction(fn, streamInfo.Signature);

                // update uri
                streamInfo.Url += $"&sig={Uri.EscapeDataString(streamInfo.Decipher)}";
            }
        }