public static string ChooseResolutionFromM3U8(string M3U8Url) { string M3U8Content = new WebClient().DownloadString(M3U8Url); MatchCollection Streams = Regex.Matches(M3U8Content, "(#EXT-X-STREAM.*)\\s(.*)"); List <(int resolution, int bandwidth, string url)> Resolutions = new List <(int, int, string)>(); foreach (Match Stream in Streams) { string INFO = Stream.Groups[1].Value; Resolutions.Add((int.Parse(Regex.Match(INFO, "RESOLUTION=[^x]*x([^,]*)").Groups[1].Value), int.Parse(Regex.Match(INFO, "BANDWIDTH=([^,]*)").Groups[1].Value), Stream.Groups[2].Value)); } IOrderedEnumerable <(int resolution, int bandwidth, string url)> OrderedResolutions = Resolutions.OrderByDescending(x => x.bandwidth).OrderByDescending(x => x.resolution); string Choice = string.Empty; bool CLIChoiceInvalid = Arguments.Quality != null && Arguments.Quality != "best" && !OrderedResolutions.Cast <Match>().Any(x => x.Groups[2].Value == Arguments.Quality); if (Arguments.Quality == null || CLIChoiceInvalid) { if (CLIChoiceInvalid) { Logger.Error("--quality value \"" + Arguments.Quality + "\" is not valid\n Please choose a new one below."); } VideoTracks(OrderedResolutions.Select(res => new[] { res.resolution.ToString(), res.bandwidth.ToString() }).ToArray()); Choice = AskInput("Which resolution do you wish to download? (use # or 'best')").Trim('#'); } else { Choice = Arguments.Quality; } var Selected = Choice == "best" ? OrderedResolutions.First() : OrderedResolutions.ElementAt(int.Parse(Choice) - 1); if (!Selected.url.StartsWith("http")) { Selected.url = M3U8Url.Substring(0, M3U8Url.LastIndexOf('/') + 1) + Selected.url; } Logger.Info("VIDEO: " + Selected.resolution + "p @ " + Selected.bandwidth + " bandwidth"); Logger.Debug("M3U8: " + Selected.url); return(Selected.url); }