Skip to content

Commit 527945e

Browse files
authored
Merge pull request #406 from Stypox/fix-decrypt
[YouTube] Fix some decryption exceptions by retrying
2 parents acb04eb + 19e8626 commit 527945e

1 file changed

Lines changed: 37 additions & 28 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -633,11 +633,10 @@ public String getErrorMessage() {
633633
@Override
634634
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
635635
final String url = getUrl() + "&pbj=1";
636+
final String playerUrl;
636637

637638
initialAjaxJson = getJsonResponse(url, getExtractorLocalization());
638639

639-
final String playerUrl;
640-
641640
if (initialAjaxJson.getObject(2).has("response")) { // age-restricted videos
642641
initialData = initialAjaxJson.getObject(2).getObject("response");
643642
ageLimit = 18;
@@ -647,12 +646,31 @@ public void onFetchPage(@Nonnull Downloader downloader) throws IOException, Extr
647646
final String infoPageResponse = downloader.get(videoInfoUrl, getExtractorLocalization()).responseBody();
648647
videoInfoPage.putAll(Parser.compatParseMap(infoPageResponse));
649648
playerUrl = info.url;
649+
650650
} else {
651-
initialData = initialAjaxJson.getObject(3).getObject("response");
652651
ageLimit = NO_AGE_LIMIT;
652+
JsonObject playerConfig;
653+
654+
// sometimes at random YouTube does not provide the player config,
655+
// so just retry the same request three times
656+
int attempts = 2;
657+
while (true) {
658+
playerConfig = initialAjaxJson.getObject(2).getObject("player", null);
659+
if (playerConfig != null) {
660+
break;
661+
}
662+
663+
if (attempts <= 0) {
664+
throw new ParsingException(
665+
"YouTube did not provide player config even after three attempts");
666+
}
667+
initialAjaxJson = getJsonResponse(url, getExtractorLocalization());
668+
--attempts;
669+
}
670+
initialData = initialAjaxJson.getObject(3).getObject("response");
653671

654-
playerArgs = getPlayerArgs(initialAjaxJson.getObject(2).getObject("player"));
655-
playerUrl = getPlayerUrl(initialAjaxJson.getObject(2).getObject("player"));
672+
playerArgs = getPlayerArgs(playerConfig);
673+
playerUrl = getPlayerUrl(playerConfig);
656674
}
657675

658676
playerResponse = getPlayerResponse();
@@ -674,36 +692,27 @@ public void onFetchPage(@Nonnull Downloader downloader) throws IOException, Extr
674692
}
675693
}
676694

677-
private JsonObject getPlayerArgs(JsonObject playerConfig) throws ParsingException {
678-
JsonObject playerArgs;
679-
695+
private JsonObject getPlayerArgs(final JsonObject playerConfig) throws ParsingException {
680696
//attempt to load the youtube js player JSON arguments
681-
try {
682-
playerArgs = playerConfig.getObject("args");
683-
} catch (Exception e) {
684-
throw new ParsingException("Could not parse yt player config", e);
697+
final JsonObject playerArgs = playerConfig.getObject("args", null);
698+
if (playerArgs == null) {
699+
throw new ParsingException("Could not extract args from YouTube player config");
685700
}
686-
687701
return playerArgs;
688702
}
689703

690-
private String getPlayerUrl(JsonObject playerConfig) throws ParsingException {
691-
try {
692-
// The Youtube service needs to be initialized by downloading the
693-
// js-Youtube-player. This is done in order to get the algorithm
694-
// for decrypting cryptic signatures inside certain stream urls.
695-
String playerUrl;
696-
697-
JsonObject ytAssets = playerConfig.getObject("assets");
698-
playerUrl = ytAssets.getString("js");
704+
private String getPlayerUrl(final JsonObject playerConfig) throws ParsingException {
705+
// The Youtube service needs to be initialized by downloading the
706+
// js-Youtube-player. This is done in order to get the algorithm
707+
// for decrypting cryptic signatures inside certain stream URLs.
708+
final String playerUrl = playerConfig.getObject("assets").getString("js");
699709

700-
if (playerUrl.startsWith("//")) {
701-
playerUrl = HTTPS + playerUrl;
702-
}
703-
return playerUrl;
704-
} catch (Exception e) {
705-
throw new ParsingException("Could not load decryption code for the Youtube service.", e);
710+
if (playerUrl == null) {
711+
throw new ParsingException("Could not extract js URL from YouTube player config");
712+
} else if (playerUrl.startsWith("//")) {
713+
return HTTPS + playerUrl;
706714
}
715+
return playerUrl;
707716
}
708717

709718
private JsonObject getPlayerResponse() throws ParsingException {

0 commit comments

Comments
 (0)