Do some code improvements
Use final where possible, annotate some methods and parameters as Nonnull and format new code to be in the 100 characters limit per line.
This commit is contained in:
parent
1c30a2725e
commit
32055147e0
|
@ -12,11 +12,12 @@ import org.schabi.newpipe.extractor.utils.Parser;
|
|||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* YouTube restricts streaming their media in multiple ways by requiring clients to apply a cipher function
|
||||
* on parameters of requests.
|
||||
* YouTube restricts streaming their media in multiple ways by requiring clients to apply a cipher
|
||||
* function on parameters of requests.
|
||||
* The cipher function is sent alongside as a JavaScript function.
|
||||
* <p>
|
||||
* This class handling fetching the JavaScript file in order to allow other classes to extract the needed functions.
|
||||
* This class handling fetching the JavaScript file in order to allow other classes to extract the
|
||||
* needed functions.
|
||||
*/
|
||||
public class YoutubeJavaScriptExtractor {
|
||||
|
||||
|
@ -27,14 +28,16 @@ public class YoutubeJavaScriptExtractor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Extracts the JavaScript file. The result is cached, so subsequent calls use the result of previous calls.
|
||||
* Extracts the JavaScript file. The result is cached, so subsequent calls use the result of
|
||||
* previous calls.
|
||||
*
|
||||
* @param videoId Does not influence the result, but a valid video id may help in the chance that YouTube tracks it.
|
||||
* @return The whole javascript file as a string.
|
||||
* @param videoId Does not influence the result, but a valid video id may help in the chance
|
||||
* that YouTube tracks it.
|
||||
* @return The whole JavaScript file as a string.
|
||||
* @throws ParsingException If the extraction failed.
|
||||
*/
|
||||
@Nonnull
|
||||
public static String extractJavaScriptCode(String videoId) throws ParsingException {
|
||||
public static String extractJavaScriptCode(final String videoId) throws ParsingException {
|
||||
if (cachedJavaScriptCode == null) {
|
||||
final String playerJsUrl = YoutubeJavaScriptExtractor.cleanJavaScriptUrl(
|
||||
YoutubeJavaScriptExtractor.extractJavaScriptUrl(videoId));
|
||||
|
@ -45,18 +48,19 @@ public class YoutubeJavaScriptExtractor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Same as {@link YoutubeJavaScriptExtractor#extractJavaScriptCode(String)} but with a constant value for videoId.
|
||||
* Same as {@link YoutubeJavaScriptExtractor#extractJavaScriptCode(String)} but with a constant
|
||||
* value for videoId.
|
||||
* Possible because the videoId has no influence on the result.
|
||||
* <p>
|
||||
* In the off chance that YouTube tracks with which video id the request is made, it may make sense to pass in
|
||||
* video ids.
|
||||
* In the off chance that YouTube tracks with which video id the request is made, it may make
|
||||
* sense to pass in video ids.
|
||||
*/
|
||||
@Nonnull
|
||||
public static String extractJavaScriptCode() throws ParsingException {
|
||||
return extractJavaScriptCode("d4IGg5dqeO8");
|
||||
}
|
||||
|
||||
private static String extractJavaScriptUrl(String videoId) throws ParsingException {
|
||||
private static String extractJavaScriptUrl(final String videoId) throws ParsingException {
|
||||
try {
|
||||
final String embedUrl = "https://www.youtube.com/embed/" + videoId;
|
||||
final String embedPageContent = NewPipe.getDownloader()
|
||||
|
@ -84,7 +88,8 @@ public class YoutubeJavaScriptExtractor {
|
|||
throw new ParsingException("Embedded info did not provide YouTube player js url");
|
||||
}
|
||||
|
||||
private static String cleanJavaScriptUrl(String playerJsUrl) {
|
||||
@Nonnull
|
||||
private static String cleanJavaScriptUrl(@Nonnull final String playerJsUrl) {
|
||||
if (playerJsUrl.startsWith("//")) {
|
||||
return HTTPS + playerJsUrl;
|
||||
} else if (playerJsUrl.startsWith("/")) {
|
||||
|
@ -95,10 +100,12 @@ public class YoutubeJavaScriptExtractor {
|
|||
}
|
||||
}
|
||||
|
||||
private static String downloadJavaScriptCode(String playerJsUrl) throws ParsingException {
|
||||
@Nonnull
|
||||
private static String downloadJavaScriptCode(final String playerJsUrl)
|
||||
throws ParsingException {
|
||||
try {
|
||||
return NewPipe.getDownloader().get(playerJsUrl, Localization.DEFAULT).responseBody();
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
throw new ParsingException("Could not get player js code from url: " + playerJsUrl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
|||
import org.schabi.newpipe.extractor.utils.JavaScript;
|
||||
import org.schabi.newpipe.extractor.utils.Parser;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -33,11 +34,12 @@ public class YoutubeThrottlingDecrypter {
|
|||
|
||||
/**
|
||||
* <p>
|
||||
* Use this if you care about the off chance that YouTube tracks with which videoId the cipher is requested.
|
||||
* Use this if you care about the off chance that YouTube tracks with which videoId the cipher
|
||||
* is requested.
|
||||
* </p>
|
||||
* Otherwise use the no-arg constructor which uses a constant value.
|
||||
*/
|
||||
public YoutubeThrottlingDecrypter(String videoId) throws ParsingException {
|
||||
public YoutubeThrottlingDecrypter(final String videoId) throws ParsingException {
|
||||
final String playerJsCode = YoutubeJavaScriptExtractor.extractJavaScriptCode(videoId);
|
||||
|
||||
functionName = parseDecodeFunctionName(playerJsCode);
|
||||
|
@ -51,17 +53,22 @@ public class YoutubeThrottlingDecrypter {
|
|||
function = parseDecodeFunction(playerJsCode, functionName);
|
||||
}
|
||||
|
||||
private String parseDecodeFunctionName(String playerJsCode) throws Parser.RegexException {
|
||||
Pattern pattern = Pattern.compile("b=a\\.get\\(\"n\"\\)\\)&&\\(b=(\\w+)\\(b\\),a\\.set\\(\"n\",b\\)");
|
||||
private String parseDecodeFunctionName(final String playerJsCode)
|
||||
throws Parser.RegexException {
|
||||
Pattern pattern = Pattern.compile(
|
||||
"b=a\\.get\\(\"n\"\\)\\)&&\\(b=(\\w+)\\(b\\),a\\.set\\(\"n\",b\\)");
|
||||
return Parser.matchGroup1(pattern, playerJsCode);
|
||||
}
|
||||
|
||||
private String parseDecodeFunction(String playerJsCode, String functionName) throws Parser.RegexException {
|
||||
Pattern functionPattern = Pattern.compile(functionName + "=function(.*?;)\n", Pattern.DOTALL);
|
||||
return "function " + functionName + Parser.matchGroup1(functionPattern, playerJsCode);
|
||||
@Nonnull
|
||||
private String parseDecodeFunction(final String playerJsCode, final String functionName)
|
||||
throws Parser.RegexException {
|
||||
Pattern functionPattern = Pattern.compile(functionName + "=function(.*?;)\n",
|
||||
Pattern.DOTALL);
|
||||
return "function " + functionName + Parser.matchGroup1(functionPattern, playerJsCode);
|
||||
}
|
||||
|
||||
public String apply(String url) throws Parser.RegexException {
|
||||
public String apply(final String url) throws Parser.RegexException {
|
||||
if (containsNParam(url)) {
|
||||
String oldNParam = parseNParam(url);
|
||||
String newNParam = decryptNParam(oldNParam);
|
||||
|
@ -71,16 +78,16 @@ public class YoutubeThrottlingDecrypter {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean containsNParam(String url) {
|
||||
private boolean containsNParam(final String url) {
|
||||
return Parser.isMatch(N_PARAM_REGEX, url);
|
||||
}
|
||||
|
||||
private String parseNParam(String url) throws Parser.RegexException {
|
||||
private String parseNParam(final String url) throws Parser.RegexException {
|
||||
Pattern nValuePattern = Pattern.compile(N_PARAM_REGEX);
|
||||
return Parser.matchGroup1(nValuePattern, url);
|
||||
}
|
||||
|
||||
private String decryptNParam(String nParam) {
|
||||
private String decryptNParam(final String nParam) {
|
||||
if (nParams.containsKey(nParam)) {
|
||||
return nParams.get(nParam);
|
||||
}
|
||||
|
@ -89,7 +96,10 @@ public class YoutubeThrottlingDecrypter {
|
|||
return decryptedNParam;
|
||||
}
|
||||
|
||||
private String replaceNParam(String url, String oldValue, String newValue) {
|
||||
@Nonnull
|
||||
private String replaceNParam(@Nonnull final String url,
|
||||
final String oldValue,
|
||||
final String newValue) {
|
||||
return url.replace(oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,17 @@ public class JavaScript {
|
|||
private JavaScript() {
|
||||
}
|
||||
|
||||
public static String run(String function, String functionName, String... parameters) {
|
||||
public static String run(final String function,
|
||||
final String functionName,
|
||||
final String... parameters) {
|
||||
try {
|
||||
Context context = Context.enter();
|
||||
final Context context = Context.enter();
|
||||
context.setOptimizationLevel(-1);
|
||||
ScriptableObject scope = context.initSafeStandardObjects();
|
||||
final ScriptableObject scope = context.initSafeStandardObjects();
|
||||
|
||||
context.evaluateString(scope, function, functionName, 1, null);
|
||||
Function jsFunction = (Function) scope.get(functionName, scope);
|
||||
Object result = jsFunction.call(context, scope, scope, parameters);
|
||||
final Function jsFunction = (Function) scope.get(functionName, scope);
|
||||
final Object result = jsFunction.call(context, scope, scope, parameters);
|
||||
return result.toString();
|
||||
} finally {
|
||||
Context.exit();
|
||||
|
|
|
@ -38,7 +38,7 @@ public class YoutubeJavaScriptExtractorTest {
|
|||
|
||||
}
|
||||
|
||||
private void assertPlayerJsCode(String playerJsCode) {
|
||||
private void assertPlayerJsCode(final String playerJsCode) {
|
||||
assertThat(playerJsCode, allOf(
|
||||
containsString(" Copyright The Closure Library Authors.\n"
|
||||
+ " SPDX-License-Identifier: Apache-2.0"),
|
||||
|
|
Loading…
Reference in New Issue