def fileName(self): bt = None if not self.titleId in Titles.keys(): if not Title.getBaseId(self.titleId) in Titles.keys(): Print.info('could not find title key for ' + str(self.titleId) + ' or ' + str(Title.getBaseId(self.titleId))) return None bt = Titles.get(Title.getBaseId(self.titleId)) t = Title() t.loadCsv(self.titleId + '0000000000000000|0000000000000000|' + bt.name) else: t = Titles.get(self.titleId) if not t: Print.error('could not find title id ' + str(self.titleId)) return None try: if not t.baseId in Titles.keys(): Print.info('could not find baseId for ' + self.path) return None except BaseException as e: print('exception: could not find title id ' + str(self.titleId) + ' ' + str(e)) return None bt = Titles.get(t.baseId) if t.isDLC: format = Config.paths.getTitleDLC(not self.hasValidTicket) elif t.isDemo: if t.idExt != 0: format = Config.paths.getTitleDemoUpdate( not self.hasValidTicket) else: format = Config.paths.getTitleDemo(not self.hasValidTicket) elif t.idExt != 0: format = Config.paths.getTitleUpdate(not self.hasValidTicket) else: format = Config.paths.getTitleBase(not self.hasValidTicket) format = format.replace('{id}', self.cleanFilename(t.id)) format = format.replace('{region}', self.cleanFilename(t.getRegion() or '')) format = format.replace('{name}', self.cleanFilename(t.getName() or '')) format = format.replace('{version}', str(self.getVersion() or 0)) format = format.replace('{baseId}', self.cleanFilename(bt.id)) baseName = self.cleanFilename(bt.getName() or '') result = format.replace('{baseName}', baseName) while (len(os.path.basename(result).encode('utf-8')) > 240 and len(baseName) > 3): baseName = baseName[:-1] result = format.replace('{baseName}', baseName) return result
def updateVersions(force=True): initTitles() initFiles() i = 0 for k, t in Titles.items(): if force or t.version is None: if (t.isDLC or t.isUpdate or Config.download.base) and (not t.isDLC or Config.download.DLC) and (not t.isDemo or Config.download.demo) and (not t.isUpdate or Config.download.update) and ( t.key or Config.download.sansTitleKey) and (len(Config.titleWhitelist) == 0 or t.id in Config.titleWhitelist) and t.id not in Config.titleBlacklist: v = t.lastestVersion(True) Print.info("%s[%s] v = %s" % (str(t.name), str(t.id), str(v))) i = i + 1 if i % 20 == 0: Titles.save() for t in list(Titles.data().values()): if not t.isUpdate and not t.isDLC and t.updateId and t.updateId and not Titles.contains(t.updateId): u = Title.Title() u.setId(t.updateId) if u.lastestVersion(): Titles.set(t.updateId, u) Print.info("%s[%s] FOUND" % (str(t.name), str(u.id))) i = i + 1 if i % 20 == 0: Titles.save() Titles.save()
def load(): confLock.acquire() global titles titles = {} if os.path.isfile("titledb/titles.json"): timestamp = time.clock() with open('titledb/titles.json', encoding="utf-8-sig") as f: for i, k in json.loads(f.read()).items(): titles[i] = Title.Title() titles[i].__dict__ = k titles[i].setId(i) Print.info('loaded titledb/titles.json in ' + str(time.clock() - timestamp) + ' seconds') ''' if os.path.isfile("titles.txt"): loadTitleFile('titles.txt', True) try: files = [f for f in os.listdir(Config.paths.titleDatabase) if f.endswith('.txt')] files.sort() for file in files: loadTitleFile(Config.paths.titleDatabase + '/' + file, False) except BaseException as e: Print.error('title load error: ' + str(e)) ''' confLock.release()
def get(key, region = None, language = None): key = key.upper() if not key in data(region, language): t = Title.Title() t.setId(key) data(region, language)[key] = t return data(region, language)[key]
def scanDLC(id, showErr=True, dlcStatus=None): id = id.upper() title = Titles.get(id) baseDlc = Title.baseDlcId(id) for i in range(0x1FF): scanId = format(baseDlc + i, 'X').zfill(16) if Titles.contains(scanId): continue ver = CDNSP.get_version(scanId.lower()) if ver != None: t = Title() t.setId(scanId) Titles.set(scanId, t) Titles.save() Print.info('Found new DLC ' + str(title.name) + ' : ' + scanId) elif showErr: Print.info('nothing found at ' + scanId + ', ' + str(ver)) if dlcStatus: dlcStatus.add()
def title(self): if not self.titleId: raise IOError('NSP no titleId set') if self.titleId in Titles.keys(): return Titles.get(self.titleId) t = Title.Title() t.setId(self.titleId) Titles.data()[self.titleId] = t return t
def scanBaseThread(baseStatus): while Config.isRunning: try: id = getRandomTitleId() if Titles.contains(id): continue ver = CDNSP.get_version(id.lower()) if ver != None: Print.info('Found new base ' + id) t = Title() t.setId(id) Titles.set(id, t) Titles.save() baseStatus.add() except BaseException as e: print('exception: ' + str(e))
def scanLatestTitleUpdates(): nut.initTitles() nut.initFiles() for k, i in CDNSP.get_versionUpdates().items(): id = str(k).upper() version = str(i) if not Titles.contains(id): if len(id) != 16: Print.info('invalid title id: ' + id) continue continue t = Title() t.setId(id) Titles.set(id, t) Print.info('Found new title id: ' + str(id)) t = Titles.get(id) if str(t.version) != str(version): Print.info('new version detected for %s[%s] v%s' % (t.name or '', t.id or ('0' * 16), str(version))) t.setVersion(version, True) Titles.save()
def getNsuid(id, region, language): id = int(id) map = data(region, language) for t in map: if map[t].nsuId == id: return map[t] title = Title.Title() title.setNsuId(id) map[str(id)] = title return title
def loadTitlesJson(filePath = 'titledb/titles.json'): newTitles = {} confLock.acquire() if os.path.isfile(filePath): timestamp = time.clock() with open(filePath, encoding="utf-8-sig") as f: for i, k in json.loads(f.read()).items(): newTitles[i] = Title.Title() newTitles[i].__dict__ = k newTitles[i].setId(i) Print.info('loaded ' + filePath + ' in ' + str(time.clock() - timestamp) + ' seconds') confLock.release() return newTitles
def scanLatestTitleUpdates(): global versionHistory initTitles() initFiles() now = datetime.datetime.now() today = now.strftime("%Y-%m-%d") try: with open('titledb/versions.json', 'r') as f: for titleId, vers in json.loads(f.read()).items(): for ver, date in vers.items(): setVersionHistory(titleId, ver, date) except BaseException: pass if not hasCdn: return for k, i in cdn.hacVersionList().items(): id = str(k).upper() version = str(i) if not Titles.contains(id): if len(id) != 16: Print.info('invalid title id: ' + id) continue t = Titles.get(id) if t.isUpdate: setVersionHistory(Title.getBaseId(id), version, today) else: setVersionHistory(id, version, today) if str(t.version) != str(version): Print.info('new version detected for %s[%s] v%s' % (t.name or '', t.id or ('0' * 16), str(version))) t.setVersion(version, True) Titles.save() try: with open('titledb/versions.json', 'w') as outfile: json.dump(versionHistory, outfile, indent=4, sort_keys=True) except BaseException as e: Print.info(str(e))
def loadTitlesJson(filePath = 'titledb/titles.json'): newTitles = {} confLock.acquire() try: if os.path.isfile(filePath): timestamp = time.process_time() with open(filePath, encoding="utf-8-sig") as f: for i, k in json.loads(f.read()).items(): newTitles[i] = Title.Title() newTitles[i].__dict__ = k newTitles[i].setId(i) Print.info('loaded ' + filePath + ' in ' + str(time.process_time() - timestamp) + ' seconds') except BaseException as e: print("load titles json exception: " + str(e)) confLock.release() return newTitles
def loadTitleBuffer(buffer, silent=False): global nsuIdMap firstLine = True importedRegions = {} map = ['id', 'key', 'name'] for line in buffer.split('\n'): line = line.strip() if len(line) == 0 or line[0] == '#': continue if firstLine: firstLine = False if re.match('[A-Za-z\|\s]+', line, re.I): map = line.split('|') i = 0 while i < len(map): if map[i] == 'RightsID': map[i] = 'id' if map[i] == 'TitleKey': map[i] = 'key' if map[i] == 'Name': map[i] = 'name' i += 1 continue t = Title.Title() t.loadCsv(line, map) if not isinstance(t.id, str): continue if 'nsuId' in map: nsuIdMap[t.nsuId] = t.id title = get(t.id, None, None) titleKey = title.key title.loadCsv(line, map) if not silent and titleKey != titles[t.id].key: Print.info('Added new title key for ' + str(titles[t.id].name) + '[' + str(t.id) + ']')
def updateVersions(force=True): initTitles() initFiles() i = 0 for k, t in tqdm(Titles.items()): if force or t.version is None: if t.isActive(): v = t.lastestVersion(True) Print.info("%s[%s] v = %s" % (str(t.name), str(t.id), str(v))) for t in list(Titles.data().values()): if not t.isUpdate and not t.isDLC and t.updateId and t.updateId and not Titles.contains( t.updateId): u = Title.Title() u.setId(t.updateId) if u.lastestVersion(): Titles.set(t.updateId, u) Print.info("%s[%s] FOUND" % (str(t.name), str(u.id))) Titles.save()
def fileName(self, forceNsp=False): bt = None if self.titleId not in Titles.keys(): if not Title.getBaseId(self.titleId) in Titles.keys(): Print.error('could not find base title for ' + str(self.titleId) + ' or ' + str(Title.getBaseId(self.titleId))) return None bt = Titles.get(Title.getBaseId(self.titleId)) t = Title.Title() if bt.name is not None: t.loadCsv(self.titleId + '0000000000000000|0000000000000000|' + bt.name) else: t.setId(self.titleId) else: t = Titles.get(self.titleId) if not t: Print.error('could not find title id ' + str(self.titleId)) return None try: if t.baseId not in Titles.keys(): Print.info('could not find baseId for ' + self.path) return None except BaseException as e: Print.error('exception: could not find title id ' + str(self.titleId) + ' ' + str(e)) return None bt = Titles.get(t.baseId) isNsx = not self.hasValidTicket and not forceNsp try: if t.isDLC: format = Config.paths.getTitleDLC(isNsx, self.path) elif t.isDemo: if t.idExt != 0: format = Config.paths.getTitleDemoUpdate(isNsx, self.path) else: format = Config.paths.getTitleDemo(isNsx, self.path) elif t.idExt != 0: if bt and bt.isDemo: format = Config.paths.getTitleDemoUpdate(isNsx, self.path) else: format = Config.paths.getTitleUpdate(isNsx, self.path) else: format = Config.paths.getTitleBase(isNsx, self.path) except BaseException as e: Print.error('calc path exception: ' + str(e)) return None if not format: return None newName = self.cleanFilename(t.getName() or '') format = format.replace('{id}', self.cleanFilename(t.id)) format = format.replace( '{region}', self.cleanFilename(t.getRegion() or bt.getRegion())) format = format.replace('{name}', newName) format = format.replace('{version}', str(self.getVersion() or 0)) format = format.replace('{baseId}', self.cleanFilename(bt.id)) if '{cr}' in format: format = format.replace('{cr}', str(self.getCr())) if '{icr}' in format: format = format.replace('{icr}', str(self.getCr(True))) bn = os.path.basename(self.path) if (not newName or len(newName) == 0) and not bn.upper().startswith(t.id.upper()): Print.error('could not get new name for ' + bn) return os.path.join(os.path.dirname(format), os.path.basename(self.path)) baseName = self.cleanFilename(bt.getName() or '') if not baseName or len(baseName) == 0: baseName = os.path.basename(self.path) result = format.replace('{baseName}', baseName) while (len(os.path.basename(result).encode('utf-8')) > 240 and len(baseName) > 3): baseName = baseName[:-1] result = format.replace('{baseName}', baseName) return os.path.abspath(result)
def move(self, forceNsp=False): if not self.path: Print.error('no path set') return False if os.path.abspath(self.path).startswith( os.path.abspath(Config.paths.nspOut) ) and not self.path.endswith('.nsz') and not self.path.endswith( '.xcz') and Config.compression.auto: nszFile = nut.compress(self.path, Config.compression.level, os.path.abspath(Config.paths.nspOut)) if nszFile: nsp = Fs.Nsp(nszFile, None) nsp.hasValidTicket = True nsp.move(forceNsp=True) Nsps.files[nsp.path] = nsp Nsps.save() newPath = self.fileName(forceNsp=forceNsp) if not newPath: Print.error('could not get filename for ' + self.path) return False if os.path.abspath(newPath).lower().replace( '\\', '/') == os.path.abspath(self.path).lower().replace('\\', '/'): return False if os.path.isfile(newPath): Print.info('\nduplicate title: ') Print.info(os.path.abspath(self.path)) Print.info(os.path.abspath(newPath)) Print.info('\n') return False if not self.verifyNcaHeaders(): Print.error('verification failed: could not move title for ' + str(self.titleId) + ' or ' + str(Title.getBaseId(self.titleId))) return False try: Print.info(self.path + ' -> ' + newPath) if not Config.dryRun: os.makedirs(os.path.dirname(newPath), exist_ok=True) #newPath = self.fileName(forceNsp = forceNsp) if not Config.dryRun: if self.isOpen(): self.close() shutil.move(self.path, newPath) if self.path in Nsps.files: del Nsps.files[self.path] Nsps.files[newPath] = self self.path = newPath except BaseException as e: Print.error('failed to rename file! %s -> %s : %s' % (self.path, newPath, e)) if not Config.dryRun: self.moveDupe() return True