2323
2424static struct shared_ptr apInf ;
2525static uint8_t leaseMgr [16 ];
26+ static struct shared_ptr reqCtx ;
2627struct gengetopt_args_info args_info ;
2728char * amUsername , * amPassword ;
2829struct shared_ptr GUID ;
2930int decryptCount = 1000 ;
31+ int offlineFlag ;
3032char * device_infos [9 ];
3133
3234// Account info cache
@@ -595,6 +597,37 @@ inline static int new_socket() {
595597}
596598
597599
600+ const char * get_m3u8_method_download (struct shared_ptr reqCtx , unsigned long adam ) {
601+ void * purchase_request = malloc (1024 );
602+ _ZN17storeservicescore15PurchaseRequestC2ERKNSt6__ndk110shared_ptrINS_14RequestContextEEE (purchase_request , & reqCtx );
603+ _ZN17storeservicescore15PurchaseRequest23setProcessDialogActionsEb (purchase_request , 1 );
604+ union std_string urlBagKey = new_std_string ("subDownload" );
605+ _ZN17storeservicescore15PurchaseRequest12setURLBagKeyERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE (purchase_request , & urlBagKey );
606+ char * buyParametersStr = malloc (128 );
607+ sprintf (buyParametersStr , "salableAdamId=%lu&price=0&pricingParameters=SUBS&productType=S" , adam );
608+ union std_string buyParameters = new_std_string (buyParametersStr );
609+ _ZN17storeservicescore15PurchaseRequest16setBuyParametersERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE (purchase_request , & buyParameters );
610+ _ZN17storeservicescore15PurchaseRequest3runEv (purchase_request );
611+ struct shared_ptr * response = _ZNK17storeservicescore15PurchaseRequest8responseEv (purchase_request );
612+ struct shared_ptr * error = _ZN17storeservicescore16PurchaseResponse5errorEv (response -> obj );;
613+ if (error -> obj == NULL ) {
614+ struct std_vector items = _ZNK17storeservicescore16PurchaseResponse5itemsEv (response -> obj );
615+ struct shared_ptr * firstItem = items .begin ;
616+ struct std_vector assets = _ZNK17storeservicescore12PurchaseItem6assetsEv (firstItem -> obj );
617+ struct shared_ptr * lastAsset = (struct shared_ptr * )assets .end - 1 ;
618+ union std_string * url_str = malloc (sizeof (union std_string ));
619+ _ZNK17storeservicescore13PurchaseAsset3URLEv (url_str , lastAsset -> obj );
620+ const char * url = std_string_data (url_str );
621+ if (url ) {
622+ char * result = strdup (url ); // Make a copy
623+ free (url_str );
624+ return result ;
625+ }
626+ }
627+ return NULL ;
628+ }
629+
630+
598631const char * get_m3u8_method_play (uint8_t leaseMgr [16 ], unsigned long adam ) {
599632 union std_string HLS = new_std_string_short_mode ("HLS" );
600633 struct std_vector HLSParam = new_std_vector (& HLS );
@@ -656,7 +689,12 @@ void handle_m3u8(const int connfd) {
656689 }
657690 char * ptr ;
658691 unsigned long adamID = strtoul (adam , & ptr , 10 );
659- const char * m3u8 = get_m3u8_method_play (leaseMgr , adamID );
692+ const char * m3u8 ;
693+ if (offlineFlag ) {
694+ m3u8 = get_m3u8_method_download (reqCtx , adamID );
695+ } else {
696+ m3u8 = get_m3u8_method_play (leaseMgr , adamID );
697+ }
660698 if (m3u8 == NULL ) {
661699 fprintf (stderr , "[.] failed to get m3u8 of adamId: %ld\n" , adamID );
662700 writefull (connfd , "\n" , sizeof ("\n" ));
@@ -974,6 +1012,19 @@ void write_music_token(void) {
9741012 fclose (fp );
9751013}
9761014
1015+ int offline_available () {
1016+ struct shared_ptr * fairplay = malloc (16 );
1017+ _ZN17storeservicescore14RequestContext8fairPlayEv (fairplay , reqCtx .obj );
1018+ struct std_vector fairplay_status = _ZN17storeservicescore8FairPlay21getSubscriptionStatusEv (fairplay -> obj );
1019+ char * begin_ptr = (char * )fairplay_status .begin ;
1020+ char * second_item_ptr = begin_ptr + 16 ;
1021+ int state = * (int * )((char * )second_item_ptr + 8 );
1022+ if (state == 2 || state == 3 ) { // kFPSubscriptionCanPlayContent, kFPSubscriptionCanStreamAndPlayContent
1023+ return 1 ;
1024+ }
1025+ return 0 ;
1026+ }
1027+
9771028int main (int argc , char * argv []) {
9781029 cmdline_parser (argc , argv , & args_info );
9791030 char * copy_that_needs_to_be_freed = NULL ;
@@ -988,12 +1039,12 @@ int main(int argc, char *argv[]) {
9881039 #endif
9891040
9901041 init ();
991- const struct shared_ptr ctx = init_ctx ();
1042+ reqCtx = init_ctx ();
9921043 if (args_info .login_given ) {
9931044 amUsername = strtok (args_info .login_arg , ":" );
9941045 amPassword = strtok (NULL , ":" );
9951046 }
996- if (args_info .login_given && !login (ctx )) {
1047+ if (args_info .login_given && !login (reqCtx )) {
9971048 fprintf (stderr , "[!] login failed\n" );
9981049 return EXIT_FAILURE ;
9991050 }
@@ -1004,10 +1055,15 @@ int main(int argc, char *argv[]) {
10041055 _ZN22SVPlaybackLeaseManager12requestLeaseERKb (leaseMgr , & autom );
10051056 FHinstance = _ZN21SVFootHillSessionCtrl8instanceEv ();
10061057
1058+ offlineFlag = offline_available ();
1059+ if (offlineFlag ) {
1060+ printf ("[+] This account supports offline channel\n" );
1061+ }
1062+
10071063 // Cache account info
1008- g_storefront_id = get_account_storefront_id (ctx );
1009- g_dev_token = get_dev_token (ctx );
1010- g_music_token = get_music_user_token (get_guid (), g_dev_token , ctx );
1064+ g_storefront_id = get_account_storefront_id (reqCtx );
1065+ g_dev_token = get_dev_token (reqCtx );
1066+ g_music_token = get_music_user_token (get_guid (), g_dev_token , reqCtx );
10111067 fprintf (stderr , "[+] account info cached successfully\n" );
10121068
10131069 write_storefront_id ();
0 commit comments