@@ -7,84 +7,54 @@ namespace YoutubeExtractor
77{
88 internal static class Decipherer
99 {
10- public static string DecipherWithVersion ( string cipher , string cipherVersion )
10+ public static string DecipherOperations ( string cipherVersion )
1111 {
12- // NB: We intentionally don't cache the operations as it seems that the same operation
13- // doesn't work if the URL below isn't called
14-
1512 string jsUrl = string . Format ( "http://s.ytimg.com/yts/jsbin/html5player-{0}.js" , cipherVersion ) ;
1613 string js = HttpHelper . DownloadString ( jsUrl ) ;
1714
1815 //Find "C" in this: var A = B.sig||C (B.s)
1916 string functNamePattern = @"\.sig\s*\|\|(\w+)\(" ;
2017 var funcName = Regex . Match ( js , functNamePattern ) . Groups [ 1 ] . Value ;
21-
22- //Match nested angle braces
23- string funcBodyPattern = @"(?<brace>{([^{}]| ?(brace))*})" ;
24- //Match the function function_name (that has one argument)
18+ string funcBodyPattern = @"(?<brace>{([^{}]| ?(brace))*})" ; //Match nested angle braces
2519 string funcPattern = string . Format ( @"{0}\(\w+\){1}" , funcName , funcBodyPattern ) ;
26- var funcBody = Regex . Match ( js , funcPattern ) . Groups [ "brace" ] . Value ;
27- var lines = funcBody . Split ( ';' ) ;
28-
29- string operations = "" ;
20+ var funcBody = Regex . Match ( js , funcPattern ) . Groups [ "brace" ] . Value ; //Entire sig function
21+ var lines = funcBody . Split ( ';' ) ; //Each line in sig function
3022
31-
32- //CYNAO - 07/08/2014, Test Fix
33- /* The previous algoritms used a.splice(), where the decipher used the method (.splice()), however it seems the new algoritm
34- * renames the method to random but unique characters (example ab.dc() = splice). This code determines what each method code is,
35- * as it is defined once using the original name.
36- */
37- string id_Reverse = "" , id_Slice = "" , id_CharSwap = "" ; //Holds the new method name for each.
23+ string id_Reverse = "" , id_Slice = "" , id_CharSwap = "" ; //Hold name for each method
3824 string functionIdentifier = "" ;
25+ string operations = "" ;
3926
40- string functIDPattern = @"\w+:\bfunction\b" ; //Define as "NB:function(a,b)" where nb can be the three ciphers
41- var funcID = Regex . Match ( js , functIDPattern ) . Groups [ 1 ] . Value ;
42-
43- ///CODE ADDITION: Get the three ciphers by finding the definition
27+ //Match the code with each function. Only runs till all three are defined.
4428 foreach ( var line in lines . Skip ( 1 ) . Take ( lines . Length - 2 ) )
4529 {
46- string newVarName ; //Previous algoritms used to be just "a." - now stores temp var name as its uneccessary
47- int locOfDot , locOfBracket , functionIDLength ;
48- locOfDot = line . IndexOf ( "." ) ; // NB.AC( - gets location of the dot.
49- locOfBracket = line . IndexOf ( "(" ) ; //NB.AC( - gets location of the bracet
50- functionIDLength = locOfBracket - ( locOfDot + 1 ) ;
51- newVarName = line . Substring ( 0 , locOfDot ) ;
52- functionIdentifier = line . Substring ( locOfDot + 1 , functionIDLength ) ; //leaving us with the function AC
53-
54- //This is what the definitions currently look like, could be changed so the regex needs improving. Messy fix.
55- string tempReverse = string . Format ( @"{0}:\bfunction\b\(\w+\)" , functionIdentifier ) ; //Reverse only one that doesnt have two parameters
56- string tempSlice = string . Format ( @"{0}:\bfunction\b\([a],b\).(\breturn\b)?.?\w+\." , functionIdentifier ) ; //Regex for slice (return or not)
57- string tempCharSwap = string . Format ( @"{0}:\bfunction\b\(\w+\,\w\).\bvar\b.\bc=a\b" , functionIdentifier ) ; //Regex for the char swap.
58-
30+ if ( ! string . IsNullOrEmpty ( id_Reverse ) && ! string . IsNullOrEmpty ( id_Slice ) &&
31+ ! string . IsNullOrEmpty ( id_CharSwap ) ) { break ; } //Break out if all defined.
32+
33+ functionIdentifier = getFunctionFromLine ( line ) ;
34+ string re_Reverse = string . Format ( @"{0}:\bfunction\b\(\w+\)" , functionIdentifier ) ; //Regex for reverse (one parameter)
35+ string re_Slice = string . Format ( @"{0}:\bfunction\b\([a],b\).(\breturn\b)?.?\w+\." , functionIdentifier ) ; //Regex for slice (return or not)
36+ string re_Swap = string . Format ( @"{0}:\bfunction\b\(\w+\,\w\).\bvar\b.\bc=a\b" , functionIdentifier ) ; //Regex for the char swap.
37+
5938 Match me ;
60- if ( ( me = Regex . Match ( js , tempReverse ) ) . Success )
39+ if ( ( me = Regex . Match ( js , re_Reverse ) ) . Success )
6140 { id_Reverse = functionIdentifier ; } //If def matched the regex for reverse then the current function is a defined as the reverse cipher
6241
63- if ( ( me = Regex . Match ( js , tempSlice ) ) . Success )
42+ if ( ( me = Regex . Match ( js , re_Slice ) ) . Success )
6443 { id_Slice = functionIdentifier ; } //If def matched the regex for slice then the current function is defined as the slice cipher.
6544
66- if ( ( me = Regex . Match ( js , tempCharSwap ) ) . Success )
45+ if ( ( me = Regex . Match ( js , re_Swap ) ) . Success )
6746 { id_CharSwap = functionIdentifier ; } //If def matched the regex for charSwap then the current function is defined as swap cipher.
6847
6948 }
7049
71-
7250 foreach ( var line in lines . Skip ( 1 ) . Take ( lines . Length - 2 ) )
7351 {
7452 Match m ;
75- ///DUPLICATE CODE! Improve.
76- int locOfDot ; int locOfBracket ; int functionIDLength ;
77- locOfDot = line . IndexOf ( "." ) ;
78- locOfBracket = line . IndexOf ( "(" ) ;
79- functionIDLength = locOfBracket - ( locOfDot + 1 ) ;
80- functionIdentifier = line . Substring ( locOfDot + 1 , functionIDLength ) ; //Just needed this (define it as a member?)
81-
82- string newSliceIDRegex = string . Format ( @"(?<index>\d+)\)+" , functionIdentifier ) ;
53+ functionIdentifier = getFunctionFromLine ( line ) ;
8354
8455 if ( ( m = Regex . Match ( line , @"\(\w+,(?<index>\d+)\)" ) ) . Success && functionIdentifier == id_CharSwap )
8556 { operations += "w" + m . Groups [ "index" ] . Value + " " ; } //Character swap regex appears to be the same as before
8657
87-
8858 if ( ( m = Regex . Match ( line , @"\(\w+,(?<index>\d+)\)" ) ) . Success && functionIdentifier == id_Slice )
8959 { operations += "s" + m . Groups [ "index" ] . Value + " " ; } //Slice appears to have changed the index location???
9060 //Could be wrong and the regex needs improving, seems to work on the latest algorithm though.
@@ -93,9 +63,29 @@ public static string DecipherWithVersion(string cipher, string cipherVersion)
9363 { operations += "r " ; } //Reverse operation, no regex required
9464
9565 }
66+
9667 operations = operations . Trim ( ) ;
68+ Console . WriteLine ( operations ) ;
69+ return operations ;
70+
71+ }
72+
73+ public static string DecipherWithOperations ( string cipher , string operations )
74+ {
75+ if ( string . IsNullOrEmpty ( operations ) )
76+ { throw new NotImplementedException ( "No valid cipher operations found." ) ; }
77+
78+ return operations . Split ( new [ ] { " " } , StringSplitOptions . RemoveEmptyEntries )
79+ . Aggregate ( cipher , ApplyOperation ) ;
80+ }
9781
98- return DecipherWithOperations ( cipher , operations ) ;
82+
83+ private static string getFunctionFromLine ( string currentLine )
84+ {
85+ Regex matchFunctionReg = new Regex ( @"\w+\.(?<functionID>\w+)\(" ) ; //lc.ac(b,c) want ac.
86+ Match rgMatch = matchFunctionReg . Match ( currentLine ) ;
87+ string matchedFunction = rgMatch . Groups [ "functionID" ] . Value ;
88+ return matchedFunction ; //return 'ac'
9989 }
10090
10191 private static string ApplyOperation ( string cipher , string op )
@@ -104,7 +94,7 @@ private static string ApplyOperation(string cipher, string op)
10494 {
10595 case 'r' :
10696 return new string ( cipher . ToCharArray ( ) . Reverse ( ) . ToArray ( ) ) ;
107-
97+
10898 case 'w' :
10999 {
110100 int index = GetOpIndex ( op ) ;
@@ -122,11 +112,6 @@ private static string ApplyOperation(string cipher, string op)
122112 }
123113 }
124114
125- private static string DecipherWithOperations ( string cipher , string operations )
126- {
127- return operations . Split ( new [ ] { " " } , StringSplitOptions . RemoveEmptyEntries )
128- . Aggregate ( cipher , ApplyOperation ) ;
129- }
130115
131116 private static int GetOpIndex ( string op )
132117 {
0 commit comments