Merge pull request #243 from TeamNewPipe/fix/yt_decryption
Fix/yt decryption
This commit is contained in:
commit
ff61e28424
|
@ -56,7 +56,7 @@ public abstract class Extractor{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertPageFetched() {
|
protected void assertPageFetched() {
|
||||||
if(!pageFetched) throw new IllegalStateException("Page is not fetched. Make sure you call fetchPage()");
|
if (!pageFetched) throw new IllegalStateException("Page is not fetched. Make sure you call fetchPage()");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isPageFetched() {
|
protected boolean isPageFetched() {
|
||||||
|
|
|
@ -677,8 +677,10 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
private static final String VERIFIED_URL_PARAMS = "&has_verified=1&bpctr=9999999999";
|
private static final String VERIFIED_URL_PARAMS = "&has_verified=1&bpctr=9999999999";
|
||||||
|
|
||||||
private final static String DECYRYPTION_SIGNATURE_FUNCTION_REGEX =
|
private final static String DECRYPTION_SIGNATURE_FUNCTION_REGEX =
|
||||||
"([\\w$]+)\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;";
|
"([\\w$]+)\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;";
|
||||||
|
private final static String DECRYPTION_SIGNATURE_FUNCTION_REGEX_2 =
|
||||||
|
"\\b([\\w$]{2})\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;";
|
||||||
private final static String DECRYPTION_AKAMAIZED_STRING_REGEX =
|
private final static String DECRYPTION_AKAMAIZED_STRING_REGEX =
|
||||||
"yt\\.akamaized\\.net/\\)\\s*\\|\\|\\s*.*?\\s*c\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*(:encodeURIComponent\\s*\\()([a-zA-Z0-9$]+)\\(";
|
"yt\\.akamaized\\.net/\\)\\s*\\|\\|\\s*.*?\\s*c\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*(:encodeURIComponent\\s*\\()([a-zA-Z0-9$]+)\\(";
|
||||||
private final static String DECRYPTION_AKAMAIZED_SHORT_STRING_REGEX =
|
private final static String DECRYPTION_AKAMAIZED_SHORT_STRING_REGEX =
|
||||||
|
@ -697,7 +699,8 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
|
|
||||||
final String playerUrl;
|
final String playerUrl;
|
||||||
// Check if the video is age restricted
|
// Check if the video is age restricted
|
||||||
if (!doc.select("meta[property=\"og:restrictions:age\"]").isEmpty()) {
|
Elements e = doc.select("meta[property=\"og:restrictions:age\"]");
|
||||||
|
if (!e.isEmpty()) {
|
||||||
final EmbeddedInfo info = getEmbeddedInfo();
|
final EmbeddedInfo info = getEmbeddedInfo();
|
||||||
final String videoInfoUrl = getVideoInfoUrl(getId(), info.sts);
|
final String videoInfoUrl = getVideoInfoUrl(getId(), info.sts);
|
||||||
final String infoPageResponse = downloader.get(videoInfoUrl, getExtractorLocalization()).responseBody();
|
final String infoPageResponse = downloader.get(videoInfoUrl, getExtractorLocalization()).responseBody();
|
||||||
|
@ -773,7 +776,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
private JsonObject getPlayerResponse() throws ParsingException {
|
private JsonObject getPlayerResponse() throws ParsingException {
|
||||||
try {
|
try {
|
||||||
String playerResponseStr;
|
String playerResponseStr;
|
||||||
if(playerArgs != null) {
|
if (playerArgs != null) {
|
||||||
playerResponseStr = playerArgs.getString("player_response");
|
playerResponseStr = playerArgs.getString("player_response");
|
||||||
} else {
|
} else {
|
||||||
playerResponseStr = videoInfoPage.get("player_response");
|
playerResponseStr = videoInfoPage.get("player_response");
|
||||||
|
@ -805,7 +808,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
final String sts = Parser.matchGroup1(stsPattern, embedPageContent);
|
final String sts = Parser.matchGroup1(stsPattern, embedPageContent);
|
||||||
return new EmbeddedInfo(playerUrl, sts);
|
return new EmbeddedInfo(playerUrl, sts);
|
||||||
} catch (Exception i) {
|
} catch (Exception i) {
|
||||||
// if it failes we simply reply with no sts as then it does not seem to be necessary
|
// if it fails we simply reply with no sts as then it does not seem to be necessary
|
||||||
return new EmbeddedInfo(playerUrl, "");
|
return new EmbeddedInfo(playerUrl, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,30 +871,28 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDecryptionFuncName(String playerCode) throws DecryptException {
|
private String getDecryptionFuncName(String playerCode) throws DecryptException {
|
||||||
String decryptionFunctionName;
|
String[] decryptionFuncNameRegexes = {
|
||||||
// Cascading things in catch is ugly, but its faster than running a match before getting the actual name
|
DECRYPTION_SIGNATURE_FUNCTION_REGEX_2,
|
||||||
// to se if the function can actually be found with the given regex.
|
DECRYPTION_SIGNATURE_FUNCTION_REGEX,
|
||||||
// However if this cascading should propably be cleaned up somehow as it looks a bit weird.
|
DECRYPTION_AKAMAIZED_SHORT_STRING_REGEX,
|
||||||
try {
|
DECRYPTION_AKAMAIZED_STRING_REGEX
|
||||||
decryptionFunctionName = Parser.matchGroup1(DECYRYPTION_SIGNATURE_FUNCTION_REGEX, playerCode);
|
};
|
||||||
} catch (Parser.RegexException re) {
|
Parser.RegexException exception = null;
|
||||||
|
for (String regex : decryptionFuncNameRegexes) {
|
||||||
try {
|
try {
|
||||||
decryptionFunctionName = Parser.matchGroup1(DECRYPTION_AKAMAIZED_SHORT_STRING_REGEX, playerCode);
|
return Parser.matchGroup1(regex, playerCode);
|
||||||
} catch (Parser.RegexException re2) {
|
} catch (Parser.RegexException re) {
|
||||||
try {
|
if (exception == null)
|
||||||
decryptionFunctionName = Parser.matchGroup1(DECRYPTION_AKAMAIZED_STRING_REGEX, playerCode);
|
exception = re;
|
||||||
} catch (Parser.RegexException re3) {
|
|
||||||
throw new DecryptException("Could not find decrypt function with any of the given patterns.", re);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return decryptionFunctionName;
|
throw new DecryptException("Could not find decrypt function with any of the given patterns.", exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private List<SubtitlesInfo> getAvailableSubtitlesInfo() throws SubtitlesException {
|
private List<SubtitlesInfo> getAvailableSubtitlesInfo() throws SubtitlesException {
|
||||||
// If the video is age restricted getPlayerConfig will fail
|
// If the video is age restricted getPlayerConfig will fail
|
||||||
if(isAgeRestricted) return Collections.emptyList();
|
if (isAgeRestricted) return Collections.emptyList();
|
||||||
|
|
||||||
final JsonObject captions;
|
final JsonObject captions;
|
||||||
if (!playerResponse.has("captions")) {
|
if (!playerResponse.has("captions")) {
|
||||||
|
@ -908,7 +909,7 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
// This check is necessary since there may be cases where subtitles metadata do not contain caption track info
|
// This check is necessary since there may be cases where subtitles metadata do not contain caption track info
|
||||||
// e.g. https://www.youtube.com/watch?v=-Vpwatutnko
|
// e.g. https://www.youtube.com/watch?v=-Vpwatutnko
|
||||||
final int captionsSize = captionsArray.size();
|
final int captionsSize = captionsArray.size();
|
||||||
if(captionsSize == 0) return Collections.emptyList();
|
if (captionsSize == 0) return Collections.emptyList();
|
||||||
|
|
||||||
List<SubtitlesInfo> result = new ArrayList<>();
|
List<SubtitlesInfo> result = new ArrayList<>();
|
||||||
for (int i = 0; i < captionsSize; i++) {
|
for (int i = 0; i < captionsSize; i++) {
|
||||||
|
|
|
@ -67,6 +67,7 @@ public class Parser {
|
||||||
if (foundMatch) {
|
if (foundMatch) {
|
||||||
return mat.group(group);
|
return mat.group(group);
|
||||||
} else {
|
} else {
|
||||||
|
// only pass input to exception message when it is not too long
|
||||||
if (input.length() > 1024) {
|
if (input.length() > 1024) {
|
||||||
throw new RegexException("failed to find pattern \"" + pat.pattern());
|
throw new RegexException("failed to find pattern \"" + pat.pattern());
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue