/// <summary> /// Translates the given JSON object extracted from YouTube to its managed representation. /// </summary> protected virtual YouTubeAdaptiveStream TranslateAdaptiveStream(JObject input) { if (input == null) { throw new ArgumentNullException(nameof(input)); } var result = new YouTubeAdaptiveStream { iTag = input.Value <int?>("itag"), Type = input.Value <string>("mimeType"), AudioSampleRate = input.Value <long>("audioSampleRate"), ContentLength = input.Value <long>("contentLength"), FPS = input.Value <int>("fps"), Quality = input.Value <string>("quality"), QualityLabel = input.Value <string>("qualityLabel"), Url = input.Value <string>("url"), FrameSize = input.ContainsKey("width") && input.ContainsKey("height") ? new Size(input.Value <int>("width"), input.Value <int>("height")) : null }; result.Mime = ExtractActualMime(result.Type); // get cipher info var cipher = input.Value <string>("cipher") ?? input.Value <string>("signatureCipher"); if (!string.IsNullOrEmpty(cipher)) { UpdateStreamCipherInfo(result, cipher); } return(result); }
/// <summary> /// Gets invoked by <see cref="DownloadMetadata"/> to extract adaptive_fmts. /// </summary> protected virtual List <YouTubeAdaptiveStream> ExtractAdaptiveFormatsMetadata(List <KeyValuePair <string, string> > adaptiveFmts) { var list = new List <YouTubeAdaptiveStream>(); var propertySet = new HashSet <string>(); var draft = new YouTubeAdaptiveStream(); void CommitDraft() { if (draft?.iTag != null && draft.Url != null) { list.Add(draft); } propertySet.Clear(); draft = new YouTubeAdaptiveStream(); } void Feed(string key, string value) { // check for force commit if (key == null) { CommitDraft(); return; } // check for rotation if (propertySet.Contains(key)) { CommitDraft(); } propertySet.Add(key); // update draft switch (key.ToLowerInvariant()) { case "quality_label": draft.QualityLabel = value; break; case "itag": draft.iTag = int.Parse(value); break; case "fps": draft.FPS = int.Parse(value); break; case "bitrate": draft.AudioSampleRate = int.Parse(value) * 1000; break; case "type": draft.Type = value; var parts = value.Split(new[] { ';' }, 2, StringSplitOptions.RemoveEmptyEntries); draft.Mime = parts[0]; break; case "size": var sizeRegex = new Regex(@"([0-9]+)[^0-9]+([0-9]+)"); var match = sizeRegex.Match(value); if (!match.Success) { throw new GrabParseException($"Failed to parse stream size: {value}."); } draft.FrameSize = new Size(int.Parse(match.Groups[1].Value), int.Parse(match.Groups[2].Value)); break; case "url": draft.Url = value; break; case "s": draft.Signature = value; break; } } UnmangleEntries(adaptiveFmts, Feed); return(list); }