@@ -30,33 +30,45 @@ final class YoutubeThrottlingParameterUtils {
3030 private static final Pattern [] DEOBFUSCATION_FUNCTION_NAME_REGEXES = {
3131
3232 /*
33- * The first regex matches the following text, where we want Wma and the array index
34- * accessed:
33+ * Matches the following text, where we want SDa and the array index accessed:
3534 *
3635 * a.D&&(b="nn"[+a.D],WL(a),c=a.j[b]||null)&&(c=SDa[0](c),a.set(b,c),SDa.length||Wma("")
3736 */
3837 Pattern .compile (SINGLE_CHAR_VARIABLE_REGEX + "=\" nn\" \\ [\\ +" + MULTIPLE_CHARS_REGEX
3938 + "\\ ." + MULTIPLE_CHARS_REGEX + "]," + MULTIPLE_CHARS_REGEX + "\\ ("
4039 + MULTIPLE_CHARS_REGEX + "\\ )," + MULTIPLE_CHARS_REGEX + "="
4140 + MULTIPLE_CHARS_REGEX + "\\ ." + MULTIPLE_CHARS_REGEX + "\\ ["
42- + MULTIPLE_CHARS_REGEX + "]\\ |\\ |null\\ ).+ \\ | \\ | (" + MULTIPLE_CHARS_REGEX
43- + ") \\ ( \" \" \\ )" ),
41+ + MULTIPLE_CHARS_REGEX + "]\\ |\\ |null\\ )&& \\ (" + MULTIPLE_CHARS_REGEX + "=("
42+ + MULTIPLE_CHARS_REGEX + ")" + ARRAY_ACCESS_REGEX ),
4443
4544 /*
46- * The second regex matches the following text, where we want SDa and the array index
47- * accessed:
45+ * Matches the following text, where we want Wma:
4846 *
4947 * a.D&&(b="nn"[+a.D],WL(a),c=a.j[b]||null)&&(c=SDa[0](c),a.set(b,c),SDa.length||Wma("")
5048 */
5149 Pattern .compile (SINGLE_CHAR_VARIABLE_REGEX + "=\" nn\" \\ [\\ +" + MULTIPLE_CHARS_REGEX
5250 + "\\ ." + MULTIPLE_CHARS_REGEX + "]," + MULTIPLE_CHARS_REGEX + "\\ ("
5351 + MULTIPLE_CHARS_REGEX + "\\ )," + MULTIPLE_CHARS_REGEX + "="
5452 + MULTIPLE_CHARS_REGEX + "\\ ." + MULTIPLE_CHARS_REGEX + "\\ ["
55- + MULTIPLE_CHARS_REGEX + "]\\ |\\ |null\\ )&&\\ (" + MULTIPLE_CHARS_REGEX + "=("
56- + MULTIPLE_CHARS_REGEX + ")" + ARRAY_ACCESS_REGEX ),
53+ + MULTIPLE_CHARS_REGEX + "]\\ |\\ |null\\ ).+\\ |\\ |(" + MULTIPLE_CHARS_REGEX
54+ + ")\\ (\" \" \\ )" ),
55+
56+ /*
57+ * Matches the following text, where we want cvb and the array index accessed:
58+ *
59+ * ,Vb(m),W=m.j[c]||null)&&(W=cvb[0](W),m.set(c,W)
60+ */
61+ Pattern .compile ("," + MULTIPLE_CHARS_REGEX + "\\ ("
62+ + MULTIPLE_CHARS_REGEX + "\\ )," + MULTIPLE_CHARS_REGEX + "="
63+ + MULTIPLE_CHARS_REGEX + "\\ ." + MULTIPLE_CHARS_REGEX + "\\ ["
64+ + MULTIPLE_CHARS_REGEX + "]\\ |\\ |null\\ )&&\\ (\\ b" + MULTIPLE_CHARS_REGEX + "=("
65+ + MULTIPLE_CHARS_REGEX + ")" + ARRAY_ACCESS_REGEX + "\\ ("
66+ + SINGLE_CHAR_VARIABLE_REGEX + "\\ )," + MULTIPLE_CHARS_REGEX
67+ + "\\ .set\\ ((?:\" n+\" |" + MULTIPLE_CHARS_REGEX + ")," + MULTIPLE_CHARS_REGEX
68+ + "\\ )" ),
5769
5870 /*
59- * The third regex matches the following text, where we want rma:
71+ * Matches the following text, where we want rma:
6072 *
6173 * a.D&&(b="nn"[+a.D],c=a.get(b))&&(c=rDa[0](c),a.set(b,c),rDa.length||rma("")
6274 */
@@ -66,8 +78,7 @@ final class YoutubeThrottlingParameterUtils {
6678 + MULTIPLE_CHARS_REGEX + ")\\ (\" \" \\ )" ),
6779
6880 /*
69- * The fourth regex matches the following text, where we want rDa and the array index
70- * accessed:
81+ * Matches the following text, where we want rDa and the array index accessed:
7182 *
7283 * a.D&&(b="nn"[+a.D],c=a.get(b))&&(c=rDa[0](c),a.set(b,c),rDa.length||rma("")
7384 */
@@ -77,8 +88,7 @@ final class YoutubeThrottlingParameterUtils {
7788 + MULTIPLE_CHARS_REGEX + "=(" + MULTIPLE_CHARS_REGEX + ")\\ [(\\ d+)]" ),
7889
7990 /*
80- * The fifth regex matches the following text, where we want BDa and the array index
81- * accessed:
91+ * Matches the following text, where we want BDa and the array index accessed:
8292 *
8393 * (b=String.fromCharCode(110),c=a.get(b))&&(c=BDa[0](c)
8494 */
@@ -89,8 +99,7 @@ final class YoutubeThrottlingParameterUtils {
8999 + SINGLE_CHAR_VARIABLE_REGEX + "\\ )" ),
90100
91101 /*
92- * The sixth regex matches the following text, where we want Yva and the array index
93- * accessed:
102+ * Matches the following text, where we want Yva and the array index accessed:
94103 *
95104 * .get("n"))&&(b=Yva[0](b)
96105 */
@@ -112,6 +121,13 @@ final class YoutubeThrottlingParameterUtils {
112121 private static final String FUNCTION_NAMES_IN_DEOBFUSCATION_ARRAY_REGEX =
113122 "\\ s*=\\ s*\\ [(.+?)][;,]" ;
114123
124+ private static final String FUNCTION_ARGUMENTS_REGEX =
125+ "=\\ s*function\\ s*\\ (\\ s*([^)]*)\\ s*\\ )" ;
126+
127+ private static final String EARLY_RETURN_REGEX =
128+ ";\\ s*if\\ s*\\ (\\ s*typeof\\ s+" + MULTIPLE_CHARS_REGEX
129+ + "+\\ s*===?\\ s*([\" '])undefined\\ 1\\ s*\\ )\\ s*return\\ s+" ;
130+
115131 private YoutubeThrottlingParameterUtils () {
116132 }
117133
@@ -154,19 +170,21 @@ static String getDeobfuscationFunctionName(@Nonnull final String javaScriptPlaye
154170 * Get the throttling parameter deobfuscation code of YouTube's base JavaScript file.
155171 *
156172 * @param javaScriptPlayerCode the complete JavaScript base player code
157- * @return the throttling parameter deobfuscation function name
173+ * @return the throttling parameter deobfuscation function code
158174 * @throws ParsingException if the throttling parameter deobfuscation code couldn't be
159175 * extracted
160176 */
161177 @ Nonnull
162178 static String getDeobfuscationFunction (@ Nonnull final String javaScriptPlayerCode ,
163179 @ Nonnull final String functionName )
164180 throws ParsingException {
181+ String function ;
165182 try {
166- return parseFunctionWithLexer (javaScriptPlayerCode , functionName );
183+ function = parseFunctionWithLexer (javaScriptPlayerCode , functionName );
167184 } catch (final Exception e ) {
168- return parseFunctionWithRegex (javaScriptPlayerCode , functionName );
185+ function = parseFunctionWithRegex (javaScriptPlayerCode , functionName );
169186 }
187+ return fixupFunction (function );
170188 }
171189
172190 /**
@@ -214,4 +232,33 @@ private static String validateFunction(@Nonnull final String function) {
214232 JavaScript .compileOrThrow (function );
215233 return function ;
216234 }
235+
236+ /**
237+ * Removes an early return statement from the code of the throttling parameter deobfuscation function.
238+ *
239+ * <p>In newer version of the player code the function contains a check for something defined outside of the function.
240+ * If that was not found it will return early.
241+ *
242+ * <p>The check can look like this (JS):<br>
243+ * if(typeof RUQ==="undefined")return p;
244+ *
245+ * <p>In this example RUQ will always be undefined when running the function as standalone.
246+ * If the check is kept it would just return p which is the input parameter and would be wrong.
247+ * For that reason this check and return statement needs to be removed.
248+ *
249+ * @param function the original throttling parameter deobfuscation function code
250+ * @return the throttling parameter deobfuscation function code with the early return statement removed
251+ */
252+ @ Nonnull
253+ private static String fixupFunction (@ Nonnull final String function )
254+ throws Parser .RegexException {
255+ final String firstArgName = Parser
256+ .matchGroup1 (FUNCTION_ARGUMENTS_REGEX , function )
257+ .split ("," )[0 ].trim ();
258+ final Pattern earlyReturnPattern = Pattern .compile (
259+ EARLY_RETURN_REGEX + firstArgName + ";" ,
260+ Pattern .DOTALL );
261+ final Matcher earlyReturnCodeMatcher = earlyReturnPattern .matcher (function );
262+ return earlyReturnCodeMatcher .replaceFirst (";" );
263+ }
217264}
0 commit comments