Skip to content
This repository was archived by the owner on Sep 28, 2020. It is now read-only.

Commit 8ee5948

Browse files
committed
Tidied up Decipher method
Moved duplicated code into a method, loop breakout added if all three cipher methods are found. From previous commit, restored original DownloadURLResolver.cs as the methods need to remain the same.
1 parent c7d95ab commit 8ee5948

File tree

2 files changed

+48
-35
lines changed

2 files changed

+48
-35
lines changed

YoutubeExtractor/YoutubeExtractor/Decipherer.cs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace YoutubeExtractor
77
{
88
internal static class Decipherer
99
{
10-
public static string DecipherOperations(string cipherVersion)
10+
public static string DecipherWithVersion(string cipher, string cipherVersion)
1111
{
1212
string jsUrl = string.Format("http://s.ytimg.com/yts/jsbin/html5player-{0}.js", cipherVersion);
1313
string js = HttpHelper.DownloadString(jsUrl);
@@ -20,15 +20,18 @@ public static string DecipherOperations(string cipherVersion)
2020
var funcBody = Regex.Match(js, funcPattern).Groups["brace"].Value; //Entire sig function
2121
var lines = funcBody.Split(';'); //Each line in sig function
2222

23-
string id_Reverse = "", id_Slice = "", id_CharSwap = ""; //Hold name for each method
23+
string id_Reverse = "", id_Slice = "", id_CharSwap = ""; //Hold name for each cipher method
2424
string functionIdentifier = "";
2525
string operations = "";
2626

27-
//Match the code with each function. Only runs till all three are defined.
28-
foreach (var line in lines.Skip(1).Take(lines.Length - 2))
27+
28+
foreach (var line in lines.Skip(1).Take(lines.Length - 2)) //Matchs the funcBody with each cipher method. Only runs till all three are defined.
2929
{
3030
if (!string.IsNullOrEmpty(id_Reverse) && !string.IsNullOrEmpty(id_Slice) &&
31-
!string.IsNullOrEmpty(id_CharSwap)) { break; } //Break out if all defined.
31+
!string.IsNullOrEmpty(id_CharSwap))
32+
{
33+
break; //Break loop if all three cipher methods are defined
34+
}
3235

3336
functionIdentifier = getFunctionFromLine(line);
3437
string re_Reverse = string.Format(@"{0}:\bfunction\b\(\w+\)", functionIdentifier); //Regex for reverse (one parameter)
@@ -37,13 +40,19 @@ public static string DecipherOperations(string cipherVersion)
3740

3841
Match me;
3942
if ((me = Regex.Match(js, re_Reverse)).Success)
40-
{ id_Reverse = functionIdentifier; } //If def matched the regex for reverse then the current function is a defined as the reverse cipher
43+
{
44+
id_Reverse = functionIdentifier; //If def matched the regex for reverse then the current function is a defined as the reverse
45+
}
4146

4247
if ((me = Regex.Match(js, re_Slice)).Success)
43-
{ id_Slice = functionIdentifier; } //If def matched the regex for slice then the current function is defined as the slice cipher.
48+
{
49+
id_Slice = functionIdentifier; //If def matched the regex for slice then the current function is defined as the slice.
50+
}
4451

4552
if ((me = Regex.Match(js, re_Swap)).Success)
46-
{ id_CharSwap = functionIdentifier; } //If def matched the regex for charSwap then the current function is defined as swap cipher.
53+
{
54+
id_CharSwap = functionIdentifier; //If def matched the regex for charSwap then the current function is defined as swap.
55+
}
4756

4857
}
4958

@@ -53,35 +62,30 @@ public static string DecipherOperations(string cipherVersion)
5362
functionIdentifier = getFunctionFromLine(line);
5463

5564
if ((m = Regex.Match(line, @"\(\w+,(?<index>\d+)\)")).Success && functionIdentifier == id_CharSwap)
56-
{ operations += "w" + m.Groups["index"].Value + " "; } //Character swap regex appears to be the same as before
65+
{
66+
operations += "w" + m.Groups["index"].Value + " "; //operation is a swap (w)
67+
}
5768

5869
if ((m = Regex.Match(line, @"\(\w+,(?<index>\d+)\)")).Success && functionIdentifier == id_Slice)
59-
{ operations += "s" + m.Groups["index"].Value + " "; } //Slice appears to have changed the index location???
60-
//Could be wrong and the regex needs improving, seems to work on the latest algorithm though.
70+
{
71+
operations += "s" + m.Groups["index"].Value + " "; //operation is a slice
72+
}
6173

62-
if (functionIdentifier == id_Reverse)
63-
{ operations += "r "; } //Reverse operation, no regex required
74+
if (functionIdentifier == id_Reverse) //No regex required for reverse (reverse method has no parameters)
75+
{
76+
operations += "r "; //operation is a reverse
77+
}
6478

6579
}
6680

6781
operations = operations.Trim();
68-
return operations;
6982

83+
return DecipherWithOperations(cipher, operations);
7084
}
7185

72-
public static string DecipherWithOperations(string cipher, string operations)
73-
{
74-
if (string.IsNullOrEmpty(operations))
75-
{ throw new NotImplementedException("No valid cipher operations found."); }
76-
77-
return operations.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries)
78-
.Aggregate(cipher, ApplyOperation);
79-
}
80-
81-
8286
private static string getFunctionFromLine(string currentLine)
8387
{
84-
Regex matchFunctionReg = new Regex(@"\w+\.(?<functionID>\w+)\("); //lc.ac(b,c) want ac.
88+
Regex matchFunctionReg = new Regex(@"\w+\.(?<functionID>\w+)\("); //lc.ac(b,c) want the ac part.
8589
Match rgMatch = matchFunctionReg.Match(currentLine);
8690
string matchedFunction = rgMatch.Groups["functionID"].Value;
8791
return matchedFunction; //return 'ac'
@@ -111,6 +115,11 @@ private static string ApplyOperation(string cipher, string op)
111115
}
112116
}
113117

118+
private static string DecipherWithOperations(string cipher, string operations)
119+
{
120+
return operations.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries)
121+
.Aggregate(cipher, ApplyOperation);
122+
}
114123

115124
private static int GetOpIndex(string op)
116125
{
@@ -129,4 +138,4 @@ private static string SwapFirstChar(string cipher, int index)
129138
return builder.ToString();
130139
}
131140
}
132-
}
141+
}

YoutubeExtractor/YoutubeExtractor/DownloadUrlResolver.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static class DownloadUrlResolver
2424
/// <exception cref="YoutubeParseException">
2525
/// There was an error while deciphering the signature.
2626
/// </exception>
27-
public static void DecryptDownloadUrl(VideoInfo videoInfo, string operations)
27+
public static void DecryptDownloadUrl(VideoInfo videoInfo)
2828
{
2929
IDictionary<string, string> queries = HttpHelper.ParseQueryString(videoInfo.DownloadUrl);
3030

@@ -36,10 +36,7 @@ public static void DecryptDownloadUrl(VideoInfo videoInfo, string operations)
3636

3737
try
3838
{
39-
if (encryptedSignature.Length == CorrectSignatureLength)
40-
{ decrypted = encryptedSignature; } //Doesn't require decrypting
41-
else
42-
{ decrypted = Decipherer.DecipherWithOperations(encryptedSignature, operations); } //Use operations get decrypted cipher
39+
decrypted = GetDecipheredSignature(videoInfo.HtmlPlayerVersion, encryptedSignature);
4340
}
4441

4542
catch (Exception ex)
@@ -97,17 +94,14 @@ public static IEnumerable<VideoInfo> GetDownloadUrls(string videoUrl, bool decry
9794
IEnumerable<VideoInfo> infos = GetVideoInfos(downloadUrls, videoTitle).ToList();
9895

9996
string htmlPlayerVersion = GetHtml5PlayerVersion(json);
100-
string operations = ""; //Same operations for the same html5Player
10197

10298
foreach (VideoInfo info in infos)
10399
{
104100
info.HtmlPlayerVersion = htmlPlayerVersion;
105101

106102
if (decryptSignature && info.RequiresDecryption)
107103
{
108-
if (string.IsNullOrEmpty(operations)) //Get operations if we don't
109-
{ operations = Decipherer.DecipherOperations(htmlPlayerVersion); }
110-
DecryptDownloadUrl(info, operations);
104+
DecryptDownloadUrl(info);
111105
}
112106
}
113107

@@ -219,6 +213,16 @@ private static string GetAdaptiveStreamMap(JObject json)
219213
return streamMap.ToString();
220214
}
221215

216+
private static string GetDecipheredSignature(string htmlPlayerVersion, string signature)
217+
{
218+
if (signature.Length == CorrectSignatureLength)
219+
{
220+
return signature;
221+
}
222+
223+
return Decipherer.DecipherWithVersion(signature, htmlPlayerVersion);
224+
}
225+
222226
private static string GetHtml5PlayerVersion(JObject json)
223227
{
224228
var regex = new Regex(@"html5player-(.+?)\.js");

0 commit comments

Comments
 (0)