@@ -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