From 5aeeae6a4da46dbb5bc11747ed00cb3b1f61ea3b Mon Sep 17 00:00:00 2001 From: RedDucks Date: Fri, 3 Nov 2017 22:13:55 -0400 Subject: [PATCH] Context menu n stuff --- NodeNUSRipper_backup.js | 668 ---------------------------------------- app.js | 45 +-- app/wrapper/js/main.js | 1 + context.js | 71 +++++ ico.png | Bin 30139 -> 7880 bytes icon.ico | Bin 12838 -> 22300 bytes 6 files changed, 98 insertions(+), 687 deletions(-) delete mode 100644 NodeNUSRipper_backup.js create mode 100644 context.js diff --git a/NodeNUSRipper_backup.js b/NodeNUSRipper_backup.js deleted file mode 100644 index 45a71f5..0000000 --- a/NodeNUSRipper_backup.js +++ /dev/null @@ -1,668 +0,0 @@ -/*----------------------------------------------------------------------------- - NodeNUSRipper - - The in-house NUS (Nintendo Update Server) game/update/DLC downloader for CemUI 2.0. - Designed for use only in the free OSS CemUI. - - Copyright (C) 2017 Jonathan Barrow (RedDucks(s)) ------------------------------------------------------------------------------*/ - -var EventEmitter = require('events').EventEmitter, - child_process = require('child_process'), - readline = require('readline'), - fs = require('fs-extra'), - url = require('url'), - util = require('util'), - path = require('path'), - http = require('http'), - async = require('async'), - request = require('request'), - struct = require('python-struct'); - -const NINTENDO_CCS_URL = 'http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/'; -const NINTENDO_NUS_URL = 'http://nus.cdn.c.shop.nintendowifi.net/ccs/download/'; -const TITLE_TYPES = [ - '0000', // application - '0002', // demo - '000C', // DLC - '000E', // update/patch -]; -const DLC_PATCH = new Buffer.from([ - 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00 -]); -const TIK = new Buffer.from([ - 0x00, 0x01, 0x00, 0x04, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, - 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, - 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, - 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, - 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, - 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, - 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, - 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, - 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, - 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, - 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, - 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, - 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, - 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0xD1, 0x5E, 0xA5, 0xED, 0x15, 0xAB, 0xE1, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6F, 0x6F, - 0x74, 0x2D, 0x43, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x2D, 0x58, 0x53, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, - 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, - 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, - 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0x01, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, - 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -]); - -let LOCAL_RESOURCES_ROOT; -if (fs.pathExistsSync('./resources')) { - LOCAL_RESOURCES_ROOT = './resources'; -} else { - LOCAL_RESOURCES_ROOT = './'; -} - -function Main() {} -util.inherits(Main, EventEmitter); - -Main.prototype._config = { - cdecrypt_location: '', - cdecrypt_folder_location: '', - ticket_cache_vendor: '', - ticket_vendor: '', - ticket_cache_folder: './ticketcache' -} - -Main.prototype.CANCEL_LIST = []; - -Main.prototype.cancel = function(tid) { - this.CANCEL_LIST.push(this.formatTID(tid)); -} - -Main.prototype.decrypt = function(location, cb) { - let self = this; - - if (!this._config.cdecrypt_location || this._config.cdecrypt_location.trim() == '' || !fs.pathExistsSync(this._config.cdecrypt_location)) { - self.emit('rom_decryption_missing', location); - self.emit('rom_decryption_completed', location); - if (cb) { - cb(true); - } - return; - } - self.emit('rom_decryption_started', location); - - fs.copySync(this._config.cdecrypt_location, path.join(location, 'cdecrypt.exe')); - fs.copySync(path.join(this._config.cdecrypt_folder_location, 'libeay32.dll'), path.join(location, 'libeay32.dll')); - fs.copySync(path.join(this._config.cdecrypt_folder_location, 'msvcr120d.dll'), path.join(location, 'msvcr120d.dll')); - - console.log('CemUI does not ship with any means to decrypt rom files.\nWhile we would love to do so, we cannot for legal reasons.\nIn order to decrypt the files, CemUI makes use of CDecrypt, which is also not shipped with CemUI due to legal reasons.\nPlease obtain a copy of CDecrypt and tell CemUI where to look for it.'); - - let decrypter = child_process.spawn('cdecrypt.exe', [ - 'title.tmd', 'title.tik' - ], { - cwd: path.resolve(process.cwd(), location) - }); - - let reader = readline.createInterface(decrypter.stdout, decrypter.stdin); - - reader.on('line', (line) => { - self.emit('file_decrypted', line); - }); - - decrypter.on('exit', () => { - let dir = fs.readdirSync(location), - files = dir.filter(file => { - let extension = path.extname(file); - if (extension == '.app' || extension == '.h3') return file; - }); - - files.push('title.tmd'); - files.push('title.tik'); - files.push('title.cert'); - - files.push('cdecrypt.exe'); - files.push('libeay32.dll'); - files.push('msvcr120d.dll'); - - for (let file of files) { - //fs.unlinkSync(path.join(location, file)); - } - - self.emit('rom_decryption_completed', location); - if (cb) { - return cb(); - } - }) -} - -Main.prototype.formatTID = function(TID) { - return TID.replace(/-/g, '').toUpperCase(); -} - -Main.prototype.getTIDType = function(TID) { - return TID.toUpperCase().substring(4, 8); -} - -Main.prototype.getTIDURL = function(TID) { - TID = this.formatTID(TID); - const TID_TYPE = this.getTIDType(TID); - if (TITLE_TYPES.indexOf(TID_TYPE) > -1) { - URL_BASE = url.resolve(NINTENDO_CCS_URL, TID); - } else URL_BASE = url.resolve(NINTENDO_NUS_URL, TID); - - return URL_BASE; -} - -Main.prototype.parseTMD = function(file, cb) { - var tmd = fs.readFileSync(file); - - var tmd_object = {}, - tmd_contents_count = struct.unpack('>H', new Buffer.from(tmd.subarray(0x1DE, 0x1E0)))[0], - tmd_contents = [], - tid_buffer = new Buffer.from(tmd.subarray(0x18C, 0x194)), - version_buffer = new Buffer.from(tmd.subarray(0x1DC, 0x1DE)), - version = struct.unpack('>H', version_buffer)[0]; - - for (var i=0;iH', new Buffer.from(tmd.subarray(0xB0A + (0x30 * i), 0xB0A + (0x30 * i) + 0x2)))[0], - size: struct.unpack('>Q', new Buffer.from(tmd.subarray(0xB0C + (0x30 * i), 0xB0C + (0x30 * i) + 0x8)))[0].low, - id: content_id, - }); - } - - tmd_object.contents = tmd_contents; - tmd_object.version = version; - - if (cb) { - return cb(tmd_object); - } - - return tmd_object; -} - -Main.prototype._patchDLC = function(ticket) { - let unpatched_buffer = fs.readFileSync(ticket), - ticket_beginning = unpatched_buffer.slice(0, 0x140 + 0x164), - ticket_end = unpatched_buffer.slice(0x140 + 0x210), - patched_buffer = Buffer.concat([ticket_beginning, DLC_PATCH, ticket_end]); - - fs.writeFileSync(ticket, patched_buffer); -} - -Main.prototype._generateTicket = function(tid, version, key, output, cb) { - console.log(tid) - console.log(version) - console.log(key) - var ticket = TIK, - version_buffer = new Buffer.from(version.toString()), - tid_buffer = new Buffer.from(this._stringToBin(tid), 'binary'), - key_buffer = new Buffer.from(this._stringToBin(key), 'binary'); - - version_buffer.copy(ticket, 0x1E6, 0); - tid_buffer.copy(ticket, 0x1DC, 0); - key_buffer.copy(ticket, 0x1BF, 0); - - fs.writeFileSync(output, ticket); - - if (cb) { - return cb(); - } -} - -Main.prototype.downloadTicketCache = function(cb) { - let self = this; - fs.ensureDirSync(this._config.ticket_cache_folder); - request(this._config.ticket_cache_vendor, (error, response, body) => { - if (error || response.statusCode != 200) { - return cb(true); - } - let titles = JSON.parse(body), - cache = [], - i = 0; - - fs.writeJSONSync(path.join(this._config.ticket_cache_folder, '_cache.json'), titles); - - var queue = async.queue((title, callback) => { - i++; - self.emit('ticket_downloaded', { - id: i, - total: titles.length - }); - if (title.titleKey && title.titleKey.trim() != '') { - if (!fs.pathExistsSync(path.join(this._config.ticket_cache_folder, title.titleID + '.tik')) && title.ticket == 1) { - this._downloadTicket(title.titleID, () => { - if (this.getTIDType(title.titleID) == '0000') { - cache.push(title); - } - callback(); - }); - } else if (fs.pathExistsSync(path.join(this._config.ticket_cache_folder, title.titleID + '.tik'))) { - let size = fs.statSync(path.join(this._config.ticket_cache_folder, title.titleID + '.tik')).size; - if (size < 172) { // 172 seems to be the standard size - this._downloadTicket(title.titleID, () => { - if (this.getTIDType(title.titleID) == '0000') { - cache.push(title); - } - callback(); - }); - } else { - if (this.getTIDType(title.titleID) == '0000') { - cache.push(title); - } - callback(); - } - } else { - if (this.getTIDType(title.titleID) == '0000') { - cache.push(title); - } - callback(); - } - } else { - callback(); - } - }); - - queue.drain = () => { - self.emit('ticket_cache_downloaded', cache); - if (cb) { - cb(cache); - } - return; - } - - queue.push(titles); - }); -} - -Main.prototype.setTicketVendor = function(vendor) { - this._config.ticket_vendor = vendor; -} - -Main.prototype.setTicketCacheVendor = function(vendor) { - this._config.ticket_cache_vendor = vendor; -} - -Main.prototype.setTicketCacheLocation = function(location) { - this._config.ticket_cache_folder = location; - //this.downloadTicketCache(this._config.ticket_vendor, location); -} - -Main.prototype.setCDecryptLocation = function(location) { - let self = this; - this._config.cdecrypt_location = location; - this._config.cdecrypt_folder_location = path.join(location, '../'); - if (!this._config.cdecrypt_location || this._config.cdecrypt_location.trim() == '' || !fs.pathExistsSync(this._config.cdecrypt_location)) { - self.emit('rom_decryption_missing', location); - } -} - -Main.prototype.verifyEncryptedContents = function(location, tid, cb) { - var tmd = this.parseTMD(path.join(location, 'title.tmd')); - this._checkApplicationFiles(tmd.contents, location, tid, () => { - this._checkHashFiles(tmd.contents.filter(item => {return item.type>=8195}), location, tid, () => { - return cb(); - }); - }); -} - -Main.prototype._checkApplicationFiles = function(contents, location, tid, cb) { - var queue = async.queue((file, callback) => { - if (fs.pathExistsSync(path.join(location, file.id + '.app'))) { - var size = fs.statSync(path.join(location, file.id + '.app')).size; - if (size < file.size) { - this._ripFile(tid, this.getTIDURL(tid) + '/' + file.id, path.join(location, file.id + '.app'), () => { - callback(); - }); - } else { - callback(); - } - } else { - this._ripFile(tid, this.getTIDURL(tid) + '/' + file.id, path.join(location, file.id + '.app'), () => { - callback(); - }); - } - }); - - queue.drain = () => { - return cb(); - } - - queue.push(contents); -} - -Main.prototype._checkHashFiles = function(contents, location, tid, cb) { - var queue = async.queue((file, callback) => { - if (fs.pathExistsSync(path.join(location, file.id + '.h3'))) { - var size = fs.statSync(path.join(location, file.id + '.h3')).size; - this._getHeaders(this.getTIDURL(tid) + '/' + file.id + '.h3', (headers) => { - if (size < headers['content-length']) { - this._ripFile(tid, this.getTIDURL(tid) + '/' + file.id + '.h3', path.join(location, file.id + '.h3'), () => { - callback(); - }); - } else { - callback(); - } - }); - } else { - this._ripFile(tid, this.getTIDURL(tid) + '/' + file.id + '.h3', path.join(location, file.id + '.h3'), () => { - callback(); - }); - } - }); - - queue.drain = () => { - return cb(); - } - - queue.push(contents); -} - -Main.prototype.downloadTID = function(TID, location, update, cb) { - let self = this, - cache = fs.readJSONSync(path.join(this._config.ticket_cache_folder, '_cache.json')); - TID = this.formatTID(TID); - fs.ensureDirSync(location); - - if (this.CANCEL_LIST.contains(TID)) { - this.CANCEL_LIST.splice(this.CANCEL_LIST.indexOf(TID), 1); - } - - fs.createReadStream(path.join(LOCAL_RESOURCES_ROOT, 'uni.cert')).pipe(fs.createWriteStream(path.join(location, 'title.cert'))); - - this.downloadTMD(TID, path.join(location, 'title.tmd'), update, () => { - self.emit('downloaded_tmd', TID); - let tmd = this.parseTMD(path.join(location, 'title.tmd')), - URL_BASE = this.getTIDURL(TID); - - if (fs.pathExistsSync(path.join(this._config.ticket_cache_folder, TID.toLowerCase() + '.tik'))) { - fs.createReadStream(path.join(this._config.ticket_cache_folder, TID.toLowerCase() + '.tik')) - .pipe(fs.createWriteStream(path.join(location, 'title.tik'))); - } else if (this.getTIDType(TID) == '000E') { - let URL_BASE = this.getTIDURL(TID); - this._ripFile(tid, URL_BASE + '/cetk', path.join(location, 'title.tik'), (error) => { - self.emit('downloaded_ticket', TID); - }); - } else { - for (var i=0;i= 8195) { - tmd_total_size += 20; - } - } - - console.log(tmd_total_size) - - self.emit('download_total_size', { - tid: TID, - size: tmd_total_size - }); - - var queue = async.queue((file, callback) => { - - if (this.CANCEL_LIST.contains(TID)) { - console.log('KILLED'); - queue.kill(); - } - - if (fs.pathExistsSync(path.join(location, file.id + '.app'))) { - var size = fs.statSync(path.join(location, file.id + '.app')).size; - if (size < file.size) { - this._ripFile(TID, URL_BASE + '/' + file.id, path.join(location, file.id + '.app'), () => { - if (file.type >= 8195) { - this._ripFile(TID, URL_BASE + '/' + file.id + '.h3', path.join(location, file.id + '.h3'), (error) => { - return callback(); - }); - } else { - return callback(); - } - }); - } else { - self.emit('download_status', { - status: 'exists', - tid: TID, - name: file.id + '.app', - path: path.join(location, file.id + '.app'), - received_bytes: size, - received_bytes_raw: size, - total_bytes: size - }); - if (file.type >= 8195) { - this._ripFile(TID, URL_BASE + '/' + file.id + '.h3', path.join(location, file.id + '.h3'), (error) => { - return callback(); - }); - } else { - return callback(); - } - } - } else { - this._ripFile(TID, URL_BASE + '/' + file.id, path.join(location, file.id + '.app'), () => { - if (file.type >= 8195) { - this._ripFile(TID, URL_BASE + '/' + file.id + '.h3', path.join(location, file.id + '.h3'), (error) => { - return callback(); - }); - } else { - return callback(); - } - }); - } - }); - - queue.drain = () => { - self.emit('rom_rip_completed', location); - if (cb) { - return cb(location); - } - } - - queue.push(tmd.contents); - }); -} - -Main.prototype.downloadTMD = function(TID, file, update, cb) { - TID = this.formatTID(TID); - let tmd_url = this.getTIDURL(TID) + '/tmd'; - if (update) tmd_url = tmd_url.concat('.', update); - console.log(tmd_url) - this._ripFile(TID, tmd_url, file, () => { - return cb(); - }); -} - -Main.prototype._downloadTicket = function(tid, cb) { - let ticket_url = this._config.ticket_vendor + '/ticket/' + tid + '.tik'; - ticket_url = ticket_url.replace(/([^:]\/)\/+/g, '$1'); - - request(ticket_url) - .pipe(fs.createWriteStream(path.join(this._config.ticket_cache_folder, tid + '.tik'))) - .on('error', () => { - console.log('ERROR', tid) - return cb(); - }) - .on('finish', () => { - return cb(); - }); -} - -Main.prototype._ripFile = function(TID, url, file, cb) { - let self = this, - files = file.split('\\'); - - this._getHeaders(url, (headers) => { - if (fs.pathExistsSync(file)) { - var size = fs.statSync(file).size; - if (size >= headers['content-length']) { - self.emit('download_status', { - status: 'exists', - tid: TID, - name: files[files.length-1], - path: file, - received_bytes: size, - received_bytes_raw: size, - total_bytes: size - }); - return cb(); - } - } - - let received_bytes = 0, - total_bytes = headers['content-length'], - req = request.get(url); - - req.on('response', (response) => { - if (response.statusCode !== 200) { - if (response.statusCode == 404) { - console.log(file); - return cb(); - } - console.log(url); - console.log(file); - console.log(response.statusCode) - throw new Error('Invalid response code', response.statusCode); - } else { - self.emit('download_status', { - status: 'started', - tid: TID, - name: files[files.length-1], - path: file, - received_bytes: 0, - received_bytes_raw: 0, - total_bytes: headers['content-length'] - }); - - var out = fs.createWriteStream(file); - req.pipe(out); - - out.on('finish', () => { - self.emit('download_status', { - status: 'finished', - tid: TID, - name: files[files.length-1], - path: file, - received_bytes: received_bytes, - received_bytes_raw: 0, - total_bytes: total_bytes - }); - out.close(cb); - }); - - out.on('error', (error) => { - console.log(error); - console.log(error.message); - console.log(url); - console.log(file); - throw error - }); - - req.on('data', (chunk) => { - - if (this.CANCEL_LIST.contains(TID)) { - console.log('KILLED'); - req.abort(); - req.destroy(); - } - - received_bytes += chunk.length; - self.emit('download_status', { - status: 'downloading', - tid: TID, - name: files[files.length-1], - path: file, - chunk_length: chunk.length, - received_bytes: received_bytes, - received_bytes_raw: chunk.length, - total_bytes: total_bytes - }); - }); - - req.on('error', (error) => { - console.log(error); - console.log(error.message); - console.log(url); - console.log(file); - throw error; - }); - } - }); - }); -} - -Main.prototype._stringToBin = function(string) { - var return_string = ''; - for (var i=0; i -1; -} \ No newline at end of file diff --git a/app.js b/app.js index 5e59a8e..27fa320 100644 --- a/app.js +++ b/app.js @@ -31,6 +31,7 @@ let electron = require('electron'), request = require('request'), ws = require('windows-shortcuts'), winston = require('winston'), + Menu = electron.Menu, notifications = electron.Notification, dialog = electron.dialog, shell = electron.shell, @@ -291,16 +292,22 @@ function createWindow(file) { ApplicationWindow.on('closed', () => { ApplicationWindow = null; }); + + ApplicationWindow.webContents.on('new-window', function(event, url) { + event.preventDefault(); + electron.shell.openExternal(url); + }); + + require('./context.js'); + } app.on('ready', () => { - updater.checkForUpdates() + updater.checkForUpdates(); createWindow('index'); + //ApplicationWindow.webContents.openDevTools(); - ApplicationWindow.webContents.on('new-window', function(event, url) { - event.preventDefault(); - electron.shell.openExternal(url); - }); + }) @@ -1705,25 +1712,25 @@ function isGame(game_path) { var stats = fs.lstatSync(game_path); if (!stats) return false; - if (stats.isSymbolicLink()) { - var link = fs.readlinkSync(game_path), - subfolders = fs.readdirSync(link); - if (subfolders.contains('code') && subfolders.contains('content')) { - if (subfolders.contains('meta') && fs.pathExistsSync(game_path + '/meta/meta.xml')) { - var rom = fs.readdirSync(game_path + '/code').filter(/./.test, /\.rpx$/i); - if (!rom || rom.length < 0) return false; - } else if (fs.pathExistsSync(game_path + '/code/app.xml')) { - var rom = fs.readdirSync(game_path + '/code').filter(/./.test, /\.rpx$/i); - if (!rom || rom.length < 0) return false; - } else return false; - } else return false; - } else if (stats.isDirectory()) { - var subfolders = fs.readdirSync(game_path); + if (stats.isSymbolicLink() || stats.isDirectory()) { + let subfolders; + if (stats.isSymbolicLink()) { + subfolders = fs.readdirSync(fs.readlinkSync(game_path)); + } else { + subfolders = fs.readdirSync(game_path); + } + if (subfolders.contains('code') && subfolders.contains('content')) { if (subfolders.contains('meta') && fs.pathExistsSync(game_path + '/meta/meta.xml')) { + let xml = XMLParser.parse(game_path + '/meta/meta.xml'); + if (NUSRipper.getTIDType(xml.title_id) != '0000') return false; + var rom = fs.readdirSync(game_path + '/code').filter(/./.test, /\.rpx$/i); if (!rom || rom.length < 0) return false; } else if (fs.pathExistsSync(game_path + '/code/app.xml')) { + let xml = XMLParser.parse(game_path + '/code/app.xml'); + if (NUSRipper.getTIDType(xml.title_id) != '0000') return false; + var rom = fs.readdirSync(game_path + '/code').filter(/./.test, /\.rpx$/i); if (!rom || rom.length < 0) return false; } else return false; diff --git a/app/wrapper/js/main.js b/app/wrapper/js/main.js index 4fb5bc6..97727c3 100644 --- a/app/wrapper/js/main.js +++ b/app/wrapper/js/main.js @@ -235,6 +235,7 @@ function toggleGAMES() { setTimeout(function () { var el = document.getElementById('dl'); el.style.display = 'none'; + window.location.reload(true); },500); return; } diff --git a/context.js b/context.js new file mode 100644 index 0000000..2db7775 --- /dev/null +++ b/context.js @@ -0,0 +1,71 @@ +const {Menu, shell} = require('electron') +const electron = require('electron') +const app = electron.app + +const template = [ + { + label: 'View', + submenu: [ + { + label: 'Reload', + accelerator: 'CmdOrCtrl+R', + click (item, focusedWindow) { + if (focusedWindow) { + focusedWindow.reload(); + } + } + }, + { + label: 'Toggle Dev Tools', + accelerator: 'Ctrl+Shift+I', + click (item, focusedWindow) { + if (focusedWindow) { + focusedWindow.webContents.toggleDevTools() + } + } + }, + { type: 'separator' }, + { role: 'resetzoom' }, + { type: 'separator' }, + { role: 'togglefullscreen' } + ] + }, + { + role: 'help', + submenu: [ + { + label: 'Cemu', + click () { + shell.openExternal('http://cemu.info/') + } + }, + { + label: 'CemUI', + click () { + shell.openExternal('http://cemui.com/') + } + }, + { + label: 'Cemu Compatibility List', + click () { + shell.openExternal('http://compat.cemu.info/') + } + }, + { + label: 'SMMDB', + click () { + shell.openExternal('https://smmdb.ddns.net/') + } + }, + { + label: 'Cemu Graphics Packs', + click () { + shell.openExternal('https://github.com/slashiee/cemu_graphic_packs') + } + } + ] + } +] + +const menu = Menu.buildFromTemplate(template) +Menu.setApplicationMenu(menu) \ No newline at end of file diff --git a/ico.png b/ico.png index aa9a6be04c79c752996ba6fa501952990aefc5ba..8c634c3532eb8d2ca3cbcd8da17b0ac81650c35e 100644 GIT binary patch literal 7880 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 literal 30139 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
b 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