Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[YouTube] Remove deprecated throttling decryption code #901

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,43 +33,18 @@
* </p>
*
*/
public class YoutubeThrottlingDecrypter {
public final class YoutubeThrottlingDecrypter {

private static final Pattern N_PARAM_PATTERN = Pattern.compile("[&?]n=([^&]+)");
private static final Pattern FUNCTION_NAME_PATTERN = Pattern.compile(
private static final Pattern DECRYPT_FUNCTION_NAME_PATTERN = Pattern.compile(
"\\.get\\(\"n\"\\)\\)&&\\(b=([a-zA-Z0-9$]+)(?:\\[(\\d+)])?\\([a-zA-Z0-9]\\)");

private static final Map<String, String> N_PARAMS_CACHE = new HashMap<>();
@SuppressWarnings("StaticVariableName") private static String FUNCTION;
@SuppressWarnings("StaticVariableName") private static String FUNCTION_NAME;
private static String decryptFunction;
private static String decryptFunctionName;

private final String functionName;
private final String function;

/**
* <p>
* 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.
*
* @deprecated Use static function instead
*/
public YoutubeThrottlingDecrypter(final String videoId) throws ParsingException {
final String playerJsCode = YoutubeJavaScriptExtractor.extractJavaScriptCode(videoId);

functionName = parseDecodeFunctionName(playerJsCode);
function = parseDecodeFunction(playerJsCode, functionName);
}

/**
* @deprecated Use static function instead
*/
public YoutubeThrottlingDecrypter() throws ParsingException {
final String playerJsCode = YoutubeJavaScriptExtractor.extractJavaScriptCode();

functionName = parseDecodeFunctionName(playerJsCode);
function = parseDecodeFunction(playerJsCode, functionName);
private YoutubeThrottlingDecrypter() {
// No implementation
}

/**
Expand All @@ -91,7 +66,7 @@ public YoutubeThrottlingDecrypter() throws ParsingException {
* function. It can be a constant value of any existing video, but a
* constant value is discouraged, because it could allow tracking.
* @return A streaming URL with the decrypted parameter or the streaming URL itself if no
* throttling parameter has been found
* throttling parameter has been found.
* @throws ParsingException If the streaming URL contains a throttling parameter and its
* decryption failed
*/
Expand All @@ -102,16 +77,16 @@ public static String apply(@Nonnull final String streamingUrl,
}

try {
if (FUNCTION == null) {
if (decryptFunction == null) {
final String playerJsCode
= YoutubeJavaScriptExtractor.extractJavaScriptCode(videoId);

FUNCTION_NAME = parseDecodeFunctionName(playerJsCode);
FUNCTION = parseDecodeFunction(playerJsCode, FUNCTION_NAME);
decryptFunctionName = parseDecodeFunctionName(playerJsCode);
decryptFunction = parseDecodeFunction(playerJsCode, decryptFunctionName);
}

final String oldNParam = parseNParam(streamingUrl);
final String newNParam = decryptNParam(FUNCTION, FUNCTION_NAME, oldNParam);
final String newNParam = decryptNParam(decryptFunction, decryptFunctionName, oldNParam);
return replaceNParam(streamingUrl, oldNParam, newNParam);
} catch (final Exception e) {
throw new ParsingException("Could not parse, decrypt or replace n parameter", e);
Expand All @@ -120,11 +95,10 @@ public static String apply(@Nonnull final String streamingUrl,

private static String parseDecodeFunctionName(final String playerJsCode)
throws Parser.RegexException {
final Matcher matcher = FUNCTION_NAME_PATTERN.matcher(playerJsCode);
final boolean foundMatch = matcher.find();
if (!foundMatch) {
final Matcher matcher = DECRYPT_FUNCTION_NAME_PATTERN.matcher(playerJsCode);
if (!matcher.find()) {
throw new Parser.RegexException("Failed to find pattern \""
+ FUNCTION_NAME_PATTERN + "\"");
+ DECRYPT_FUNCTION_NAME_PATTERN + "\"");
}

final String functionName = matcher.group(1);
Expand Down Expand Up @@ -166,17 +140,6 @@ private static String parseWithRegex(final String playerJsCode, final String fun
return "function " + functionName + Parser.matchGroup1(functionPattern, playerJsCode);
}

@Deprecated
public String apply(final String url) throws ParsingException {
if (containsNParam(url)) {
final String oldNParam = parseNParam(url);
final String newNParam = decryptNParam(function, functionName, oldNParam);
return replaceNParam(url, oldNParam, newNParam);
} else {
return url;
}
}

private static boolean containsNParam(final String url) {
return Parser.isMatch(N_PARAM_PATTERN, url);
}
Expand Down Expand Up @@ -204,14 +167,14 @@ private static String replaceNParam(@Nonnull final String url,
}

/**
* @return the number of the cached "n" query parameters.
* @return The number of the cached {@code n} query parameters.
*/
public static int getCacheSize() {
return N_PARAMS_CACHE.size();
}

/**
* Clears all stored "n" query parameters.
* Clears all stored {@code n} query parameters.
*/
public static void clearCache() {
N_PARAMS_CACHE.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,8 @@ public List<VideoStream> getVideoOnlyStreams() throws ExtractionException {
}

/**
* Try to decrypt a streaming URL and fallback to the given URL, because decryption may fail if
* YouTube do breaking changes.
* Try to decrypt a streaming URL and fall back to the given URL, because decryption may fail
* if YouTube changes break something.
*
* <p>
* This way a breaking change from YouTube does not result in a broken extractor.
Expand Down