33import com .grack .nanojson .JsonArray ;
44import com .grack .nanojson .JsonObject ;
55import com .grack .nanojson .JsonParser ;
6-
76import org .mozilla .javascript .Context ;
87import org .mozilla .javascript .Function ;
98import org .mozilla .javascript .ScriptableObject ;
3635import org .schabi .newpipe .extractor .utils .Parser ;
3736import org .schabi .newpipe .extractor .utils .Utils ;
3837
38+ import javax .annotation .Nonnull ;
39+ import javax .annotation .Nullable ;
3940import java .io .IOException ;
4041import java .io .UnsupportedEncodingException ;
4142import java .text .SimpleDateFormat ;
4950import java .util .Locale ;
5051import java .util .Map ;
5152
52- import javax .annotation .Nonnull ;
53- import javax .annotation .Nullable ;
54-
5553import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .fixThumbnailUrl ;
5654import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getJsonResponse ;
5755import static org .schabi .newpipe .extractor .services .youtube .YoutubeParsingHelper .getTextFromObject ;
@@ -84,8 +82,8 @@ public class YoutubeStreamExtractor extends StreamExtractor {
8482 // Exceptions
8583 //////////////////////////////////////////////////////////////////////////*/
8684
87- public class DecryptException extends ParsingException {
88- DecryptException (String message , Throwable cause ) {
85+ public class DeobfuscateException extends ParsingException {
86+ DeobfuscateException (String message , Throwable cause ) {
8987 super (message , cause );
9088 }
9189 }
@@ -156,20 +154,23 @@ public String getTextualUploadDate() throws ParsingException {
156154 TimeAgoParser timeAgoParser = TimeAgoPatternsManager .getTimeAgoParserFor (Localization .fromLocalizationCode ("en" ));
157155 Calendar parsedTime = timeAgoParser .parse (time ).date ();
158156 return new SimpleDateFormat ("yyyy-MM-dd" ).format (parsedTime .getTime ());
159- } catch (Exception ignored ) {}
157+ } catch (Exception ignored ) {
158+ }
160159
161160 try { // Premiered Feb 21, 2020
162161 Date d = new SimpleDateFormat ("MMM dd, YYYY" , Locale .ENGLISH ).parse (time );
163162 return new SimpleDateFormat ("yyyy-MM-dd" ).format (d .getTime ());
164- } catch (Exception ignored ) {}
163+ } catch (Exception ignored ) {
164+ }
165165 }
166166
167167 try {
168168 // TODO: this parses English formatted dates only, we need a better approach to parse the textual date
169169 Date d = new SimpleDateFormat ("dd MMM yyyy" , Locale .ENGLISH ).parse (
170170 getTextFromObject (getVideoPrimaryInfoRenderer ().getObject ("dateText" )));
171171 return new SimpleDateFormat ("yyyy-MM-dd" ).format (d );
172- } catch (Exception ignored ) {}
172+ } catch (Exception ignored ) {
173+ }
173174 throw new ParsingException ("Could not get upload date" );
174175 }
175176
@@ -368,7 +369,8 @@ public String getUploaderName() throws ParsingException {
368369 try {
369370 uploaderName = getTextFromObject (getVideoSecondaryInfoRenderer ().getObject ("owner" )
370371 .getObject ("videoOwnerRenderer" ).getObject ("title" ));
371- } catch (ParsingException ignored ) { }
372+ } catch (ParsingException ignored ) {
373+ }
372374
373375 if (isNullOrEmpty (uploaderName )) {
374376 uploaderName = playerResponse .getObject ("videoDetails" ).getString ("author" );
@@ -436,11 +438,11 @@ public String getDashMpdUrl() throws ParsingException {
436438 }
437439
438440 if (!dashManifestUrl .contains ("/signature/" )) {
439- String encryptedSig = Parser .matchGroup1 ("/s/([a-fA-F0-9\\ .]+)" , dashManifestUrl );
440- String decryptedSig ;
441+ String obfuscatedSig = Parser .matchGroup1 ("/s/([a-fA-F0-9\\ .]+)" , dashManifestUrl );
442+ String deobfuscatedSig ;
441443
442- decryptedSig = decryptSignature ( encryptedSig , decryptionCode );
443- dashManifestUrl = dashManifestUrl .replace ("/s/" + encryptedSig , "/signature/" + decryptedSig );
444+ deobfuscatedSig = deobfuscateSignature ( obfuscatedSig , deobfuscationCode );
445+ dashManifestUrl = dashManifestUrl .replace ("/s/" + obfuscatedSig , "/signature/" + deobfuscatedSig );
444446 }
445447
446448 return dashManifestUrl ;
@@ -630,7 +632,7 @@ public String getErrorMessage() {
630632 private static final String FORMATS = "formats" ;
631633 private static final String ADAPTIVE_FORMATS = "adaptiveFormats" ;
632634 private static final String HTTPS = "https:" ;
633- private static final String DECRYPTION_FUNC_NAME = "decrypt" ;
635+ private static final String DEOBFUSCATION_FUNC_NAME = "decrypt" ;
634636
635637 private final static String [] REGEXES = {
636638 "(?:\\ b|[^a-zA-Z0-9$])([a-zA-Z0-9$]{2})\\ s*=\\ s*function\\ (\\ s*a\\ s*\\ )\\ s*\\ {\\ s*a\\ s*=\\ s*a\\ .split\\ (\\ s*\" \" \\ s*\\ )" ,
@@ -640,7 +642,7 @@ public String getErrorMessage() {
640642 "\\ bc\\ s*&&\\ s*d\\ .set\\ ([^,]+\\ s*,\\ s*(:encodeURIComponent\\ s*\\ ()([a-zA-Z0-9$]+)\\ ("
641643 };
642644
643- private volatile String decryptionCode = "" ;
645+ private volatile String deobfuscationCode = "" ;
644646
645647 @ Override
646648 public void onFetchPage (@ Nonnull Downloader downloader ) throws IOException , ExtractionException {
@@ -695,8 +697,8 @@ public void onFetchPage(@Nonnull Downloader downloader) throws IOException, Extr
695697 throw new ContentNotAvailableException ("Got error: \" " + reason + "\" " );
696698 }
697699
698- if (decryptionCode .isEmpty ()) {
699- decryptionCode = loadDecryptionCode (playerUrl );
700+ if (deobfuscationCode .isEmpty ()) {
701+ deobfuscationCode = loadDeobfuscationCode (playerUrl );
700702 }
701703
702704 if (subtitlesInfos .isEmpty ()) {
@@ -716,7 +718,7 @@ private JsonObject getPlayerArgs(final JsonObject playerConfig) throws ParsingEx
716718 private String getPlayerUrl (final JsonObject playerConfig ) throws ParsingException {
717719 // The Youtube service needs to be initialized by downloading the
718720 // js-Youtube-player. This is done in order to get the algorithm
719- // for decrypting cryptic signatures inside certain stream URLs.
721+ // for deobfuscating cryptic signatures inside certain stream URLs.
720722 final String playerUrl = playerConfig .getObject ("assets" ).getString ("js" );
721723
722724 if (playerUrl == null ) {
@@ -768,11 +770,11 @@ private EmbeddedInfo getEmbeddedInfo() throws ParsingException, ReCaptchaExcepti
768770
769771 } catch (IOException e ) {
770772 throw new ParsingException (
771- "Could load decryption code form restricted video for the Youtube service." , e );
773+ "Could load deobfuscation code form restricted video for the Youtube service." , e );
772774 }
773775 }
774776
775- private String loadDecryptionCode (String playerUrl ) throws DecryptException {
777+ private String loadDeobfuscationCode (String playerUrl ) throws DeobfuscateException {
776778 try {
777779 Downloader downloader = NewPipe .getDownloader ();
778780 if (!playerUrl .contains ("https://youtube.com" )) {
@@ -782,49 +784,49 @@ private String loadDecryptionCode(String playerUrl) throws DecryptException {
782784 }
783785
784786 final String playerCode = downloader .get (playerUrl , getExtractorLocalization ()).responseBody ();
785- final String decryptionFunctionName = getDecryptionFuncName (playerCode );
787+ final String deobfuscationFunctionName = getDeobfuscationFuncName (playerCode );
786788
787789 final String functionPattern = "("
788- + decryptionFunctionName .replace ("$" , "\\ $" )
790+ + deobfuscationFunctionName .replace ("$" , "\\ $" )
789791 + "=function\\ ([a-zA-Z0-9_]+\\ )\\ {.+?\\ })" ;
790- final String decryptionFunction = "var " + Parser .matchGroup1 (functionPattern , playerCode ) + ";" ;
792+ final String deobfuscateFunction = "var " + Parser .matchGroup1 (functionPattern , playerCode ) + ";" ;
791793
792794 final String helperObjectName =
793- Parser .matchGroup1 (";([A-Za-z0-9_\\ $]{2})\\ ...\\ (" , decryptionFunction );
795+ Parser .matchGroup1 (";([A-Za-z0-9_\\ $]{2})\\ ...\\ (" , deobfuscateFunction );
794796 final String helperPattern =
795797 "(var " + helperObjectName .replace ("$" , "\\ $" ) + "=\\ {.+?\\ }\\ };)" ;
796798 final String helperObject =
797799 Parser .matchGroup1 (helperPattern , playerCode .replace ("\n " , "" ));
798800
799801 final String callerFunction =
800- "function " + DECRYPTION_FUNC_NAME + "(a){return " + decryptionFunctionName + "(a);}" ;
802+ "function " + DEOBFUSCATION_FUNC_NAME + "(a){return " + deobfuscationFunctionName + "(a);}" ;
801803
802- return helperObject + decryptionFunction + callerFunction ;
804+ return helperObject + deobfuscateFunction + callerFunction ;
803805 } catch (IOException ioe ) {
804- throw new DecryptException ("Could not load decrypt function" , ioe );
806+ throw new DeobfuscateException ("Could not load deobfuscate function" , ioe );
805807 } catch (Exception e ) {
806- throw new DecryptException ("Could not parse decrypt function " , e );
808+ throw new DeobfuscateException ("Could not parse deobfuscate function " , e );
807809 }
808810 }
809811
810- private String decryptSignature (String encryptedSig , String decryptionCode ) throws DecryptException {
812+ private String deobfuscateSignature (String obfuscatedSig , String deobfuscationCode ) throws DeobfuscateException {
811813 final Context context = Context .enter ();
812814 context .setOptimizationLevel (-1 );
813815 final Object result ;
814816 try {
815817 final ScriptableObject scope = context .initSafeStandardObjects ();
816- context .evaluateString (scope , decryptionCode , "decryptionCode" , 1 , null );
817- final Function decryptionFunc = (Function ) scope .get ("decrypt" , scope );
818- result = decryptionFunc .call (context , scope , scope , new Object []{encryptedSig });
818+ context .evaluateString (scope , deobfuscationCode , "decryptionCode" , 1 , null );
819+ final Function deobfuscateFunc = (Function ) scope .get ("decrypt" , scope );
820+ result = deobfuscateFunc .call (context , scope , scope , new Object []{obfuscatedSig });
819821 } catch (Exception e ) {
820- throw new DecryptException ("Could not get decrypt signature" , e );
822+ throw new DeobfuscateException ("Could not get deobfuscate signature" , e );
821823 } finally {
822824 Context .exit ();
823825 }
824826 return result == null ? "" : result .toString ();
825827 }
826828
827- private String getDecryptionFuncName (final String playerCode ) throws DecryptException {
829+ private String getDeobfuscationFuncName (final String playerCode ) throws DeobfuscateException {
828830 Parser .RegexException exception = null ;
829831 for (final String regex : REGEXES ) {
830832 try {
@@ -835,7 +837,7 @@ private String getDecryptionFuncName(final String playerCode) throws DecryptExce
835837 }
836838 }
837839 }
838- throw new DecryptException ("Could not find decrypt function with any of the given patterns." , exception );
840+ throw new DeobfuscateException ("Could not find deobfuscate function with any of the given patterns." , exception );
839841 }
840842
841843 @ Nonnull
@@ -989,18 +991,19 @@ private Map<String, ItagItem> getItags(String streamingDataKey, ItagItem.ItagTyp
989991 if (formatData .has ("url" )) {
990992 streamUrl = formatData .getString ("url" );
991993 } else {
992- // this url has an encrypted signature
994+ // this url has an obfuscated signature
993995 final String cipherString = formatData .has ("cipher" )
994996 ? formatData .getString ("cipher" )
995997 : formatData .getString ("signatureCipher" );
996998 final Map <String , String > cipher = Parser .compatParseMap (cipherString );
997999 streamUrl = cipher .get ("url" ) + "&" + cipher .get ("sp" ) + "="
998- + decryptSignature (cipher .get ("s" ), decryptionCode );
1000+ + deobfuscateSignature (cipher .get ("s" ), deobfuscationCode );
9991001 }
10001002
10011003 urlAndItags .put (streamUrl , itagItem );
10021004 }
1003- } catch (UnsupportedEncodingException ignored ) {}
1005+ } catch (UnsupportedEncodingException ignored ) {
1006+ }
10041007 }
10051008 }
10061009
0 commit comments