Skip to content

Commit d39fc43

Browse files
XiangRongLinStypox
andcommitted
[Youtube] Adjust throttling function extraction to changes (#1191)
* [Youtube] Adjust throttling function extraction to changes --------- Co-authored-by: Stypox <[email protected]>
1 parent bba3b6c commit d39fc43

File tree

3 files changed

+79
-26
lines changed

3 files changed

+79
-26
lines changed

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

+12-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.schabi.newpipe.extractor.services.youtube;
22

3+
import static org.schabi.newpipe.extractor.utils.Parser.matchGroup1MultiplePatterns;
4+
35
import org.schabi.newpipe.extractor.exceptions.ParsingException;
46
import org.schabi.newpipe.extractor.utils.JavaScript;
57
import org.schabi.newpipe.extractor.utils.Parser;
@@ -20,13 +22,13 @@ final class YoutubeSignatureUtils {
2022
*/
2123
static final String DEOBFUSCATION_FUNCTION_NAME = "deobfuscate";
2224

23-
private static final String[] FUNCTION_REGEXES = {
24-
"\\bm=([a-zA-Z0-9$]{2,})\\(decodeURIComponent\\(h\\.s\\)\\)",
25-
"\\bc&&\\(c=([a-zA-Z0-9$]{2,})\\(decodeURIComponent\\(c\\)\\)",
25+
private static final Pattern[] FUNCTION_REGEXES = {
2626
// CHECKSTYLE:OFF
27-
"(?:\\b|[^a-zA-Z0-9$])([a-zA-Z0-9$]{2,})\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)",
27+
Pattern.compile("\\bm=([a-zA-Z0-9$]{2,})\\(decodeURIComponent\\(h\\.s\\)\\)"),
28+
Pattern.compile("\\bc&&\\(c=([a-zA-Z0-9$]{2,})\\(decodeURIComponent\\(c\\)\\)"),
29+
Pattern.compile("(?:\\b|[^a-zA-Z0-9$])([a-zA-Z0-9$]{2,})\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)"),
30+
Pattern.compile("([\\w$]+)\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;")
2831
// CHECKSTYLE:ON
29-
"([\\w$]+)\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;"
3032
};
3133

3234
private static final String STS_REGEX = "signatureTimestamp[=:](\\d+)";
@@ -104,19 +106,12 @@ static String getDeobfuscationCode(@Nonnull final String javaScriptPlayerCode)
104106
@Nonnull
105107
private static String getDeobfuscationFunctionName(@Nonnull final String javaScriptPlayerCode)
106108
throws ParsingException {
107-
Parser.RegexException exception = null;
108-
for (final String regex : FUNCTION_REGEXES) {
109-
try {
110-
return Parser.matchGroup1(regex, javaScriptPlayerCode);
111-
} catch (final Parser.RegexException e) {
112-
if (exception == null) {
113-
exception = e;
114-
}
115-
}
109+
try {
110+
return matchGroup1MultiplePatterns(FUNCTION_REGEXES, javaScriptPlayerCode);
111+
} catch (final Parser.RegexException e) {
112+
throw new ParsingException(
113+
"Could not find deobfuscation function with any of the known patterns", e);
116114
}
117-
118-
throw new ParsingException(
119-
"Could not find deobfuscation function with any of the known patterns", exception);
120115
}
121116

122117
@Nonnull

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

+36-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.schabi.newpipe.extractor.services.youtube;
22

3+
import static org.schabi.newpipe.extractor.utils.Parser.matchMultiplePatterns;
4+
35
import org.schabi.newpipe.extractor.exceptions.ParsingException;
46
import org.schabi.newpipe.extractor.utils.JavaScript;
57
import org.schabi.newpipe.extractor.utils.Parser;
@@ -18,10 +20,33 @@ final class YoutubeThrottlingParameterUtils {
1820

1921
private static final Pattern THROTTLING_PARAM_PATTERN = Pattern.compile("[&?]n=([^&]+)");
2022

21-
private static final Pattern DEOBFUSCATION_FUNCTION_NAME_PATTERN = Pattern.compile(
22-
// CHECKSTYLE:OFF
23-
"\\.get\\(\"n\"\\)\\)&&\\([a-zA-Z0-9$_]=([a-zA-Z0-9$_]+)(?:\\[(\\d+)])?\\([a-zA-Z0-9$_]\\)");
24-
// CHECKSTYLE:ON
23+
private static final String SINGLE_CHAR_VARIABLE_REGEX = "[a-zA-Z0-9$_]";
24+
25+
private static final String FUNCTION_NAME_REGEX = SINGLE_CHAR_VARIABLE_REGEX + "+";
26+
27+
private static final String ARRAY_ACCESS_REGEX = "\\[(\\d+)]";
28+
29+
/**
30+
* The first regex matches this, where we want BDa:
31+
* <p>
32+
* (b=String.fromCharCode(110),c=a.get(b))&&(c=<strong>BDa</strong><strong>[0]</strong>(c)
33+
* <p>
34+
* Array access is optional, but needs to be handled, since the actual function is inside the
35+
* array.
36+
*/
37+
// CHECKSTYLE:OFF
38+
private static final Pattern[] DEOBFUSCATION_FUNCTION_NAME_REGEXES = {
39+
Pattern.compile("\\(" + SINGLE_CHAR_VARIABLE_REGEX + "=String\\.fromCharCode\\(110\\),"
40+
+ SINGLE_CHAR_VARIABLE_REGEX + "=" + SINGLE_CHAR_VARIABLE_REGEX + "\\.get\\("
41+
+ SINGLE_CHAR_VARIABLE_REGEX + "\\)\\)" + "&&\\(" + SINGLE_CHAR_VARIABLE_REGEX
42+
+ "=(" + FUNCTION_NAME_REGEX + ")" + "(?:" + ARRAY_ACCESS_REGEX + ")?\\("
43+
+ SINGLE_CHAR_VARIABLE_REGEX + "\\)"),
44+
Pattern.compile("\\.get\\(\"n\"\\)\\)&&\\(" + SINGLE_CHAR_VARIABLE_REGEX
45+
+ "=(" + FUNCTION_NAME_REGEX + ")(?:" + ARRAY_ACCESS_REGEX + ")?\\("
46+
+ SINGLE_CHAR_VARIABLE_REGEX + "\\)"),
47+
};
48+
// CHECKSTYLE:ON
49+
2550

2651
// Escape the curly end brace to allow compatibility with Android's regex engine
2752
// See https://stackoverflow.com/q/45074813
@@ -48,11 +73,13 @@ private YoutubeThrottlingParameterUtils() {
4873
@Nonnull
4974
static String getDeobfuscationFunctionName(@Nonnull final String javaScriptPlayerCode)
5075
throws ParsingException {
51-
final Matcher matcher = DEOBFUSCATION_FUNCTION_NAME_PATTERN.matcher(javaScriptPlayerCode);
52-
if (!matcher.find()) {
53-
throw new ParsingException("Failed to find deobfuscation function name pattern \""
54-
+ DEOBFUSCATION_FUNCTION_NAME_PATTERN
55-
+ "\" in the base JavaScript player code");
76+
final Matcher matcher;
77+
try {
78+
matcher = matchMultiplePatterns(DEOBFUSCATION_FUNCTION_NAME_REGEXES,
79+
javaScriptPlayerCode);
80+
} catch (final Parser.RegexException e) {
81+
throw new ParsingException("Could not find deobfuscation function with any of the "
82+
+ "known patterns in the base JavaScript player code", e);
5683
}
5784

5885
final String functionName = matcher.group(1);

extractor/src/main/java/org/schabi/newpipe/extractor/utils/Parser.java

+31
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,37 @@ public static String matchGroup(@Nonnull final Pattern pat,
7878
}
7979
}
8080

81+
public static String matchGroup1MultiplePatterns(final Pattern[] patterns, final String input)
82+
throws RegexException {
83+
return matchMultiplePatterns(patterns, input).group(1);
84+
}
85+
86+
public static Matcher matchMultiplePatterns(final Pattern[] patterns, final String input)
87+
throws RegexException {
88+
Parser.RegexException exception = null;
89+
for (final Pattern pattern : patterns) {
90+
final Matcher matcher = pattern.matcher(input);
91+
if (matcher.find()) {
92+
return matcher;
93+
} else if (exception == null) {
94+
// only pass input to exception message when it is not too long
95+
if (input.length() > 1024) {
96+
exception = new RegexException("Failed to find pattern \"" + pattern.pattern()
97+
+ "\"");
98+
} else {
99+
exception = new RegexException("Failed to find pattern \"" + pattern.pattern()
100+
+ "\" inside of \"" + input + "\"");
101+
}
102+
}
103+
}
104+
105+
if (exception == null) {
106+
throw new RegexException("Empty patterns array passed to matchMultiplePatterns");
107+
} else {
108+
throw exception;
109+
}
110+
}
111+
81112
public static boolean isMatch(final String pattern, final String input) {
82113
final Pattern pat = Pattern.compile(pattern);
83114
final Matcher mat = pat.matcher(input);

0 commit comments

Comments
 (0)