@@ -543,8 +543,6 @@ public String getErrorMessage() {
543543 private static final String HTTPS = "https:" ;
544544 private static final String CONTENT = "content" ;
545545 private static final String DECRYPTION_FUNC_NAME = "decrypt" ;
546- private static final String GET_VIDEO_INFO_URL = "https://www.youtube.com/get_video_info?video_id=" + "%s" +
547- "&el=info&ps=default&eurl=&gl=US&hl=en" ;
548546
549547 private volatile String decryptionCode = "" ;
550548
@@ -559,19 +557,21 @@ private String getPageHtml(Downloader downloader) throws IOException, Extraction
559557
560558 @ Override
561559 public void onFetchPage (@ Nonnull Downloader downloader ) throws IOException , ExtractionException {
562- String pageContent = getPageHtml (downloader );
560+ final String pageContent = getPageHtml (downloader );
563561 doc = Jsoup .parse (pageContent , getCleanUrl ());
564562
565-
566- String playerUrl ;
563+ final String playerUrl ;
564+ // TODO: use embedded videos to fetch DASH manifest for all videos
567565 // Check if the video is age restricted
568566 if (pageContent .contains ("<meta property=\" og:restrictions:age" )) {
569- String infoPageResponse = downloader .download (String .format (GET_VIDEO_INFO_URL , getId ()));
567+ final EmbeddedInfo info = getEmbeddedInfo ();
568+ final String videoInfoUrl = getVideoInfoUrl (getId (), info .sts );
569+ final String infoPageResponse = downloader .download (videoInfoUrl );
570570 videoInfoPage .putAll (Parser .compatParseMap (infoPageResponse ));
571- playerUrl = getPlayerUrlFromRestrictedVideo () ;
571+ playerUrl = info . url ;
572572 isAgeRestricted = true ;
573573 } else {
574- JsonObject ytPlayerConfig = getPlayerConfig (pageContent );
574+ final JsonObject ytPlayerConfig = getPlayerConfig (pageContent );
575575 playerArgs = getPlayerArgs (ytPlayerConfig );
576576 playerUrl = getPlayerUrl (ytPlayerConfig );
577577 isAgeRestricted = false ;
@@ -643,24 +643,26 @@ private String getPlayerUrl(JsonObject playerConfig) throws ParsingException {
643643 }
644644 }
645645
646- private String getPlayerUrlFromRestrictedVideo () throws ParsingException , ReCaptchaException {
646+ @ Nonnull
647+ private EmbeddedInfo getEmbeddedInfo () throws ParsingException , ReCaptchaException {
647648 try {
648- Downloader downloader = NewPipe .getDownloader ();
649- String playerUrl = "" ;
650- String embedUrl = "https://www.youtube.com/embed/" + getId ();
651- String embedPageContent = downloader .download (embedUrl );
652- //todo: find out if this can be reapaced by Parser.matchGroup1()
653- Pattern assetsPattern = Pattern .compile ("\" assets\" :.+?\" js\" :\\ s*(\" [^\" ]+\" )" );
654- Matcher patternMatcher = assetsPattern .matcher (embedPageContent );
655- while (patternMatcher .find ()) {
656- playerUrl = patternMatcher .group (1 );
657- }
658- playerUrl = playerUrl .replace ("\\ " , "" ).replace ("\" " , "" );
659-
649+ final Downloader downloader = NewPipe .getDownloader ();
650+ final String embedUrl = "https://www.youtube.com/embed/" + getId ();
651+ final String embedPageContent = downloader .download (embedUrl );
652+
653+ // Get player url
654+ final String assetsPattern = "\" assets\" :.+?\" js\" :\\ s*(\" [^\" ]+\" )" ;
655+ String playerUrl = Parser .matchGroup1 (assetsPattern , embedPageContent )
656+ .replace ("\\ " , "" ).replace ("\" " , "" );
660657 if (playerUrl .startsWith ("//" )) {
661658 playerUrl = HTTPS + playerUrl ;
662659 }
663- return playerUrl ;
660+
661+ // Get embed sts
662+ final String stsPattern = "\" sts\" \\ s*:\\ s*(\\ d+)" ;
663+ final String sts = Parser .matchGroup1 (stsPattern , embedPageContent );
664+
665+ return new EmbeddedInfo (playerUrl , sts );
664666 } catch (IOException e ) {
665667 throw new ParsingException (
666668 "Could load decryption code form restricted video for the Youtube service." , e );
@@ -730,10 +732,31 @@ private String decryptSignature(String encryptedSig, String decryptionCode) thro
730732 return result == null ? "" : result .toString ();
731733 }
732734
735+ /*//////////////////////////////////////////////////////////////////////////
736+ // Data Class
737+ //////////////////////////////////////////////////////////////////////////*/
738+
739+ private class EmbeddedInfo {
740+ final String url ;
741+ final String sts ;
742+
743+ EmbeddedInfo (final String url , final String sts ) {
744+ this .url = url ;
745+ this .sts = sts ;
746+ }
747+ }
748+
733749 /*//////////////////////////////////////////////////////////////////////////
734750 // Utils
735751 //////////////////////////////////////////////////////////////////////////*/
736752
753+ @ Nonnull
754+ private String getVideoInfoUrl (final String id , final String sts ) {
755+ return "https://www.youtube.com/get_video_info?" + "video_id=" + id +
756+ "&eurl=https://youtube.googleapis.com/v/" + id +
757+ "&sts=" + sts + "&ps=default&gl=US&hl=en" ;
758+ }
759+
737760 private Map <String , ItagItem > getItags (String encodedUrlMapKey , ItagItem .ItagType itagTypeWanted ) throws ParsingException {
738761 Map <String , ItagItem > urlAndItags = new LinkedHashMap <>();
739762
0 commit comments