def interface_file(path, TD): if TD == "pick": TD = Private.TD_picker(path) folder = path TeamDrive = TD response = False files = list() while True: filter = interface_filter(path) files = Private.search_folder(folder, TD=TeamDrive, pickmode="multi", filter=filter, Print=False) if files == False: print("Query returned no files") input('\nPress any key to continue...') clear_Screen() About() return True else: response = interface_menu(files, TeamDrive) if str(response) == "False": return response elif str(response) == "CHANGE": return True
def route_download(path,TD,ofolder,xcimode="Untrimmed",zmode="Compressed"): if (path.endswith('.xcz') or path.endswith('.nsz')) and zmode=="Uncompressed": decompress(path,ofolder,TD=TD) if path.endswith('.xci') and xcimode=="Trimmed": Private.download(path,ofolder,TD=TD,trimm=True) elif path.endswith('.xci') and xcimode=="Supertrimmed": supertrimm(path,ofolder,TD=TD) else: Private.download(path,ofolder,TD=TD,trimm=False)
def Interface(): clear_Screen() About() response = False print('\n********************************************************') print('DOWNLOAD SYSTEM') print('********************************************************') while True: print('Input "1" to select folder and file via file-picker') if os.path.exists(remote_lib_file): print('Input "2" to select from libraries') print('') print('Input "0" to go back to the MAIN PROGRAM') print('') print('--- Or INPUT GDRIVE Route OR PUBLIC_LINK ---') print('') ck = input('Input your answer: ') if ck == "0": break elif ck == "1": while True: folder, TD = Private.folder_walker() if folder == False: return False print(folder) response = interface_file(folder, TD) if response == False: return False elif ck == "2" and os.path.exists(remote_lib_file): while True: paths, TDs = pick_libraries() if paths == False: return False response = interface_file(paths, TDs) if response == False: return False elif ck == "0": break elif ck.startswith('http'): url = ck response = interface_menu(url, None, True) elif ck.endswith('/') or ck.endswith('\\'): response = interface_file(ck, "pick") elif (ck[:-1]).endswith('.xc') or (ck[:-1]).endswith('.ns'): TD = Private.TD_picker(ck) response = interface_menu(ck, TD, True) if response == False: break
def getcnmtdata(filename,remotelocation=False): filename=html.unescape(filename) print('* Reading Data from Cnmt') sys.stdout.flush() if remotelocation != False: global globalpath; global globalremote if globalpath!=filename: globalpath=filename lib,TD,libpath=get_library_from_path(remote_lib_file,filename) ID,name,type,size,md5,remote=DrivePrivate.get_Data(filename,TD=TD,Print=False) globalremote=remote feed=DriveHtmlInfo.read_cnmt(file=globalremote) eel.set_cnmt_data(feed) return else: if filename.endswith('.nsp')or filename.endswith('.nsx') or filename.endswith('.nsz'): f = Fs.ChromeNsp(filename, 'rb') elif filename.endswith('.xci') or filename.endswith('.xcz'): f = Fs.ChromeXci(filename) elif filename.endswith('.xc0') or filename.endswith('.ns0') or filename.endswith('00'): ck=file_chunk.chunk(filename) feed=ck.send_html_cnmt_data() eel.set_cnmt_data(feed) return else: eel.set_cnmt_data("") return feed=f.read_cnmt() f.flush() f.close() eel.set_cnmt_data(feed) return
def showicon_remote(filename): filename=html.unescape(filename) global globalpath; global globalremote if globalpath!=filename: if not filename.startswith('http'): globalpath=filename lib,TD,libpath=get_library_from_path(remote_lib_file,filename) ID,name,type,size,md5,remote=DrivePrivate.get_Data(filename,TD=TD,Print=False) globalremote=remote else: globalpath=filename remote=DrivePublic.location(filename);readable=remote.readable globalremote=remote if not readable: eel.setImage("") return try: a=DriveHtmlInfo.icon_info(file=globalremote) # a=DriveHtmlInfo.icon_info(path=filename,TD=TD) encoded = b64encode(a).decode("ascii") data="data:image/png;base64, " + encoded eel.setImage(data) return except: iconurl=nutdb.get_icon(remote.id) if iconurl!=False: eel.setImage(iconurl) return else: eel.setImage("") return
def getnpdmdata(filename,remotelocation=False): filename=html.unescape(filename) print('* Reading Data from Npdm') sys.stdout.flush() if remotelocation != False: global globalpath; global globalremote if globalpath!=filename: globalpath=filename lib,TD,libpath=get_library_from_path(remote_lib_file,filename) ID,name,type,size,md5,remote=DrivePrivate.get_Data(filename,TD=TD,Print=False) globalremote=remote feed=DriveHtmlInfo.read_npdm(file=globalremote) if feed=='': feed=html_feed(feed,2,message=str('No npdm in the file')) eel.set_npdm_data(feed) return else: if filename.endswith('.nsp')or filename.endswith('.nsx') or filename.endswith('.nsz'): f = Fs.ChromeNsp(filename, 'rb') files_list=sq_tools.ret_nsp_offsets(filename) elif filename.endswith('.xci') or filename.endswith('.xcz'): f = Fs.ChromeXci(filename) files_list=sq_tools.ret_xci_offsets(filename) else: eel.set_npdm_data("") return feed=f.read_npdm(files_list) f.flush() f.close() if feed=='': feed=html_feed(feed,2,message=str('No npdm in the file')) eel.set_npdm_data(feed) return
def public_gdrive_transfer(filepath,destiny="SD",truecopy=True): check_connection() lib,TD,libpath=get_cache_lib() if lib==None: sys.exit(f"Google Drive Public Links are only supported via cache folder") if destiny=="SD": destiny="1: External SD Card/" filename=addtodrive(filepath,truecopy=truecopy) ID,name,type,size,md5,remote=DrivePrivate.get_Data(filename,TD=TD,Print=False) token=remote.access_token name=remote.name sz=remote.size URL='https://www.googleapis.com/drive/v3/files/'+remote.ID+'?alt=media' ext=name.split('.') ext=ext[-1] file_size=int(sz) print("- Retrieving Space on device") SD_ds,SD_fs,NAND_ds,NAND_fs,FW,device=get_storage_info() print(f" * SD free space: {SD_fs} ({sq_tools.getSize(SD_fs)})") print(f" * File installed size: {file_size} ({sq_tools.getSize(file_size)})") if file_size>SD_fs: print(" Not enough space on SD. Changing target to EMMC") print(f" * EMMC free space: {NAND_fs} ({sq_tools.getSize(NAND_fs)})") sys.exit(" NOT ENOUGH SPACE SD STORAGE") process=subprocess.Popen([nscb_mtp,"DriveTransfer","-ori",URL,"-dst",destiny,"-name",name,"-size",sz,"-tk",token]) while process.poll()==None: if process.poll()!=None: process.terminate();
def download(filename,remotelocation=False): filename=html.unescape(filename) lib,TD,libpath=get_library_from_path(remote_lib_file,filename) ID,name,type,size,md5,remote=DrivePrivate.get_Data(filename,TD=TD,Print=False) # header=DrivePrivate.get_html_header(remote.access_token) token=remote.access_token URL='https://www.googleapis.com/drive/v3/files/'+remote.ID+'?alt=media' eel.browser_download(URL,token)
def scrape_lib_worker(db,entry,filter=''): results=[]; path=db[entry]['path'] TD=db[entry]['TD_name'] from Drive import Private as DrivePrivate response=DrivePrivate.search_folder(path,TD=TD,filter=filter,Pick=False) if response!=False: results+=response return results
def remote_select_from_walker(tfile, types='all'): from workers import concurrent_scrapper from Drive import Private as DrivePrivate ext = [] if types != 'all': items = types.split(' ') for x in items: ext.append(str(x).lower()) folder, TeamDrive = DrivePrivate.folder_walker() if TeamDrive == "" or TeamDrive == False: TeamDrive = None if folder == False: return False filt = remote_interface_filter() order = pick_order() if order == False: return False print(f"- Checking {folder}") print(" * Parsing files from Google Drive. Please Wait...") db = {} db[folder] = {'path': folder, 'TD_name': TeamDrive} files = concurrent_scrapper(filter=filt, order=order, remotelib='all', db=db) if files == False: return False print(" * Entering File Picker") title = 'Select content to install or transfer: \n + Press space or right to select content \n + Press Enter to confirm selection \n + Press E to exit selection' filenames = [] for f in files: if types == 'all': filenames.append(f[0]) else: for x in ext: if (str(f[0]).lower()).endswith(x): filenames.append(f[0]) break if filenames == []: print(" * Request didn't retrieve any files") return False options = filenames picker = Picker(options, title, multi_select=True, min_selection_count=1) def end_selection(picker): return False, -1 picker.register_custom_handler(ord('e'), end_selection) picker.register_custom_handler(ord('E'), end_selection) selected = picker.start() if selected[0] == False: print(" User didn't select any files") return False with open(tfile, 'a') as textfile: for f in selected: textfile.write((files[f[1]])[2] + '/' + (files[f[1]])[0] + '|' + str(TeamDrive) + '\n')
def install_xci_csv(filepath=None,remote=None,destiny="SD",cachefolder=None,override=False,keypatch=False): if filepath=="": filepath=None if remote=="": remote=None if remote==None: test=filepath.split('|');TD=None if len(test)<2: filepath=test[0] lib,TD,libpath=get_library_from_path(remote_lib_file,filepath) else: filepath=test[0] TD=test[1] if str(TD).upper()=="NONE": TD=None ID,name,type,size,md5,remote=DrivePrivate.get_Data(filepath,TD=TD,Print=False) check_connection() if cachefolder==None: cachefolder=os.path.join(ztools_dir, '_mtp_cache_') files_list=DriveTools.get_files_from_head(remote,remote.name) remote.rewind() print(f"Installing {remote.name} by content") print('- Parsing headers...') files=list();filesizes=list() fplist=list() counter=0 for k in range(len(files_list)): entry=files_list[k] cnmtfile=entry[0] if cnmtfile.endswith('.cnmt.nca'): counter+=1 print(f"- Detected {counter} content ids") for i in range(len(files_list)): entry=files_list[i] cnmtfile=entry[0]; if cnmtfile.endswith('.cnmt.nca'): target_cnmt=cnmtfile nspname=gen_xci_parts_spec0(remote=remote,target_cnmt=target_cnmt,cachefolder=cachefolder,keypatch=keypatch) if (remote.name).endswith('xcz'): nspname=nspname[:-1]+'z' files_csv=os.path.join(cachefolder, 'remote_files.csv') process=subprocess.Popen([nscb_mtp,"GDInstallfromCSV","-cs",files_csv,"-nm",nspname,"-dst",destiny]) while process.poll()==None: if process.poll()!=None: process.terminate(); counter-=1 print('\n- Still '+str(counter)+' subitems to process') if counter>0: print("") if os.path.exists(cachefolder): for f in os.listdir(cachefolder): fp = os.path.join(cachefolder, f) try: shutil.rmtree(fp) except OSError: os.remove(fp)
def addtodrive(filename,truecopy=True): if os.path.exists(cache_lib_file): lib,TD,libpath=get_cache_lib() if lib!=None: file_id, is_download_link=DrivePublic.parse_url(filename) if is_download_link: remote=DrivePrivate.location(route=libpath,TD_Name=TD) result=remote.drive_service.files().get(fileId=file_id, fields="name,mimeType").execute() name=result['name'] testpath=('{}/{}').format(libpath,name) remote=DrivePrivate.location(route=testpath,TD_Name=TD) if remote.name==None: name=DrivePrivate.add_to_drive(url=filename,filepath=libpath,makecopy=truecopy,TD=TD) filename=('{}/{}').format(libpath,name) ID,name,type,size,md5,remote=DrivePrivate.get_Data(filename,TD=TD,Print=False) else: filename=testpath globalremote=remote return filename
def get_cnmt_data(path=None,TD=None,filter=None,target=None,file=None): if path==None and file==None: return False if file != None: remote=file type='file' remote.rewind() elif path.startswith('http'): url=path remote=Public.location(url);readable=remote.readable if not readable: return False type='file' else: if path=='pick': account=Private.token_picker() TD=Private.TD_picker(account) return test=path.split(".+") if TD=='pick': TD=Private.TD_picker(path) if len(test)>1 or path.endswith('/') or path.endswith('\\'): type="folder" else: ID,name,type,size,md5,remote=Private.get_Data(path,TD=TD,Print=False) if type!='file': # print('Path is a folder') Private.folderpicker(path,TD=TD,filter=filter,mode='get_cnmt_data') return else: files_list=get_files_from_head(remote,remote.name) # print(files_list) for i in range(len(files_list)): if (files_list[i][0]).endswith('.cnmt.nca'): nca_name=files_list[i][0] off1=files_list[i][1] off2=files_list[i][2] sz=files_list[i][3] if target==None: break # print(nca_name) # print(target) if str(nca_name).lower()==str(target).lower(): break remote.seek(off1,off2) buf=int(sz) try: nca=Nca() nca.open(MemoryFile(remote.read(buf))) nca.rewind() cnmt=io.BytesIO(nca.return_cnmt()) titleid,titleversion,base_ID,keygeneration,rightsId,RSV,RGV,ctype,metasdkversion,exesdkversion,hasHtmlManual,Installedsize,DeltaSize,ncadata=cnmt_data(cnmt,nca,nca_name) d={} d['titleid']=titleid;d['version']=titleversion;d['baseid']=base_ID;d['keygeneration']=keygeneration;d['rightsId']=rightsId; d['rsv']=RSV;d['rgv']=RGV;d['ctype']=ctype;d['metasdkversion']=metasdkversion;d['exesdkversion']=exesdkversion; d['hasHtmlManual']=hasHtmlManual;d['Installedsize']=Installedsize;d['DeltaSize']=DeltaSize;d['ncadata']=ncadata; # print(d) return d,files_list,remote except IOError as e: print(e, file=sys.stderr)
def supertrimm(path,ofolder,TD=None,filter=None,file=None): buf=64*1024;buffer=buf if path.startswith('http'): url=path if file==None: remote=Public.location(url);readable=remote.readable else: remote=file;readable=remote.readable if not readable: return False type='file' else: if path=='pick': account=Private.token_picker() TD=Private.TD_picker(account) return test=path.split(".+") if TD=='pick': TD=Private.TD_picker(path) if len(test)>1 or path.endswith('/') or path.endswith('\\'): type="folder" else: ID,name,type,size,md5,remote=Private.get_Data(path,TD=TD,Print=False) if type!='file': # print('Path is a folder') Private.folderpicker(path,TD=TD,filter=filter,mode='supertrimm') return else: if remote.name.endswith(".xci"): supertrimm_xci(remote,ofolder) elif remote.name.endswith(".xcz"): from Drive.Decompress import decompress decompress(path,ofolder,TD)
def scrape_remote_libs(): db=libraries(remote_lib_file) if db==False: return results=[]; for entry in db: path=db[entry]['path'] TD=db[entry]['TD_name'] from Drive import Private as DrivePrivate response=DrivePrivate.search_folder(path,TD=TD,filter="",Pick=False) if response!=False: results+=response remote_lib_2html(entry,response) remote_lib_2html('all',results)
def search_remote_lib(value,library): if library=='None': html='<p style="margin-bottom: 2px;margin-top: 3px"><strong style="margin-left: 12px">You need to create a library config file first</strong></p>' eel.load_remote_results(html) return try: db=libraries(remote_lib_file) if db==False: eel.load_remote_results(False) return if not library.lower()=='all': results=[] path=db[library]['path'] TD=db[library]['TD_name'] print("* Searching library {}".format(library)) sys.stdout.flush() response=DrivePrivate.search_folder(path,TD=TD,filter=value,Pick=False) if response!=False: results+=response send_results=[] try: for entry in results: send_results.append('{}/{}'.format(entry[2],entry[0])) sr=sortbyname(send_results) except:pass html='<ul style="margin-bottom: 2px;margin-top: 3px; list-style-type: none;">' i=0 for it in sorted(sr.keys()): i+=1;type='' item=sr[it] item2=' '+it if item2.endswith('.nsp'): type='<span class="bg-darkBlue fg-white"> nsp </span>' elif item2.endswith('.xci'): type='<span class="bg-darkRed fg-white"> xci  </span>' var='remote_res_'+str(i) html+='<li style="margin-bottom: 2px;margin-top: 3px" onclick="start_from_remote_library({})"><span id="{}" style="display:none">{}</span>{}<strong>{}</strong></li>'.format(var,var,item,type,item2) html+='</ul>' else: results=[] for entry in db: path=db[entry]['path'] TD=db[entry]['TD_name'] print("* Searching library {}".format(entry)) sys.stdout.flush() response=DrivePrivate.search_folder(path,TD=TD,filter=value,Pick=False) if response!=False: results+=response send_results=[] try: for entry in results: send_results.append('{}/{}'.format(entry[2],entry[0])) sr=sortbyname(send_results) except:pass html='<ul style="margin-bottom: 2px;margin-top: 3px; list-style-type: none;">' i=0 for it in sorted(sr.keys()): i+=1;type='' item=sr[it] item2=' '+it if item2.endswith('.nsp'): type='<span class="bg-darkBlue fg-white"> nsp </span>' elif item2.endswith('.xci'): type='<span class="bg-darkRed fg-white"> xci  </span>' var='remote_res_'+str(i) html+='<li style="margin-bottom: 2px;margin-top: 3px" onclick="start_from_remote_library({})"><span id="{}" style="display:none">{}</span>{}<strong>{}</strong></li>'.format(var,var,item,type,item2) html+='</ul>' eel.load_remote_results(html) return except BaseException as e: Print.error('Exception: ' + str(e)) sys.stdout.flush()
def getinfo(filename,remotelocation=False): filename=html.unescape(filename) print('* Retrieving Game Information') sys.stdout.flush() if remotelocation == False: if filename.endswith('.nsp')or filename.endswith('.nsx') or filename.endswith('.nsz'): f = Fs.ChromeNsp(filename, 'rb') elif filename.endswith('.xci') or filename.endswith('.xcz'): f = Fs.ChromeXci(filename) elif filename.endswith('.xc0') or filename.endswith('.ns0') or filename.endswith('00'): f=file_chunk.chunk(filename) else: return [] if not filename.endswith('0'): dict=f.return_DBdict() else: dict=f.getDBdict() # print(dict) else: global globalpath; global globalremote if globalpath!=filename: globalpath=filename lib,TD,libpath=get_library_from_path(remote_lib_file,filename) ID,name,type,size,md5,remote=DrivePrivate.get_Data(filename,TD=TD,Print=False) globalremote=remote dict=DriveHtmlInfo.getDBdict(file=globalremote) if remotelocation == False: try: ModuleId,BuildID8,BuildID16=f.read_buildid() ModuleId=sq_tools.trimm_module_id(ModuleId) except: ModuleId="-";BuildID8="-";BuildID16="-"; else: try: ModuleId=dict['ModuleId'] BuildID8=dict['BuildID8'] BuildID16=dict['BuildID16'] ModuleId=sq_tools.trimm_module_id(ModuleId) except: ModuleId="-";BuildID8="-";BuildID16="-"; try: MinRSV=sq_tools.getMinRSV(dict['keygeneration'],dict['RSV']) RSV_rq_min=sq_tools.getFWRangeRSV(MinRSV) FW_rq=sq_tools.getFWRangeKG(dict['keygeneration']) except: MinRSV="-";RSV_rq_min="-";FW_rq="-" try: RGV=dict['RGV'] RS_number=int(int(RGV)/65536) except: RGV="0";RS_number="0"; send_=list() try: if str(dict['Type']).upper()=='DLC': send_.append(dict['contentname']) else: send_.append(dict['baseName']) except:send_.append('-') try: send_.append(dict['editor']) except:send_.append('-') try: send_.append(dict['id']) except:send_.append('-') try: send_.append(dict['version']) except:send_.append('-') try: send_.append(dict['Type']) except:send_.append('-') try: send_.append(dict['dispversion']) except:send_.append('-') try: send_.append(dict['metasdkversion']) except:send_.append('-') try: send_.append(dict['exesdkversion']) except:send_.append('-') try: lang=str((', '.join(dict['languages']))) send_.append(lang) except:send_.append('-') try: send_.append(dict['RSV']) except:send_.append('-') try: send_.append(str(dict['keygeneration'])+" -> " +FW_rq) except:send_.append('-') try: send_.append(dict['nsuId']) except:send_.append('-') try: genres=str((', '.join(dict['genretags']))) send_.append(genres) except:send_.append('-') try: ratags=str((', '.join(dict['ratingtags']))) send_.append(ratags) except:send_.append('-') try: send_.append(dict['worldreleasedate']) except:send_.append('-') try: send_.append(dict['numberOfPlayers']) except:send_.append('-') try: send_.append(str(dict['eshoprating'])) except:send_.append('-') try: send_.append(sq_tools.getSize(dict['InstalledSize'])) except:send_.append('-') try: send_.append(BuildID8) except:send_.append('-') try: send_.append(ModuleId) except:send_.append('-') try: send_.append(dict['key']) except:send_.append('-') try: send_.append(RSV_rq_min[1:-1]) except:send_.append('-') try: if 'regions' in dict: reg=str((', '.join(dict['regions']))) send_.append(reg) else: send_.append('-') except: send_.append('-') try: if dict["intro"] !='-' and dict["intro"] !=None and dict["intro"] !='': if str(dict['Type']).upper()!='DLC': send_.append(dict['baseName']+". "+dict["intro"]) else: send_.append(dict['contentname']+". "+dict["intro"]) else: if str(dict['Type']).upper()!='DLC': send_.append(dict['baseName']) else: send_.append(dict['contentname']) except: try: if str(dict['Type']).upper()!='DLC': try: send_.append(dict['baseName']) except:send_.append('-') else: try: send_.append(dict['contentname']) except:send_.append('-') except:send_.append('-') try: if dict["description"] !='-': send_.append(dict["description"]) else: send_.append("Not available") except:send_.append("Not available") try: if str(dict['HtmlManual']).lower()=="true": send_.append("Yes") else: send_.append("No") except:send_.append('-') try: # print(str(dict['linkedAccRequired'])) if str(dict['linkedAccRequired']).lower()=="true": send_.append("Yes") else: send_.append("No") except:send_.append('-') try: if dict["ContentNumber"] !='-': if int(dict["ContentNumber"])>1: if 'ContentString' in dict: send_.append(dict["ContentString"]) else: send_.append("Yes ({})".format(dict["ContentNumber"])) else: send_.append("No") else: send_.append("-") except:send_.append("-") if remotelocation == False: try: if filename.endswith('.nsp')or filename.endswith('.nsx') or filename.endswith('.nsz'): send_.append("Eshop") elif filename.endswith('.xci') or filename.endswith('.xcz'): send_.append("Gamecard") else: send_.append("-") except:send_.append("-") else: remotename=globalremote.name try: if remotename.endswith('.nsp')or remotename.endswith('.nsx') or remotename.endswith('.nsz'): send_.append("Eshop") elif remotename.endswith('.xci') or remotename.endswith('.xcz'): send_.append("Gamecard") else: send_.append("-") except:send_.append("-") try: send_.append(sq_tools.getSize(dict['GCSize'])) except:send_.append('-') try:#data[30] x=get_screen_gallery(dict["bannerUrl"],dict["screenshots"]) send_.append(x) except:send_.append("Not available") try:#data[31] RQversion=0 if str(dict['Type']).upper()=='DLC': if int(RGV)>0: RQversion=str(RGV)+" -> Patch ({})".format(str(RS_number)) else: RQversion=str(RGV)+" -> Application ({})".format(str(RS_number)) send_.append(RQversion) except:send_.append('-') ###NEW JSON STUFF### try:#data[32] send_.append(dict['developer']) except:send_.append('-') try:#data[33] send_.append(dict['productCode']) except:send_.append('-') try:#data[34] if str(dict['OnlinePlay']).lower()=="true": send_.append("Yes") else: send_.append("No") except:send_.append('No') try:#data[35] if str(dict['SaveDataCloud']).lower()=="true": send_.append("Yes") else: send_.append("No") except:send_.append('No') try:#data[36] playmodes=str((', '.join(dict['playmodes']))) send_.append(playmodes) except:send_.append('-') try:#data[37] if str(dict['metascore']).lower()=='false': send_.append('-') else: send_.append(dict['metascore']) except:send_.append('-') try:#data[38] if str(dict['userscore']).lower()=='false': send_.append('-') else: send_.append(dict['userscore']) except:send_.append('-') try:#data[39] FWoncard=dict['FWoncard'] FWoncard=str(FWoncard).strip("'") send_.append(FWoncard) except:send_.append('-') try:#data[40] if str(enablevideoplayback).lower() == 'true': video=dict['video'] video=ast.literal_eval(str(video)) video=video[0] send_.append(str(video)) else: send_.append('-') except:send_.append('-') try:#data[41] if str(dict['openscore']).lower()=='false': send_.append('-') else: if dict['openscore'] != dict['metascore']: send_.append(dict['openscore']) else: send_.append('-') except:send_.append('-') try: f.flush() f.close() except:pass eel.setInfo(send_) return
def decompress_xcz(remote, ofolder): buf = 64 * 1024 buffer = buf endname = remote.name[:-1] + 'i' output = os.path.join(ofolder, endname) files_list = DriveTools.get_files_from_head(remote, remote.name) remote.rewind() # print(files_list) print('Decompressing {}'.format(remote.name)) print('- Parsing headers...') files = list() filesizes = list() fplist = list() for k in range(len(files_list)): entry = files_list[k] fplist.append(entry[0]) for i in range(len(files_list)): entry = files_list[i] cnmtfile = entry[0] metadict = {} if cnmtfile.endswith('.cnmt.nca'): metadict, d1, d2 = DriveTools.get_cnmt_data(target=cnmtfile, file=remote) ncadata = metadict['ncadata'] for j in range(len(ncadata)): row = ncadata[j] # print(row) if row['NCAtype'] != 'Meta': test1 = str(row['NcaId']) + '.nca' test2 = str(row['NcaId']) + '.ncz' if test1 in fplist or test2 in fplist: # print(str(row['NcaId'])+'.nca') files.append(str(row['NcaId']) + '.nca') filesizes.append(int(row['Size'])) else: # print(str(row['NcaId'])+'.cnmt.nca') files.append(str(row['NcaId']) + '.cnmt.nca') filesizes.append(int(row['Size'])) for k in range(len(files_list)): entry = files_list[k] fp = entry[0] sz = int(entry[3]) if fp.endswith('xml'): files.append(fp) filesizes.append(sz) for k in range(len(files_list)): entry = files_list[k] fp = entry[0] sz = int(entry[3]) if fp.endswith('.tik'): files.append(fp) filesizes.append(sz) for k in range(len(files_list)): entry = files_list[k] fp = entry[0] sz = int(entry[3]) if fp.endswith('.cert'): files.append(fp) filesizes.append(sz) sec_hashlist = list() try: for target in files: sha, size, gamecard = DriveTools.file_hash(remote, target, files_list) # print(sha) if sha != False: sec_hashlist.append(sha) except BaseException as e: Print.error('Exception: ' + str(e)) # print(sec_hashlist) xci_header, game_info, sig_padding, xci_certificate, root_header, upd_header, norm_header, sec_header, rootSize, upd_multiplier, norm_multiplier, sec_multiplier = sq_tools.get_xciheader( files, filesizes, sec_hashlist) outheader = xci_header outheader += game_info outheader += sig_padding outheader += xci_certificate outheader += root_header outheader += upd_header outheader += norm_header outheader += sec_header properheadsize = len(outheader) totsize = properheadsize for s in filesizes: totsize += s # Hex.dump(outheader) # print(totsize) print(files) t = tqdm(total=totsize, unit='B', unit_scale=True, leave=False) with open(output, 'wb') as o: o.write(outheader) t.update(len(outheader)) for file in files: if file.endswith('cnmt.nca'): for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(file).lower(): nca_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] nca_size = files_list[i][3] break t.write('- Appending {}'.format(nca_name)) data = remote.read_at(off1, nca_size) with open(output, 'ab') as o: o.write(data) t.update(len(data)) elif file.endswith('.nca'): for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(file).lower(): nca_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] nca_size = files_list[i][3] t.write('- Appending {}'.format(nca_name)) o = open(output, 'ab+') remote.seek(off1, off2) for data in remote.response.iter_content(chunk_size=buf): o.write(data) t.update(len(data)) o.flush() if not data: o.close() break elif (str(files_list[i][0]).lower())[:-1] == ( str(file).lower())[:-1] and str( files_list[i][0]).endswith('ncz'): ncz_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] sz = files_list[i][3] t.write('- Calculating compressed sections for: ' + ncz_name) remote.seek(off1, off2) header = remote.read(0x4000) magic = readInt64(remote) sectionCount = readInt64(remote) sections = [] for i in range(sectionCount): sections.append(Section(remote)) t.write(' Detected {} sections'.format(str(sectionCount))) with open(output, 'rb+') as o: o.seek(0, os.SEEK_END) curr_off = o.tell() t.write('- Appending decompressed {}'.format(ncz_name)) t.write(' Writing nca header') o.write(header) t.update(len(header)) timestamp = time.time() t.write(' Writing decompressed body in plaintext') count = 0 checkstarter = 0 dctx = zstandard.ZstdDecompressor() hd = Private.get_html_header(remote.access_token, remote.position, off2) remote.get_session(hd) reader = dctx.stream_reader(remote.response.raw, read_size=buffer) c = 0 spsize = 0 for s in sections: end = s.offset + s.size if s.cryptoType == 1: #plain text t.write(' * Section {} is plaintext'.format( str(c))) t.write(' %x - %d bytes, Crypto type %d' % ((s.offset), s.size, s.cryptoType)) spsize += s.size end = s.offset + s.size i = s.offset while i < end: chunkSz = buffer if end - i > buffer else end - i chunk = reader.read(chunkSz) if not len(chunk): break o.write(chunk) t.update(len(chunk)) i += chunkSz elif s.cryptoType not in (3, 4): raise IOError('Unknown crypto type: %d' % s.cryptoType) else: t.write(' * Section {} needs decompression'. format(str(c))) t.write(' %x - %d bytes, Crypto type %d' % ((s.offset), s.size, s.cryptoType)) t.write(' Key: %s, IV: %s' % (str(hx(s.cryptoKey)), str(hx(s.cryptoCounter)))) crypto = AESCTR(s.cryptoKey, s.cryptoCounter) spsize += s.size test = int(spsize / (buffer)) i = s.offset while i < end: crypto.seek(i) chunkSz = buffer if end - i > buffer else end - i chunk = reader.read(chunkSz) if not len(chunk): break o.write(crypto.encrypt(chunk)) t.update(len(chunk)) i += chunkSz c += 1 elapsed = time.time() - timestamp minutes = elapsed / 60 seconds = elapsed % 60 speed = 0 if elapsed == 0 else (spsize / elapsed) t.write( '\n Decompressed in %02d:%02d at speed: %.1f MB/s\n' % (minutes, seconds, speed / 1000000.0)) else: for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(file).lower(): file_name = files_list[i][0] off1 = files_list[i][1] off2 = files_list[i][2] file_size = files_list[i][3] break t.write('- Appending {}'.format(file_name)) data = remote.read_at(off1, file_size) with open(output, 'ab') as o: o.write(data) t.update(len(data)) t.close()
def gen_xci_parts_spec1(filepath=None,remote=None,target_cnmt=None,cachefolder=None,keypatch=False,files_list=None): if filepath=="": filepath=None if remote=="": remote=None if remote==None: test=filepath.split('|');TD=None if len(test)<2: filepath=test[0] lib,TD,libpath=get_library_from_path(remote_lib_file,filepath) else: filepath=test[0] TD=test[1] if str(TD).upper()=="NONE": TD=None ID,name,type,size,md5,remote=DrivePrivate.get_Data(filepath,TD=TD,Print=False) if keypatch!=False: try: keypatch=int(keypatch) except: keypatch=False if cachefolder==None: cachefolder=os.path.join(ztools_dir, '_mtp_cache_') if not os.path.exists(cachefolder): os.makedirs(cachefolder) else: for f in os.listdir(cachefolder): fp = os.path.join(cachefolder, f) try: shutil.rmtree(fp) except OSError: os.remove(fp) if files_list==None: files_list=DriveTools.get_files_from_head(remote,remote.name) files=list();filesizes=list() fplist=list() for k in range(len(files_list)): entry=files_list[k] fplist.append(entry[0]) if target_cnmt==None: for i in range(len(files_list)): entry=files_list[i] cnmtfile=entry[0] if cnmtfile.endswith('.cnmt.nca'): target_cnmt=cnmtfile break for i in range(len(files_list)): entry=files_list[i] cnmtfile=entry[0] if cnmtfile.endswith('.cnmt.nca') and target_cnmt==cnmtfile: metadict,d1,d2=DriveTools.get_cnmt_data(target=cnmtfile,file=remote) ncadata=metadict['ncadata'] for j in range(len(ncadata)): row=ncadata[j] if row['NCAtype']!='Meta' and row['NCAtype']!='Program': test1=str(row['NcaId'])+'.nca';test2=str(row['NcaId'])+'.ncz' if test1 in fplist: files.append(str(row['NcaId'])+'.nca') filesizes.append(int(row['Size'])) elif test2 in fplist: files.append(str(row['NcaId'])+'.ncz') for k in range(len(files_list)): entry=files_list[k] if entry[0]==test2: filesizes.append(int(entry[3])) break for j in range(len(ncadata)): row=ncadata[j] if row['NCAtype']=='Meta': # print(str(row['NcaId'])+'.cnmt.nca') files.append(str(row['NcaId'])+'.cnmt.nca') filesizes.append(int(row['Size'])) for j in range(len(ncadata)): row=ncadata[j] # print(row) if row['NCAtype']=='Program': test1=str(row['NcaId'])+'.nca';test2=str(row['NcaId'])+'.ncz' if test1 in fplist: files.append(str(row['NcaId'])+'.nca') filesizes.append(int(row['Size'])) elif test2 in fplist: files.append(str(row['NcaId'])+'.ncz') for k in range(len(files_list)): entry=files_list[k] if entry[0]==test2: filesizes.append(int(entry[3])) break break remote.rewind() outheader = sq_tools.gen_nsp_header(files,filesizes) properheadsize=len(outheader) # print(properheadsize) # print(bucketsize) i=0;sum=properheadsize; outfile=os.path.join(cachefolder, "0") outf = open(outfile, 'w+b') outf.write(outheader) written=0 for fi in files: if fi.endswith('nca') or fi.endswith('ncz') : for i in range(len(files_list)): if str(files_list[i][0]).lower() == str(fi).lower(): nca_name=files_list[i][0] off1=files_list[i][1] off2=files_list[i][2] nca_size=files_list[i][3] break data=remote.read_at(off1,nca_size) ncaHeader = NcaHeader() ncaHeader.open(MemoryFile(remote.read_at(off1,0x400), FsType.Crypto.XTS, uhx(Keys.get('header_key')))) crypto1=ncaHeader.getCryptoType() crypto2=ncaHeader.getCryptoType2() if crypto2>crypto1: masterKeyRev=crypto2 if crypto2<=crypto1: masterKeyRev=crypto1 crypto = aes128.AESECB(Keys.keyAreaKey(Keys.getMasterKeyIndex(masterKeyRev), ncaHeader.keyIndex)) hcrypto = aes128.AESXTS(uhx(Keys.get('header_key'))) gc_flag='00'*0x01 crypto1=ncaHeader.getCryptoType() crypto2=ncaHeader.getCryptoType2() if ncaHeader.getRightsId() != 0: ncaHeader.rewind() if crypto2>crypto1: masterKeyRev=crypto2 if crypto2<=crypto1: masterKeyRev=crypto1 titleKeyDec = Keys.decryptTitleKey(titleKey, Keys.getMasterKeyIndex(int(masterKeyRev))) encKeyBlock = crypto.encrypt(titleKeyDec * 4) if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < ncaHeader.getCryptoType2(): encKeyBlock,crypto1,crypto2=get_new_cryptoblock(ncaHeader,keypatch,encKeyBlock,t) t.close() if ncaHeader.getRightsId() == 0: ncaHeader.rewind() encKeyBlock = ncaHeader.getKeyBlock() if str(keypatch) != "False": t = tqdm(total=False, unit='B', unit_scale=False, leave=False) if keypatch < ncaHeader.getCryptoType2(): encKeyBlock,crypto1,crypto2=get_new_cryptoblock(ncaHeader,keypatch,encKeyBlock,t) t.close() ncaHeader.rewind() i=0 newheader=get_newheader(MemoryFile(remote.read_at(off1,0xC00)),encKeyBlock,crypto1,crypto2,hcrypto,gc_flag) outf.write(newheader) written+=len(newheader) break else:pass outf.flush() outf.close() tfile=os.path.join(cachefolder, "remote_files.csv") with open(tfile,'w') as csvfile: csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format("step","filepath","size","targetsize","off1","off2","token")) csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format(0,outfile,properheadsize+written,properheadsize,0,properheadsize,"False")) k=0;l=0 for fi in files: for j in files_list: if j[0]==fi: csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format(k+1,outfile,properheadsize+written,0xC00,(properheadsize+l*0xC00),(properheadsize+(l*0xC00)+0xC00),"False")) off1=j[1]+0xC00 off2=j[2] targetsize=j[3]-0xC00 URL='https://www.googleapis.com/drive/v3/files/'+remote.ID+'?alt=media' token=remote.access_token csvfile.write("{}|{}|{}|{}|{}|{}|{}\n".format(k+2,URL,remote.size,targetsize,off1,off2,token)) break k+=2;l+=1 nspname="test.nsp" try: g=remote.name g0=[pos for pos, char in enumerate(g) if char == '['] g0=(g[0:g0[0]]).strip() titleid=metadict['titleid'] titleversion=metadict['version'] ctype=metadict['ctype'] nspname=f"{g0} [{titleid}] [v{titleversion}] [{ctype}].nsp" except:pass return nspname
def public_gdrive_install(filepath,destiny="SD",truecopy=True,outfolder=None,ch_medium=True,check_fw=True,patch_keygen=False,ch_base=False,ch_other=False,installed_list=False): check_connection() lib,TD,libpath=get_cache_lib() if lib==None: sys.exit(f"Google Drive Public Links are only supported via cache folder") filename=addtodrive(filepath,truecopy=truecopy) ID,name,type,size,md5,remote=DrivePrivate.get_Data(filename,TD=TD,Print=False) token=remote.access_token name=remote.name sz=remote.size URL='https://www.googleapis.com/drive/v3/files/'+remote.ID+'?alt=media' ext=name.split('.') ext=ext[-1] if not name.endswith('nsp') and not name.endswith('nsz') and not name.endswith('xci') and not name.endswith('xcz'): print(f"Extension not supported for direct instalation {ext} in {name}") return False print("- Retrieving Space on device") SD_ds,SD_fs,NAND_ds,NAND_fs,FW,device=get_storage_info() print("- Calculating Installed size") filesize=int(sz) if destiny=="SD": print(f" * SD free space: {SD_fs} ({sq_tools.getSize(SD_fs)})") print(f" * File size: {filesize} ({sq_tools.getSize(filesize)})") if filesize>SD_fs: if filesize<NAND_fs and ch_medium==True: print(" Not enough space on SD. Changing target to EMMC") print(f" * EMMC free space: {NAND_fs} ({sq_tools.getSize(NAND_fs)})") destiny="NAND" elif ch_medium==False: sys.exit(" NOT ENOUGH SPACE SD STORAGE") else: sys.exit(" NOT ENOUGH SPACE ON DEVICE") else: print(f" * EMMC free space: {NAND_fs} ({sq_tools.getSize(NAND_fs)})") print(f" * File size: {filesize} ({sq_tools.getSize(filesize)})") if filesize>NAND_fs: if filesize<SD_fs and ch_medium==True: print(" Not enough space on EMMC. Changing target to SD") print(f" * SD free space: {SD_fs} ({sq_tools.getSize(SD_fs)})") destiny="SD" elif ch_medium==False: sys.exit(" NOT ENOUGH SPACE EMMC STORAGE") else: sys.exit(" NOT ENOUGH SPACE ON DEVICE") kgwarning=False if check_fw==True: try: cnmtdata,files_list,remote=DriveTools.get_cnmt_data(file=remote) keygeneration=int(cnmtdata['keygeneration']) if FW!='unknown': try: FW_RSV,RRSV=sq_tools.transform_fw_string(FW) FW_kg=sq_tools.kg_by_RSV(FW_RSV) except BaseException as e: Print.error('Exception: ' + str(e)) FW='unknown' FW_kg='unknown' pass if FW!='unknown' and FW_kg!='unknown': if int(keygeneration)>int(FW_kg): kgwarning=True tgkg=int(FW_kg) else: tgkg=keygeneration else: tgkg=keygeneration print(f"- Console Firmware: {FW} ({FW_RSV}) - keygen {FW_kg})") print(f"- File keygeneration: {keygeneration}") if kgwarning==True: print("File requires a higher firmware. Skipping...") return False except: print("Error getting cnmtdata from file") if installed_list!=False: try: fileid,fileversion,cctag,nG,nU,nD,baseid=listmanager.parsetags(name) fileversion=int(fileversion) if fileid.endswith('000') and fileversion==0 and fileid in installed_list.keys() and ch_base==True: print("Base game already installed. Skipping...") return False elif fileid.endswith('000') and fileid in installed_list.keys() and ch_other==True: updid=fileid[:-3]+'800' if fileversion>((installed_list[fileid])[2]): print("Asking DBI to delete previous content") process=subprocess.Popen([nscb_mtp,"DeleteID","-ID",fileid]) while process.poll()==None: if process.poll()!=None: process.terminate(); process=subprocess.Popen([nscb_mtp,"DeleteID","-ID",updid]) while process.poll()==None: if process.poll()!=None: process.terminate(); else: print("The update is a previous version than the installed on device.Skipping..") listmanager.striplines(tfile,counter=True) return False elif ch_other==True and fileid in installed_list.keys(): if fileversion>((installed_list[fileid])[2]): print("Asking DBI to delete previous update") process=subprocess.Popen([nscb_mtp,"DeleteID","-ID",fileid]) while process.poll()==None: if process.poll()!=None: process.terminate(); else: print("The update is a previous version than the installed on device.Skipping..") listmanager.striplines(tfile,counter=True) return False except:pass if name.endswith('xci') or name.endswith('xcz'): from mtpxci_remote import install_xci_csv install_xci_csv(remote=remote,destiny=destiny,cachefolder=outfolder) else: process=subprocess.Popen([nscb_mtp,"DriveInstall","-ori",URL,"-dst",destiny,"-name",name,"-size",sz,"-tk",token]) while process.poll()==None: if process.poll()!=None: process.terminate();