def c_uninstall(self, args): if args: addons = args.split(',') with tqdm(total=len(addons), bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar: for addon in addons: name, version = self.core.del_addon(addon) if name: self.table_data.append([ f'{Fore.LIGHTRED_EX}Uninstalled{Fore.RESET}', name, version ]) else: self.table_data.append([ f'{Fore.LIGHTBLACK_EX}Not installed{Fore.RESET}', addon, '' ]) pbar.update(1) print(self.table.table) else: printft( HTML( '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links or addo' 'n names as an argument.\n<ansigreen>Supported URLs:</ansigreen>\n\thttps://www.curseforge.com' '/wow/addons/[addon_name]\n\thttps://www.wowinterface.com/downloads/[addon_name]\n\tElvUI\n\tE' 'lvUI:Dev\n\tTukUI'))
def c_uninstall(self, args): if args: addons = [ addon.strip() for addon in list(reader([args], skipinitialspace=True))[0] ] with tqdm(total=len(addons), bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar: for addon in addons: name, version = self.core.del_addon(addon) if name: self.tableData.append([ f'{AC.LIGHTRED_EX}Uninstalled{AC.RESET}', name, version ]) else: self.tableData.append([ f'{AC.LIGHTBLACK_EX}Not installed{AC.RESET}', addon, '' ]) pbar.update(1) self.sanitize_table() printft(ANSI(self.table.table)) else: printft( HTML( '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links as an a' 'rgument.\n<ansigreen>Supported URLs:</ansigreen>\n\thttps://www.curseforge.com/wow/addons/[ad' 'don_name] <ansiwhite>|</ansiwhite> cf:[addon_name]\n\thttps://www.wowinterface.com/downloads/' '[addon_name] <ansiwhite>|</ansiwhite> wowi:[addon_id]\n\thttps://www.tukui.org/addons.php?id=' '[addon_id] <ansiwhite>|</ansiwhite> tu:[addon_id]\n\thttps://www.tukui.org/classic-addons.php' '?id=[addon_id] <ansiwhite>|</ansiwhite> tuc:[addon_id]\n\tElvUI <ansiwhite>|</ansiwhite> ElvU' 'I:Dev\n\tTukui'))
def c_help(self, _): printft(HTML('<ansigreen>install [URL]</ansigreen>\n\tCommand accepts a comma-separated list of links.\n' '<ansigreen>uninstall [URL/Name]</ansigreen>\n\tCommand accepts a comma-separated list of links or' ' addon names.\n' '<ansigreen>update [URL/Name]</ansigreen>\n\tCommand accepts a comma-separated list of links or ad' 'don names.\n\tIf no argument is provided all non-modified addons will be updated.\n' '<ansigreen>force_update [URL/Name]</ansigreen>\n\tCommand accepts a comma-separated list of links' ' or addon names.\n\tSelected addons will be reinstalled or updated regardless of their current st' 'ate.\n' '<ansigreen>wa_update</ansigreen>\n\tCommand detects all installed WeakAuras and generate WeakAura' 's Companion payload.\n' '<ansigreen>status</ansigreen>\n\tPrints the current state of all installed addons.\n' '<ansigreen>orphans</ansigreen>\n\tPrints list of orphaned directories and files.\n' '<ansigreen>search [Keyword]</ansigreen>\n\tExecutes addon search on CurseForge.\n' '<ansigreen>import</ansigreen>\n\tCommand attempts to import already installed addons.\n' '<ansigreen>export</ansigreen>\n\tCommand prints list of all installed addons in a form suitable f' 'or sharing.\n' '<ansigreen>toggle_backup</ansigreen>\n\tEnables/disables automatic daily backup of WTF directory.' '\n<ansigreen>toggle_dev [Name]</ansigreen>\n\tCommand accepts an addon name as argument.\n\tPrior' 'itizes alpha/beta versions for the provided addon.\n' '<ansigreen>toggle_wa [Username]</ansigreen>\n\tEnables/disables automatic WeakAuras updates.\n\tI' 'f a username is provided check will start to ignore the specified author.\n' '<ansigreen>set_wa_api [API key]</ansigreen>\n\tSets Wago API key required to access private auras' '.\n\tIt can be procured here: https://wago.io/account\n' '<ansigreen>set_wa_wow_account [Account name]</ansigreen>\n\tSets WoW account used by WeakAuras up' 'dater.\n\tNeeded only if WeakAuras are used on more than one WoW account.\n' '<ansigreen>uri_integration</ansigreen>\n\tEnables integration with CurseForge page. "Install" but' 'ton will now start this application.\n' '\n<ansibrightgreen>Supported URL:</ansibrightgreen>\n\thttps://www.curseforge.com/wow/addons/[add' 'on_name] <ansiwhite>|</ansiwhite> cf:[addon_name]\n\thttps://www.wowinterface.com/downloads/[addo' 'n_name] <ansiwhite>|</ansiwhite> wowi:[addon_id]\n\thttps://www.tukui.org/addons.php?id=[addon_id' '] <ansiwhite>|</ansiwhite> tu:[addon_id]\n\thttps://www.tukui.org/classic-addons.php?id=[addon_id' '] <ansiwhite>|</ansiwhite> tuc:[addon_id]\n\tElvUI <ansiwhite>|</ansiwhite> ElvUI:Dev\n\tTukui'))
def c_install(self, args): if args: addons = [addon.strip() for addon in args.split(',')] with tqdm(total=len(addons), bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar: for addon in addons: installed, name, version = self.core.add_addon(addon) if installed: self.tableData.append( [f'{AC.GREEN}Installed{AC.RESET}', name, version]) else: self.tableData.append([ f'{AC.LIGHTBLACK_EX}Already installed{AC.RESET}', name, version ]) pbar.update(1) printft(ANSI(self.table.table)) else: printft( HTML( '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links as an a' 'rgument.\n<ansigreen>Supported URLs:</ansigreen>\n\thttps://www.curseforge.com/wow/addons/[ad' 'don_name] <ansiwhite>|</ansiwhite> cf:[addon_name]\n\thttps://www.wowinterface.com/downloads/' '[addon_name] <ansiwhite>|</ansiwhite> wowi:[addon_id]\n\thttps://www.tukui.org/addons.php?id=' '[addon_id]\n\thttps://www.tukui.org/classic-addons.php?id=[addon_id]\n\tElvUI <ansiwhite>|</a' 'nsiwhite> ElvUI:Dev\n\tTukui'))
def c_install(self, args): if args: if args.startswith('-i '): args = args[3:] optignore = True else: optignore = False addons = [addon.strip() for addon in args.split(',')] with tqdm(total=len(addons), bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar: for addon in addons: installed, name, version = self.core.add_addon( addon, optignore) if installed: self.tableData.append( [f'{AC.GREEN}Installed{AC.RESET}', name, version]) else: self.tableData.append([ f'{AC.LIGHTBLACK_EX}Already installed{AC.RESET}', name, version ]) pbar.update(1) self.sanitize_table() printft(ANSI(self.table.table)) else: printft( HTML( '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links as an a' 'rgument.\n\tOption <ansiwhite>-i</ansiwhite> will disable the client version check.\n<ansigre' 'en>Supported URLs:</ansigreen>\n\thttps://www.curseforge.com/wow/addons/[addon_name] <ansiwhi' 'te>|</ansiwhite> cf:[addon_name]\n\thttps://www.wowinterface.com/downloads/[addon_name] <ansi' 'white>|</ansiwhite> wowi:[addon_id]\n\thttps://www.tukui.org/addons.php?id=[addon_id] <ansiwh' 'ite>|</ansiwhite> tu:[addon_id]\n\thttps://www.tukui.org/classic-addons.php?id=[addon_id] <an' 'siwhite>|</ansiwhite> tuc:[addon_id]\n\tElvUI <ansiwhite>|</ansiwhite> ElvU' 'I:Dev\n\tTukui'))
def c_force_update(self, args): if args: self.c_update(args, False, True, True) else: printft( HTML( '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links or addo' 'n names as an argument.'))
def c_uri_integration(self, _): self.core.create_reg() printft('CurseBreaker.reg file was created. Attempting to import...') out = os.system('Reg import CurseBreaker.reg') if out != 0: printft('Import failed. Please try to import REG file manually.') else: os.remove('CurseBreaker.reg')
def handle_exception(self, e): if len(self.table_data) > 1: print(self.table.table) if getattr(sys, 'frozen', False): printft(HTML(f'\n<ansibrightred>{str(e)}</ansibrightred>')) else: sys.tracebacklimit = 1000 traceback.print_exc()
def c_update(self, args, addline=False, update=True, force=False): if len(self.core.cfCache) > 0 or len(self.core.wowiCache) > 0: self.core.cfCache = {} self.core.wowiCache = {} if args: addons = [ addon.strip() for addon in list(reader([args], skipinitialspace=True))[0] ] else: addons = sorted(self.core.config['Addons'], key=lambda k: k['Name'].lower()) self.core.bulk_check(addons) with tqdm(total=len(addons), bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar: exceptions = [] for addon in addons: try: name, versionnew, versionold, modified = self.core.\ update_addon(addon if isinstance(addon, str) else addon['URL'], update, force) if versionold: if versionold == versionnew: if modified: self.tableData.append([ f'{AC.LIGHTRED_EX}Modified{AC.RESET}', name, versionold ]) else: self.tableData.append([ f'{AC.GREEN}Up-to-date{AC.RESET}', name, versionold ]) else: if modified: self.tableData.append([ f'{AC.LIGHTRED_EX}Update suppressed{AC.RESET}', name, versionold ]) else: self.tableData.append([ f'{AC.YELLOW}{"Updated " if update else "Update available"}' f'{AC.RESET}', name, f'{AC.YELLOW}{versionnew}{AC.RESET}' ]) else: self.tableData.append([ f'{AC.LIGHTBLACK_EX}Not installed{AC.RESET}', addon, '' ]) except Exception as e: exceptions.append(e) pbar.update(1) self.sanitize_table() printft(ANSI('\n' + self.table.table if addline else self.table.table)) if len(exceptions) > 0: self.handle_exception(exceptions, False)
def c_symlink_protection(self, _): if self.os == 'Windows': printft(HTML('<ansigreen>Directories tweaked:</ansigreen>')) for root, dirs, _ in os.walk(self.core.path / '..' / '..'): for d in dirs: path = Path(root) / d if os.path.islink(path): set_icon(path, Path("C:/Windows/System32/SHELL32.dll"), 4) print(path.resolve()) else: printft('This feature is available only on Windows.')
def c_uri_integration(self, _): self.core.create_reg() printft('CurseBreaker.reg file was created. Attempting to import...') out = os.system( '"' + str(Path(os.path.dirname(sys.executable), 'CurseBreaker.reg')) + '"') if out != 0: printft('Import failed. Please try to import REG file manually.') else: os.remove('CurseBreaker.reg')
def c_toggle_wa(self, args): if args: if args == self.core.config['WAUsername']: printft( HTML( f'WeakAuras version check is now: <ansigreen>ENABLED</ansigreen>\n' f'Auras created by <ansiwhite>{self.core.config["WAUsername"]}</ansiwhite>' f' are now included.')) self.core.config['WAUsername'] = '' else: self.core.config['WAUsername'] = args.strip() printft( HTML( f'WeakAuras version check is now: <ansigreen>ENABLED</ansigreen>\n' f'Auras created by <ansiwhite>{self.core.config["WAUsername"]}</ansiwhite>' f' are now ignored.')) else: if self.core.config['WAUsername'] == 'DISABLED': self.core.config['WAUsername'] = '' printft( HTML( 'WeakAuras version check is now: <ansigreen>ENABLED</ansigreen>' )) else: self.core.config['WAUsername'] = '******' shutil.rmtree(Path('Interface/AddOns/WeakAurasCompanion'), ignore_errors=True) printft( HTML( 'WeakAuras version check is now: <ansired>DISABLED</ansired>' )) self.core.save_config()
def c_install(self, args): if args: if args.startswith('-i '): args = args[3:] optignore = True else: optignore = False addons = [ addon.strip() for addon in list(reader([args], skipinitialspace=True))[0] ] with tqdm(total=len(addons), bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar: results = [] pool = ThreadPool(len(addons) if len(addons) <= 10 else 10) queue = Queue() last = False for addon in addons: results.append( pool.apply_async(self.core.add_addon, args=(addon, optignore, queue))) for _ in range(len(addons)): queue.get() pbar.update(1) pool.close() pool.join() self.core.save_config() for result in range(len(results)): installed, name, version = results[result].get() if installed: self.tableData.append( [f'{AC.GREEN}Installed{AC.RESET}', name, version]) else: self.tableData.append([ f'{AC.LIGHTBLACK_EX}Already installed{AC.RESET}', name, version ]) self.sanitize_table() printft(ANSI(self.table.table)) else: printft( HTML( '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links as an a' 'rgument.\n\tOption <ansiwhite>-i</ansiwhite> will disable the client version check.\n<ansigre' 'en>Supported URLs:</ansigreen>\n\thttps://www.curseforge.com/wow/addons/[addon_name] <ansiwhi' 'te>|</ansiwhite> cf:[addon_name]\n\thttps://www.wowinterface.com/downloads/[addon_name] <ansi' 'white>|</ansiwhite> wowi:[addon_id]\n\thttps://www.tukui.org/addons.php?id=[addon_id] <ansiwh' 'ite>|</ansiwhite> tu:[addon_id]\n\thttps://www.tukui.org/classic-addons.php?id=[addon_id] <an' 'siwhite>|</ansiwhite> tuc:[addon_id]\n\tElvUI <ansiwhite>|</ansiwhite> ElvU' 'I:Dev\n\tTukui'))
def c_orphans(self, _): orphansd, orphansf = self.core.find_orphans() printft(HTML('<ansigreen>Directories that are not part of any installed addon:</ansigreen>')) for orphan in sorted(orphansd): printft(HTML(orphan.replace('[GIT]', '<ansiyellow>[GIT]</ansiyellow>'))) printft(HTML('\n<ansigreen>Files that are leftovers after no longer installed addons:</ansigreen>')) for orphan in sorted(orphansf): printft(orphan)
def runner( list, cwd): p = subprocess.Popen(list, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) r = re.compile('pkg2zip v\\d.\\d') full_out = '' for line in iter(p.stdout.readline, b''): out = line.rstrip().decode() full_out += f"{out}\n" # if out.startswith("ERROR") == False and r.match(out) is None: # rich.print(out, style="dim") # test for corrupted and file not being a pkg if "ERROR: not a pkg file" in full_out: # corrupted file and feeding inexistent file if os.path.isfile(file): if file.endswith(".pkg"): rich.print("The provided file is is a .pkg, but seems to be corrupted", style='red on black') else: rich.print("The provided file is is not a .pkg", style='red on black') else: rich.print("Provided file doesn't exist", style='red on black') return False elif "ERROR: pkg file is too small" in full_out: # download not ended rich.print("The provided file is too small, it's probably corrupted or didn't fully downloaded", style='red on black') return False elif "ERROR: failed to read 256 bytes from file" in full_out: # feeded a folder to pkg2zip if os.path.isdir(file): rich.print("The provided file seems to be a folder", style='red on black') else: rich.print("Unknown extraction error. Output:", style='red on black') rich.print(full_out, style='bright_black on black') return False elif "ERROR: cannot create 'pspemu' folder" in full_out: printft(HTML("<red>[PKG2ZIP] cannot create 'pspemu' folder. Do you have reading permissions for your Download folder?</red>")) else: if "done!" in full_out: rich.print(f"File extracted to: [bright_black]{extraction_folder}", style='green') return True else: rich.print("Unknown extraction error. Output:", style='red on black') rich.print(full_out, style='bright_black on black') return False
def c_toggle_dev(self, args): if args: status = self.core.dev_toggle(args) if status is None: printft(HTML('<ansibrightred>This addon does not exist or it is not installed yet.</ansibrightred>')) elif status: printft('This addon will now prioritize alpha/beta versions.') else: printft('This addon will not longer prioritize alpha/beta versions.') else: printft(HTML('<ansigreen>Usage:</ansigreen>\n\tThis command accepts an addon name as an argument.'))
def c_search(self, args): if args: results = self.core.search(args) printft(HTML('<ansigreen>Top results of your search:</ansigreen>')) for url in results: if self.core.check_if_installed(url): printft(HTML(f'{url} <ansiyellow>[Installed]</ansiyellow>')) else: printft(url) else: printft(HTML('<ansigreen>Usage:</ansigreen>\n\tThis command accepts a search query as an argument.'))
def auto_update(self): if getattr(sys, 'frozen', False): try: if os.path.isfile(sys.executable + '.old'): os.remove(sys.executable + '.old') payload = requests.get( 'https://api.github.com/repos/AcidWeb/CurseBreaker/releases/latest', headers=HEADERS).json() remoteversion = payload['name'] changelog = payload['body'] url = payload['assets'][0]['browser_download_url'] if StrictVersion( remoteversion[1:]) > StrictVersion(__version__): printft( HTML( '<ansigreen>Updating CurseBreaker...</ansigreen>')) shutil.move(sys.executable, sys.executable + '.old') payload = requests.get(url, headers=HEADERS) with open(sys.executable, 'wb') as f: f.write(payload.content) printft( HTML( f'<ansibrightgreen>Update complete! Please restart the application.</ansibrightgreen' f'>\n\n<ansigreen>Changelog:</ansigreen>\n{changelog}\n' )) os.system('pause') sys.exit(0) except Exception as e: printft( HTML( f'<ansibrightred>Update failed!\n\nReason: {str(e)}</ansibrightred>\n' )) os.system('pause') sys.exit(1)
def process_resumes(out): for dict in out: term_cols = get_terminal_columns() tag = dict["session_tag"] index = dict["Index"] dicts = dict["session_dict"] time = dict["session_time"] id = dict["session_id"] pretty_time = dict["session_prettytime"] printft(HTML("<green>Session</green><red> %s</red>") % index) header = f"TAG: {tag} | SAVED AT: {pretty_time}" tail = f"UUID: {id}" header_tail = f"{header} | {tail}" if len(header_tail) < term_cols: rest = " " * (term_cols - (len(header) + len(tail))) header_tail = f"{header}{rest}{tail}" # print(header_tail) printft(HTML("<grey>%s</grey>") % header_tail) process_search(dicts, show_index=False) printft(HTML("<grey>%s</grey>") % fill_term())
def c_set_wa_wow_account(self, args): if args: args = args.strip() if os.path.isfile(Path(f'WTF/Account/{args}/SavedVariables/WeakAuras.lua')): printft(HTML(f'WoW account name set to: <ansiwhite>{args}</ansiwhite>')) self.core.config['WAAccountName'] = args self.core.save_config() else: printft('Incorrect WoW account name.') else: printft(HTML('<ansigreen>Usage:</ansigreen>\n\tThis command accepts the WoW account name as an argument.'))
def c_set_wa_api(self, args): if args: printft('Wago API key is now set.') self.core.config['WAAPIKey'] = args.strip() self.core.save_config() elif self.core.config['WAAPIKey'] != '': printft('Wago API key is now removed.') self.core.config['WAAPIKey'] = '' self.core.save_config() else: printft(HTML('<ansigreen>Usage:</ansigreen>\n\tThis command accepts API key as an argument.'))
def auto_update(self): if getattr(sys, 'frozen', False): try: if os.path.isfile(sys.executable + '.old'): try: os.remove(sys.executable + '.old') except PermissionError: pass payload = requests.get( 'https://api.github.com/repos/AcidWeb/CurseBreaker/releases/latest', headers=HEADERS).json() if 'name' in payload and 'body' in payload and 'assets' in payload: remoteversion = payload['name'] changelog = payload['body'] url = None for binary in payload['assets']: if (self.os == 'Windows' and '.exe' in binary['name'])\ or (self.os == 'Darwin' and '.zip' in binary['name'])\ or (self.os == 'Linux' and '.gz' in binary['name']): url = binary['browser_download_url'] break if url and StrictVersion( remoteversion[1:]) > StrictVersion(__version__): printft( HTML( '<ansigreen>Updating CurseBreaker...</ansigreen>' )) shutil.move(sys.executable, sys.executable + '.old') payload = requests.get(url, headers=HEADERS) if self.os == 'Darwin': zipfile.ZipFile(io.BytesIO( payload.content)).extractall() else: with open(sys.executable, 'wb') as f: if self.os == 'Windows': f.write(payload.content) elif self.os == 'Linux': f.write(gzip.decompress(payload.content)) os.chmod(sys.executable, 0o775) printft( HTML( f'<ansibrightgreen>Update complete! Please restart the application.</ansibrightgre' f'en>\n\n<ansigreen>Changelog:</ansigreen>\n{changelog}\n' )) pause() sys.exit(0) except Exception as e: printft( HTML( f'<ansibrightred>Update failed!\n\nReason: {str(e)}</ansibrightred>\n' )) pause() sys.exit(1)
def download_save_state(dict, DBFOLDER, id, tag=False): """saves downloads sessions""" epoch_date = int(time.time()) pretty_date = datetime.utcfromtimestamp(epoch_date).strftime('%Y-%m-%d %H:%M:%S') with SqliteDict(f"{DBFOLDER}/downloads.db", autocommit=False) as database: if "resumes" not in database: database["resumes"] = [] database_editable = database["resumes"] # check, by uuid, if session is already saved checker = next((item for item in database_editable if item['session_id'] == id), None) if tag in [None, False]: tag = str(epoch_date) printft(HTML("<green>[DOWNLOAD] saving session with the tag: %s</green>") %epoch_date) else: # check if tag is already used by other session that's not checker tag_checker = next((item for item in database_editable if item['session_tag'] == tag), None) if tag_checker is not None: if checker is not None: # match tag_chcker uuid with checker uuid # make a new one in case the uuids are different if checker['session_id'] != tag_checker['session_id']: tag = f"{tag}{epoch_date}" printft(HTML("<orange>[DOWNLOAD] tag is in use by other session, new tag will be set as: %s</orange>") %tag) else: # just make a new tag appeding epoch_date # since duplication is certain tag = f"{tag}{epoch_date}" printft(HTML("<orange>[DOWNLOAD] tag is in use by other session, new tag will be set as: %s</orange>") %tag) new_dict = {"session_time":epoch_date, "session_prettytime":pretty_date, "session_dict":dict, "session_tag":tag, "session_id":id } if checker is None: database_editable.append(new_dict) else: checker_index = database_editable.index(checker) database_editable[checker_index].update(new_dict) # try commiting database["resumes"] = database_editable database.commit()
def auth(self) -> None: login_sys = Login() try: if not login_sys.passwd: printft('First run - initialise users') admin_user = self.session.prompt( 'Admin username (default: {}): '.format( DEFAULT_ADMIN_USERNAME)) if not admin_user: admin_user = DEFAULT_ADMIN_USERNAME admin_pass = self.session.prompt('Admin password: '******'Admin password: '******'admin']) else: login_attempt = 0 while True: user = None while not user: user = self.session.prompt('Username: '******'Password: '******'Login attempt limit reached. Exiting') self.exit(1) printft('Username or password incorrect. Please try again') except KeyboardInterrupt: printft('Exiting...') self.exit(0) self.run()
def run(self) -> None: while True: cmd = None try: cmd = self.session.prompt(self.prompt_text, is_password=False) except KeyboardInterrupt: printft('CTRL-C pressed') except EOFError: printft('CTRL-D pressed') if cmd == 'exit': self.exit() if cmd == 'repair': self.runrepair() if cmd == 'clear': self.clear() printft('cmd is {}'.format(cmd))
def handle_exception(self, e, table=True): if len(self.tableData) > 1 and table: self.sanitize_table() printft(ANSI(self.table.table)) if getattr(sys, 'frozen', False): if isinstance(e, list): for es in e: printft(HTML(f'\n<ansibrightred>{str(es)}</ansibrightred>')) else: printft(HTML(f'\n<ansibrightred>{str(e)}</ansibrightred>')) else: if isinstance(e, list): for es in e: traceback.print_exception(es, es, es.__traceback__, limit=1000) else: traceback.print_exc(limit=1000)
def create_args(): parser = argparse.ArgumentParser( description= 'pyNPS is a Nopaystation client writen in python 3.7 that, with the help of wget and pkg2zip, can search, download and decrypt/extract PSVita, PSP, PSX and PSM games from Nopaystation database.' ) parser.add_argument( "search", help= "search something to download, you can search by name or ID or use '_all' to return everythning.", type=str, nargs="?") parser.add_argument("-c", "--console", help="the console you wanna get content with NPS.", type=str, required=False, action='append', choices=["psv", "psp", "psx", "psm", "ps3"]) parser.add_argument("-r", "--region", help="the region for the pkj you want.", type=str, required=False, action='append', choices=["usa", "eur", "jap", "asia", "int"]) parser.add_argument( "-s", "--sort", help= "sort search output by column name, can string multiple names by using a comma. Available options are: console or c, title_id or id, region or r, type or t, game_name or n, size or s. Default value: c,t,r,n", type=str, required=False) parser.add_argument("-G", "-dg", "--games", help="to download PSV/PSP/PSX/PSM games.", action="store_true") parser.add_argument("-D", "-dd", "--dlcs", help="to download PSV/PSP dlcs.", action="store_true") parser.add_argument("-T", "-dt", "--themes", help="to download PSV/PSP themes.", action="store_true") parser.add_argument("-U", "-du", "--updates", help="to download PSV/PSP game updates.", action="store_true") parser.add_argument("-E", "-dde", "--demos", help="to download PSV demos.", action="store_true") parser.add_argument("-A", "-da", "--avatars", help="to download PS3 avatars.", action="store_true") parser.add_argument( "-k", "--keepkg", help="using this flag will keep the pkg after the extraction", action="store_true") parser.add_argument( "-eb", "--eboot", help="use this argument to unpack PSP games as EBOOT.PBP", action="store_true") parser.add_argument( "-cso", "--compress_cso", help= "use this argument to unpack PSP games as a compressed .cso file. You can use any number beetween 1 and 9 for compression factors, were 1 is less compressed and 9 is more compressed.", type=str, required=False, choices=[str(x) for x in range(1, 10)]) parser.add_argument("-zip", "--compress_zip", help="extract pkgs into zip files instead of folders.", action="store_true") parser.add_argument( "-l", "--limit_rate", help="limit download speed, input is the same as wget's.", type=str, required=False) parser.add_argument("-u", "--update", help="update database.", action="store_true") parser.add_argument( "-p", "--print", help= "just print the result and exit, you can use this option to redirect the output to a file!", action="store_true") parser.add_argument("-R", "--resume_session", help="update database.", action="store_true") parser.add_argument('--version', action='version', version=f"%(prog)s version {variables.VERSION}") a = parser.parse_args() if a.console is not None: a.console = list({x.upper() for x in a.console}) else: # consoles that are shown by default, i.e in case the -c flag is not used a.console = ["PSV", "PSP", "PSX", "PSM", "PS3"] # warn zip, cso and eboot won't work with PS3 if "PS3" in a.console: if a.compress_zip is True: printft( HTML( "<orange>[WARNING] PS3 games can't be extracted as zip files</orange>" )) if a.compress_cso is True: printft( HTML( "<orange>[WARNING] PS3 games can't be compressed as cso files</orange>" )) if a.eboot is True: printft( HTML( "<orange>[WARNING] PS3 games can't be packed as eboot files</orange>" )) # exclusions test = [ a.console, a.region, a.games, a.dlcs, a.themes, a.updates, a.demos, a.eboot, a.compress_cso, a.update, a.avatars ] == [['PSV', 'PSP', 'PSX', 'PSM', 'PS3'], None, False, False, False, False, False, False, None, False, False] if a.resume_session is True and test is False: printft( HTML( "<red>[ERROR] you can only use -R/--resume_session alongside the -l/--limit_rate and -k/--keepkg arguments</red>" )) sys.exit(1) # unsuported download types if "PSP" in a.console and True in [a.demos, a.avatars]: if len(a.console) > 1: printft( HTML( "<orange>[WARNING] NPS has no support for demos or avatars with the Playstation Portable (PSP)</orange>" )) else: printft( HTML( "<red>[ERROR] NPS has no support for demos or avatars with the Playstation Portable (PSP)</red>" )) sys.exit(1) if "PSX" in a.console and True in [ a.dlcs, a.themes, a.updates, a.demos, a.avatars ]: if len(a.console) > 1: printft( HTML( "<orange>[WARNING] NPS only supports game downlaods for the Playstation (PSX)</orange>" )) else: printft( HTML( "<red>[ERROR] NPS only supports game downlaods for the Playstation (PSX)</red>" )) sys.exit(1) if "PS3" in a.console and a.updates == True: if len(a.console) > 1: printft( HTML( "<orange>[WARNING] NPS has no support for updates with the Playstation 3 (PS3)</orange>" )) else: printft( HTML( "<red>[ERROR] NPS has no support for updates with the Playstation 3 (PS3))</red>" )) sys.exit(1) if "PSV" in a.console and a.avatars == True: if len(a.console) > 1: printft( HTML( "<orange>[WARNING] NPS has no support for avatars with the Playstation Vita (PSV)</orange>" )) else: printft( HTML( "<red>[ERROR] NPS has no support for avatars with the Playstation Vita (PSV)</red>" )) sys.exit(1) if "PSM" in a.console and a.avatars == True: if len(a.console) > 1: printft( HTML( "<orange>[WARNING] NPS has no support for avatars with the Playstation Mobile (PSM)</orange>" )) else: printft( HTML( "<red>[ERROR] NPS has no support for avatars with the Playstation Mobile (PSM)</red>" )) sys.exit(1) # limit rate string if a.limit_rate is not None: # check how it ends if a.limit_rate[:-1].isdigit() is False or a.limit_rate[-1].lower( ) not in ["k", "m", "g", "t"]: printft(HTML("<red>[ERROR] invalid format for --limit_rate</red>")) sys.exit(1) # eboot and cso can't be used at the same time if a.eboot is True and a.compress_cso is not None: printft( HTML( "<red>[ERROR] you can't use --eboot and --compress_cso at the same time</red>" )) sys.exit(1) # check order list if a.sort is not None: for i in a.sort.split(","): if i.lower() not in [ "c", "id", "r", "t", "gn", "s", "console", "title_id", "region", "type", "game_name", "size" ]: printft(HTML("<red>[ERROR] invalid list for --order</red>")) sys.exit(1) return a, parser
def dl_file(dict, system, DLFOLDER, WGET, limit_rate): """this function downloads the games""" system_name = variables.FULL_SYSTEM_NAME[system.upper()] url = dict['PKG direct link'] filename = url.split('/')[-1] name = dict['Name'] title_id = dict['Title ID'] printft(HTML("<grey>%s</grey>") % fill_term()) printft( HTML("<green>[DOWNLOAD] %s (%s) [%s] for %s</green>") % (name, dict['Region'], title_id, system)) dl_folder = f"{DLFOLDER}/PKG/{system}/{dict['Type']}" # making folder create_folder(dl_folder) # check if file exists if os.path.isfile(f"{dl_folder}/{filename}"): printft( HTML( "<orange>[DOWNLOAD] file exists, wget will decide if the file is completely downloaded, if it's not the download will be resumed</orange>" )) try: if limit_rate is None: process = subprocess.run( [WGET, "-q", "--show-progress", "-c", dl_folder, url], cwd=dl_folder) else: process = subprocess.run([ WGET, "-q", "--show-progress", "-c", "--limit-rate", limit_rate, dl_folder, url ], cwd=dl_folder) except KeyboardInterrupt: # TODO: add infor about resuming printft( HTML( "\n<orange>[DOWNLOAD] File was partially downloaded, you can resume this download by searching for same pkg again</orange>" )) printft( HTML( "<orange>[DOWNLOAD] File location:</orange> <grey>%s/%s</grey>" ) % (dl_folder, filename)) printft(HTML("<grey>Download interrupted by user</grey>")) return False return True
def c_export(self, _): printft(self.core.export_addons())
def c_import(self, args): hit, partial_hit, miss = self.core.detect_addons() if args == 'install' and len(hit) > 0: self.c_install(','.join(hit)) else: printft(HTML(f'<ansigreen>Addons found:</ansigreen>')) for addon in hit: printft(addon) printft(HTML(f'\n<ansiyellow>Possible matches:</ansiyellow>')) for addon in partial_hit: printft(HTML(' <ansiwhite>or</ansiwhite> '.join(addon))) printft(HTML(f'\n<ansired>Unknown directories:</ansired>')) for addon in miss: printft(f'{addon}') printft( HTML( f'\nExecute <ansiwhite>import install</ansiwhite> command to install all detected addons.\n' f'Possible matches need to be installed manually with the <ansiwhite>install</ansiwhite>' f' command.'))