Skip to content

Commit 1ca8275

Browse files
authored
Merge pull request #1253 from gechoto/fix-n-func
[YouTube] Fixes for n param deobfuscation function
2 parents e0359ab + b74a8d0 commit 1ca8275

1 file changed

Lines changed: 65 additions & 18 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeThrottlingParameterUtils.java

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)