private static IEnumerable <VideoInfo> GetVideoInfos(IEnumerable <ExtractionInfo> extractionInfos, string videoTitle) { var downLoadInfos = new List <VideoInfo>(); foreach (ExtractionInfo extractionInfo in extractionInfos) { string itag = HTTPHelperYoutube.ParseQueryString(extractionInfo.Uri.Query)["itag"]; int formatCode = int.Parse(itag); VideoInfo info = VideoInfo.Defaults.SingleOrDefault(videoInfo => videoInfo.FormatCode == formatCode); if (info != null) { info = new VideoInfo(info) { DownloadUrl = extractionInfo.Uri.ToString(), Title = videoTitle, RequiresDecryption = extractionInfo.RequiresDecryption }; } else { info = new VideoInfo(formatCode) { DownloadUrl = extractionInfo.Uri.ToString() }; } downLoadInfos.Add(info); } return(downLoadInfos); }
public static bool TryNormalizeYoutubeUrl(string url, out string normalizedUrl) { url = url.Trim(); url = url.Replace("youtu.be/", "youtube.com/watch?v="); url = url.Replace("www.youtube", "youtube"); url = url.Replace("youtube.com/embed/", "youtube.com/watch?v="); if (url.Contains("/v/")) { url = "https://youtube.com" + new Uri(url).AbsolutePath.Replace("/v/", "/watch?v="); } url = url.Replace("/watch#", "/watch?"); IDictionary <string, string> query = HTTPHelperYoutube.ParseQueryString(url); string v; if (!query.TryGetValue("v", out v)) { normalizedUrl = null; return(false); } normalizedUrl = "https://youtube.com/watch?v=" + v; return(true); }
} //END TryNormalizeYoutubeUrl //--------------------------------------------------------------------------------// private static IEnumerable <ExtractionInfo> ExtractDownloadUrls(JObject json) //--------------------------------------------------------------------------------// { string[] splitByUrls = GetStreamMap(json).Split(','); string[] adaptiveFmtSplitByUrls = GetAdaptiveStreamMap(json).Split(','); splitByUrls = splitByUrls.Concat(adaptiveFmtSplitByUrls).ToArray(); foreach (string s in splitByUrls) { IDictionary <string, string> queries = HTTPHelperYoutube.ParseQueryString(s); string url; bool requiresDecryption = false; if (queries.ContainsKey("s") || queries.ContainsKey("sig")) { requiresDecryption = queries.ContainsKey("s"); string signature = queries.ContainsKey("s") ? queries["s"] : queries["sig"]; url = string.Format("{0}&{1}={2}", queries["url"], SignatureQuery, signature); string fallbackHost = queries.ContainsKey("fallback_host") ? "&fallback_host=" + queries["fallback_host"] : String.Empty; url += fallbackHost; } else { url = queries["url"]; } url = HTTPHelperYoutube.UrlDecode(url); url = HTTPHelperYoutube.UrlDecode(url); IDictionary <string, string> parameters = HTTPHelperYoutube.ParseQueryString(url); if (!parameters.ContainsKey(RateBypassFlag)) { url += string.Format("&{0}={1}", RateBypassFlag, "yes"); } yield return(new ExtractionInfo { RequiresDecryption = requiresDecryption, Uri = new Uri(url) }); } } //END ExtractDownloadUrls
public IEnumerator DecryptDownloadUrl(Action <string> callback, VideoInfo videoInfo) { IDictionary <string, string> queries = HTTPHelperYoutube.ParseQueryString(videoInfo.DownloadUrl); if (queries.ContainsKey(SignatureQuery)) { string encryptedSignature = queries[SignatureQuery]; //decrypted = GetDecipheredSignature( encryptedSignature); //MagicHands.DecipherWithVersion(encryptedSignature, videoInfo.HtmlPlayerVersion); //string jsUrl = string.Format("http://s.ytimg.com/yts/jsbin/{0}-{1}.js", videoInfo.HtmlscriptName, videoInfo.HtmlPlayerVersion); string jsUrl = string.Format("http://s.ytimg.com/yts/jsbin/player{0}.js", videoInfo.HtmlPlayerVersion); yield return(StartCoroutine(DownloadUrl(jsUrl))); string js = downloadUrlResponse.data; //Find "C" in this: var A = B.sig||C (B.s) string functNamePattern = @"(\w+)=function\((\w+)\){\2=\2\.split\(\""\""\);"; //Regex Formed To Find Word or DollarSign var funcName = Regex.Match(js, functNamePattern).Groups[1].Value; if (funcName.Contains("$")) { funcName = "\\" + funcName; //Due To Dollar Sign Introduction, Need To Escape } string funcPattern = @"(?!h\.)" + @funcName + @"=function\(\w+\)\{.*?\}"; //Escape funcName string var funcBody = Regex.Match(js, funcPattern, RegexOptions.Singleline).Value; //Entire sig function var lines = funcBody.Split(';'); //Each line in sig function string idReverse = "", idSlice = "", idCharSwap = ""; //Hold name for each cipher method string functionIdentifier = ""; string operations = ""; foreach (var line in lines.Skip(1).Take(lines.Length - 2)) //Matches the funcBody with each cipher method. Only runs till all three are defined. { if (!string.IsNullOrEmpty(idReverse) && !string.IsNullOrEmpty(idSlice) && !string.IsNullOrEmpty(idCharSwap)) { break; //Break loop if all three cipher methods are defined } functionIdentifier = GetFunctionFromLine(line); string reReverse = string.Format(@"{0}:\bfunction\b\(\w+\)", functionIdentifier); //Regex for reverse (one parameter) string reSlice = string.Format(@"{0}:\bfunction\b\([a],b\).(\breturn\b)?.?\w+\.", functionIdentifier); //Regex for slice (return or not) string reSwap = string.Format(@"{0}:\bfunction\b\(\w+\,\w\).\bvar\b.\bc=a\b", functionIdentifier); //Regex for the char swap. if (Regex.Match(js, reReverse).Success) { idReverse = functionIdentifier; //If def matched the regex for reverse then the current function is a defined as the reverse } if (Regex.Match(js, reSlice).Success) { idSlice = functionIdentifier; //If def matched the regex for slice then the current function is defined as the slice. } if (Regex.Match(js, reSwap).Success) { idCharSwap = functionIdentifier; //If def matched the regex for charSwap then the current function is defined as swap. } } foreach (var line in lines.Skip(1).Take(lines.Length - 2)) { Match m; functionIdentifier = GetFunctionFromLine(line); if ((m = Regex.Match(line, @"\(\w+,(?<index>\d+)\)")).Success && functionIdentifier == idCharSwap) { operations += "w" + m.Groups["index"].Value + " "; //operation is a swap (w) } if ((m = Regex.Match(line, @"\(\w+,(?<index>\d+)\)")).Success && functionIdentifier == idSlice) { operations += "s" + m.Groups["index"].Value + " "; //operation is a slice } if (functionIdentifier == idReverse) //No regex required for reverse (reverse method has no parameters) { operations += "r "; //operation is a reverse } } operations = operations.Trim(); string magicResult = MagicHands.DecipherWithOperations(encryptedSignature, operations); videoInfo.DownloadUrl = HTTPHelperYoutube.ReplaceQueryStringParameter(videoInfo.DownloadUrl, SignatureQuery, magicResult); videoInfo.RequiresDecryption = false; callback.Invoke(videoInfo.DownloadUrl); } else { yield return(null); } }
public void DoRegexFunctionsForVideo() { string js = masterURLForVideo; //Find "C" in this: var A = B.sig||C (B.s) string functNamePattern = @"(\w+)\s*=\s*function\(\s*(\w+)\s*\)\s*{\s*\2\s*=\s*\2\.split\(\""\""\)\s*;(.+)return\s*\2\.join\(\""\""\)\s*}\s*;"; var funcName = Regex.Match(js, functNamePattern).Groups[1].Value; if (funcName.Contains("$")) { funcName = "\\" + funcName; //Due To Dollar Sign Introduction, Need To Escape } string funcPattern = @"(?!h\.)" + @funcName + @"=function\(\w+\)\{.*?\}"; //Escape funcName string var funcBody = Regex.Match(js, funcPattern, RegexOptions.Singleline).Value; //Entire sig function var lines = funcBody.Split(';'); //Each line in sig function string idReverse = "", idSlice = "", idCharSwap = ""; //Hold name for each cipher method string functionIdentifier = ""; string operations = ""; foreach (var line in lines.Skip(1).Take(lines.Length - 2)) //Matches the funcBody with each cipher method. Only runs till all three are defined. { if (!string.IsNullOrEmpty(idReverse) && !string.IsNullOrEmpty(idSlice) && !string.IsNullOrEmpty(idCharSwap)) { break; //Break loop if all three cipher methods are defined } functionIdentifier = GetFunctionFromLine(line); string reReverse = string.Format(@"{0}:\bfunction\b\(\w+\)", functionIdentifier); //Regex for reverse (one parameter) string reSlice = string.Format(@"{0}:\bfunction\b\([a],b\).(\breturn\b)?.?\w+\.", functionIdentifier); //Regex for slice (return or not) string reSwap = string.Format(@"{0}:\bfunction\b\(\w+\,\w\).\bvar\b.\bc=a\b", functionIdentifier); //Regex for the char swap. if (Regex.Match(js, reReverse).Success) { idReverse = functionIdentifier; //If def matched the regex for reverse then the current function is a defined as the reverse } if (Regex.Match(js, reSlice).Success) { idSlice = functionIdentifier; //If def matched the regex for slice then the current function is defined as the slice. } if (Regex.Match(js, reSwap).Success) { idCharSwap = functionIdentifier; //If def matched the regex for charSwap then the current function is defined as swap. } } foreach (var line in lines.Skip(1).Take(lines.Length - 2)) { Match m; functionIdentifier = GetFunctionFromLine(line); if ((m = Regex.Match(line, @"\(\w+,(?<index>\d+)\)")).Success && functionIdentifier == idCharSwap) { operations += "w" + m.Groups["index"].Value + " "; //operation is a swap (w) } if ((m = Regex.Match(line, @"\(\w+,(?<index>\d+)\)")).Success && functionIdentifier == idSlice) { operations += "s" + m.Groups["index"].Value + " "; //operation is a slice } if (functionIdentifier == idReverse) //No regex required for reverse (reverse method has no parameters) { operations += "r "; //operation is a reverse } } operations = operations.Trim(); string magicResult = MagicHands.DecipherWithOperations(encryptedSignatureVideo, operations); decryptedVideoUrlResult = HTTPHelperYoutube.ReplaceQueryStringParameter(EncryptUrlForVideo, SignatureQuery, magicResult); decryptedUrlForVideo = true; }