Merge pull request #406 from Stypox/fix-decrypt
[YouTube] Fix some decryption exceptions by retrying
This commit is contained in:
commit
527945eadb
|
@ -633,11 +633,10 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
@Override
|
@Override
|
||||||
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
|
||||||
final String url = getUrl() + "&pbj=1";
|
final String url = getUrl() + "&pbj=1";
|
||||||
|
final String playerUrl;
|
||||||
|
|
||||||
initialAjaxJson = getJsonResponse(url, getExtractorLocalization());
|
initialAjaxJson = getJsonResponse(url, getExtractorLocalization());
|
||||||
|
|
||||||
final String playerUrl;
|
|
||||||
|
|
||||||
if (initialAjaxJson.getObject(2).has("response")) { // age-restricted videos
|
if (initialAjaxJson.getObject(2).has("response")) { // age-restricted videos
|
||||||
initialData = initialAjaxJson.getObject(2).getObject("response");
|
initialData = initialAjaxJson.getObject(2).getObject("response");
|
||||||
ageLimit = 18;
|
ageLimit = 18;
|
||||||
|
@ -647,12 +646,31 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
final String infoPageResponse = downloader.get(videoInfoUrl, getExtractorLocalization()).responseBody();
|
final String infoPageResponse = downloader.get(videoInfoUrl, getExtractorLocalization()).responseBody();
|
||||||
videoInfoPage.putAll(Parser.compatParseMap(infoPageResponse));
|
videoInfoPage.putAll(Parser.compatParseMap(infoPageResponse));
|
||||||
playerUrl = info.url;
|
playerUrl = info.url;
|
||||||
} else {
|
|
||||||
initialData = initialAjaxJson.getObject(3).getObject("response");
|
|
||||||
ageLimit = NO_AGE_LIMIT;
|
|
||||||
|
|
||||||
playerArgs = getPlayerArgs(initialAjaxJson.getObject(2).getObject("player"));
|
} else {
|
||||||
playerUrl = getPlayerUrl(initialAjaxJson.getObject(2).getObject("player"));
|
ageLimit = NO_AGE_LIMIT;
|
||||||
|
JsonObject playerConfig;
|
||||||
|
|
||||||
|
// sometimes at random YouTube does not provide the player config,
|
||||||
|
// so just retry the same request three times
|
||||||
|
int attempts = 2;
|
||||||
|
while (true) {
|
||||||
|
playerConfig = initialAjaxJson.getObject(2).getObject("player", null);
|
||||||
|
if (playerConfig != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempts <= 0) {
|
||||||
|
throw new ParsingException(
|
||||||
|
"YouTube did not provide player config even after three attempts");
|
||||||
|
}
|
||||||
|
initialAjaxJson = getJsonResponse(url, getExtractorLocalization());
|
||||||
|
--attempts;
|
||||||
|
}
|
||||||
|
initialData = initialAjaxJson.getObject(3).getObject("response");
|
||||||
|
|
||||||
|
playerArgs = getPlayerArgs(playerConfig);
|
||||||
|
playerUrl = getPlayerUrl(playerConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
playerResponse = getPlayerResponse();
|
playerResponse = getPlayerResponse();
|
||||||
|
@ -674,36 +692,27 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonObject getPlayerArgs(JsonObject playerConfig) throws ParsingException {
|
private JsonObject getPlayerArgs(final JsonObject playerConfig) throws ParsingException {
|
||||||
JsonObject playerArgs;
|
|
||||||
|
|
||||||
//attempt to load the youtube js player JSON arguments
|
//attempt to load the youtube js player JSON arguments
|
||||||
try {
|
final JsonObject playerArgs = playerConfig.getObject("args", null);
|
||||||
playerArgs = playerConfig.getObject("args");
|
if (playerArgs == null) {
|
||||||
} catch (Exception e) {
|
throw new ParsingException("Could not extract args from YouTube player config");
|
||||||
throw new ParsingException("Could not parse yt player config", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return playerArgs;
|
return playerArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPlayerUrl(JsonObject playerConfig) throws ParsingException {
|
private String getPlayerUrl(final JsonObject playerConfig) throws ParsingException {
|
||||||
try {
|
// The Youtube service needs to be initialized by downloading the
|
||||||
// The Youtube service needs to be initialized by downloading the
|
// js-Youtube-player. This is done in order to get the algorithm
|
||||||
// js-Youtube-player. This is done in order to get the algorithm
|
// for decrypting cryptic signatures inside certain stream URLs.
|
||||||
// for decrypting cryptic signatures inside certain stream urls.
|
final String playerUrl = playerConfig.getObject("assets").getString("js");
|
||||||
String playerUrl;
|
|
||||||
|
|
||||||
JsonObject ytAssets = playerConfig.getObject("assets");
|
if (playerUrl == null) {
|
||||||
playerUrl = ytAssets.getString("js");
|
throw new ParsingException("Could not extract js URL from YouTube player config");
|
||||||
|
} else if (playerUrl.startsWith("//")) {
|
||||||
if (playerUrl.startsWith("//")) {
|
return HTTPS + playerUrl;
|
||||||
playerUrl = HTTPS + playerUrl;
|
|
||||||
}
|
|
||||||
return playerUrl;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ParsingException("Could not load decryption code for the Youtube service.", e);
|
|
||||||
}
|
}
|
||||||
|
return playerUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonObject getPlayerResponse() throws ParsingException {
|
private JsonObject getPlayerResponse() throws ParsingException {
|
||||||
|
|
Loading…
Reference in New Issue