def main(): global err try: if len(argv) > 1: args = ParseArguments.parse() else: try: from nsz.gui.NSZ_GUI import GUI except ImportError: Print.error("Failed to import the GUI - is it installed?") return args = GUI().run() if args == None: Print.info("Done!") return if args.output: outfolderToPharse = args.output if not outfolderToPharse.endswith('/') and not outfolderToPharse.endswith('\\'): outfolderToPharse += "/" if not Path(outfolderToPharse).is_dir(): Print.error('Error: Output directory "{0}" does not exist!'.format(args.output)) return outfolder = Path(outfolderToPharse).resolve() if args.output else Path('.').resolve() Print.info('') Print.info(' NSZ v3.1 ,;:;;,') Print.info(' ;;;;;') Print.info(' .=\', ;:;;:,') Print.info(' /_\', "=. \';:;:;') Print.info(' @=:__, \,;:;:\'') Print.info(' _(\.= ;:;;\'') Print.info(' `"_( _/="`') Print.info(' `"\'') Print.info('') barManager = enlighten.get_manager() poolManager = Manager() statusReport = poolManager.list() readyForWork = Counter(0) pleaseNoPrint = Counter(0) pleaseKillYourself = Counter(0) pool = [] work = poolManager.Queue() amountOfTastkQueued = Counter(0) if args.titlekeys: extractTitlekeys(args.file) if args.extract: for f_str in args.file: for filePath in expandFiles(Path(f_str)): filePath_str = str(filePath) Print.info('Extracting "{0}" to {1}'.format(filePath_str, outfolder)) dir = outfolder.joinpath(filePath.stem) container = factory(filePath) container.open(filePath_str, 'rb') if isXciXcz(filePath): for hfs0 in container.hfs0: secureIn = hfs0 secureIn.unpack(dir.joinpath(hfs0._path), args.extractregex) else: container.unpack(dir, args.extractregex) container.close() if args.create: Print.info('Creating "{0}"'.format(args.create)) nsp = Nsp.Nsp(None, None) nsp.path = args.create nsp.pack(args.file) if args.C: targetDictNsz = CreateTargetDict(outfolder, args.parseCnmt, ".nsz") targetDictXcz = CreateTargetDict(outfolder, args.parseCnmt, ".xcz") sourceFileToDelete = [] for f_str in args.file: for filePath in expandFiles(Path(f_str)): if not isUncompressedGame(filePath): continue try: if filePath.suffix == '.nsp': if not AllowedToWriteOutfile(filePath, ".nsz", targetDictNsz, args.rm_old_version, args.overwrite, args.parseCnmt): continue elif filePath.suffix == '.xci': if not AllowedToWriteOutfile(filePath, ".xcz", targetDictXcz, args.rm_old_version, args.overwrite, args.parseCnmt): continue compress(filePath, outfolder, args, work, amountOfTastkQueued) if args.rm_source: sourceFileToDelete.append(filePath) except KeyboardInterrupt: raise except BaseException as e: Print.error('Error when compressing file: %s' % filePath) err.append({"filename":filePath,"error":format_exc() }) print_exc() bars = [] compressedSubBars = [] BAR_FMT = u'{desc}{desc_pad}{percentage:3.0f}%|{bar}| {count:{len_total}d}/{total:d} {unit} [{elapsed}<{eta}, {rate:.2f}{unit_pad}{unit}/s]' parallelTasks = min(args.multi, amountOfTastkQueued.value()) if parallelTasks < 0: parallelTasks = 4 for i in range(parallelTasks): statusReport.append([0, 0, 100]) p = Process(target=solidCompressTask, args=(work, statusReport, readyForWork, pleaseNoPrint, pleaseKillYourself, i)) p.start() pool.append(p) for i in range(parallelTasks): bar = barManager.counter(total=100, desc='Compressing', unit='MiB', color='cyan', bar_format=BAR_FMT) compressedSubBars.append(bar.add_subcounter('green')) bars.append(bar) #Ensures that all threads are started and compleaded before being requested to quit while readyForWork.value() < parallelTasks: sleep(0.2) if pleaseNoPrint.value() > 0: continue pleaseNoPrint.increment() for i in range(parallelTasks): compressedRead, compressedWritten, total = statusReport[i] if bars[i].total != total: bars[i].total = total//1048576 bars[i].count = compressedRead//1048576 compressedSubBars[i].count = compressedWritten//1048576 bars[i].refresh() pleaseNoPrint.decrement() pleaseKillYourself.increment() for i in range(readyForWork.value()): work.put(None) while readyForWork.value() > 0: sleep(0.02) for i in range(parallelTasks): bars[i].close(clear=True) #barManager.stop() #We aren’t using stop because of it printing garbage to the console. for filePath in sourceFileToDelete: delete_source_file(filePath) if args.D: targetDictNsz = CreateTargetDict(outfolder, args.parseCnmt, ".nsp") targetDictXcz = CreateTargetDict(outfolder, args.parseCnmt, ".xci") for f_str in args.file: for filePath in expandFiles(Path(f_str)): if not isCompressedGame(filePath) and not isCompressedGameFile(filePath): continue try: if filePath.suffix == '.nsz': if not AllowedToWriteOutfile(filePath, ".nsp", targetDictNsz, args.rm_old_version, args.overwrite, args.parseCnmt): continue elif filePath.suffix == '.xcz': if not AllowedToWriteOutfile(filePath, ".xci", targetDictXcz, args.rm_old_version, args.overwrite, args.parseCnmt): continue elif filePath.suffix == '.ncz': outfile = Path(changeExtension(outfolder.joinpath(filePath.name), ".nca")) if not args.overwrite and outfile.is_file(): Print.info('{0} with the same file name already exists in the output directory.\n'\ 'If you want to overwrite it use the -w parameter!'.format(outfile.name)) continue decompress(filePath, outfolder) if args.rm_source: delete_source_file(filePath) except KeyboardInterrupt: raise except BaseException as e: Print.error('Error when decompressing file: {0}'.format(filePath)) err.append({"filename":filePath, "error":format_exc()}) print_exc() if args.info: for f_str in args.file: for filePath in expandFiles(Path(f_str)): filePath_str = str(filePath) Print.info(filePath_str) f = factory(filePath) f.open(filePath_str, 'r+b') f.printInfo(args.depth+1) f.close() if args.verify and not args.C and not args.D: for f_str in args.file: for filePath in expandFiles(Path(f_str)): try: if isGame(filePath): Print.info("[VERIFY {0}] {1}".format(getExtensionName(filePath), filePath.name)) verify(filePath, False) except KeyboardInterrupt: raise except BaseException as e: Print.error('Error when verifying file: {0}'.format(filePath)) err.append({"filename":filePath,"error":format_exc()}) print_exc() if len(argv) == 1: pass except KeyboardInterrupt: Print.info('Keyboard exception') except BaseException as e: Print.info('nut exception: {0}'.format(str(e))) raise if err: Print.info('\n\033[93m\033[1mSummary of errors which occurred while processing files:') for e in err: Print.info('\033[0mError while processing {0}'.format(e["filename"])) Print.info(e["error"]) Print.info('Done!') _exit(0)
def undupe(args): filesAtTarget = {} alreadyExists = {} for f_str in args.file: (filesAtTarget, alreadyExists) = CreateTargetDict( Path(f_str).absolute(), True, None, filesAtTarget, alreadyExists) Print.info("") for (titleID_key, titleID_value) in alreadyExists.items(): maxVersion = max(titleID_value.keys()) for (version_key, version_value) in titleID_value.items(): if args.undupe_old_versions and version_key < maxVersion: for file in list(version_value): if not isOnWhitelist(args, file): if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [OLD_VERSION]: " + file) else: os.remove(file) Print.info("[DELETED] [OLD_VERSION]: " + file) continue if not args.undupe_blacklist == "": for file in list(version_value): if not isOnWhitelist(args, file) and re.match( args.undupe_blacklist, file): version_value.remove(file) if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [BLACKLIST]: " + file) else: os.remove(file) Print.info("[DRYRUN] [DELETED] [BLACKLIST]: " + file) if not args.undupe_prioritylist == "": for file in list(version_value.reverse()): if len(version_value) > 1 and not isOnWhitelisth( args, file) and re.match(args.undupe_prioritylist, file): version_value.remove(file) if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [PRIORITYLIST]: " + file) else: os.remove(file) Print.info("[DRYRUN] [DELETED] [PRIORITYLIST]: " + file) firstDeleted = False for file in list(version_value[1:]): if not isOnWhitelist(args, file): if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [DUPE]: " + file) Print.info("Keeping " + version_value[0]) else: os.remove(file) Print.info("[DELETED] [DUPE]: " + file) Print.info("Keeping " + version_value[0]) elif not firstDeleted and not isOnWhitelist( args, version_value[0]): firstDeleted = True if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [DUPE]: " + version_value[0]) Print.info("Keeping " + file) else: os.remove(version_value[0]) Print.info("[DELETED] [DUPE]: " + version_value[0]) Print.info("Keeping " + file)
def undupe(args, argOutFolder): filesAtTarget = {} alreadyExists = {} for f_str in args.file: (filesAtTarget, alreadyExists) = CreateTargetDict( Path(f_str).absolute(), args, None, filesAtTarget, alreadyExists) Print.info("") for (titleID_key, titleID_value) in alreadyExists.items(): maxVersion = max(titleID_value.keys()) for (version_key, version_value) in titleID_value.items(): if args.undupe_old_versions and version_key < maxVersion: for file in list(version_value): if not isOnWhitelist(args, file): if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [OLD_VERSION]: " + file) else: os.remove(file) Print.info("[DELETED] [OLD_VERSION]: " + file) continue if not args.undupe_blacklist == "": for file in list(version_value): if not isOnWhitelist(args, file) and re.match( args.undupe_blacklist, file): version_value.remove(file) if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [BLACKLIST]: " + file) else: os.remove(file) Print.info("[DRYRUN] [DELETED] [BLACKLIST]: " + file) if not args.undupe_prioritylist == "": for file in list(version_value.reverse()): if len(version_value) > 1 and not isOnWhitelisth( args, file) and re.match(args.undupe_prioritylist, file): version_value.remove(file) if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [PRIORITYLIST]: " + file) else: os.remove(file) Print.info("[DRYRUN] [DELETED] [PRIORITYLIST]: " + file) firstDeleted = False for file in list(version_value[1:]): if not isOnWhitelist(args, file): if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [DUPE]: " + file) Print.info("Keeping " + version_value[0]) else: os.remove(file) Print.info("[DELETED] [DUPE]: " + file) Print.info("Keeping " + version_value[0]) elif not firstDeleted and not isOnWhitelist( args, version_value[0]): firstDeleted = True if args.undupe_dryrun: Print.info("[DRYRUN] [DELETE] [DUPE]: " + version_value[0]) Print.info("Keeping " + file) else: os.remove(version_value[0]) Print.info("[DELETED] [DUPE]: " + version_value[0]) Print.info("Keeping " + file) if args.undupe_rename or args.undupe_hardlink: for file in version_value: if not isOnWhitelist(args, file): newName = str( argOutFolder.joinpath("[" + titleID_key + "][v" + str(version_key) + "]" + Path(file).suffix)) if args.undupe_hardlink: if Path(newName).is_file(): if Path(file).samefile(Path(newName)): Print.info("[HARDLINK] [SKIPPED] " + newName) else: Print.info( "[HARDLINK] [ERROR_ALREADY_EXIST] " + newName) else: if args.undupe_dryrun: Print.info("[DRYRUN] [HARDLINK]: " + "os.link(" + file + ", " + newName) else: Print.info("[HARDLINK]: " + "os.link(" + file + ", " + newName) os.link(file, newName) if args.undupe_rename: if Path(newName).is_file(): if Path(file).samefile(Path(newName)): Print.info("[RENAME] [SKIPPED] " + newName) else: Print.info( "[RENAME] [ERROR_ALREADY_EXIST] " + newName) else: if args.undupe_dryrun: Print.info("[DRYRUN] [RENAME]: " + "os.rename(" + file + ", " + newName) else: Print.info("[RENAME]: " + "os.rename(" + file + ", " + newName) os.rename(file, newName)