├── Screenshots ├── NXRG-main.jpg ├── NXRG-titles.jpg └── NXRG-download.jpg ├── Sample - Download.txt ├── README.md ├── LICENSE └── main.py /Screenshots/NXRG-main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hotshotz79/NX-RomGet/HEAD/Screenshots/NXRG-main.jpg -------------------------------------------------------------------------------- /Screenshots/NXRG-titles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hotshotz79/NX-RomGet/HEAD/Screenshots/NXRG-titles.jpg -------------------------------------------------------------------------------- /Screenshots/NXRG-download.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hotshotz79/NX-RomGet/HEAD/Screenshots/NXRG-download.jpg -------------------------------------------------------------------------------- /Sample - Download.txt: -------------------------------------------------------------------------------- 1 | Rom Name (USA);http://link.com/romname.zip 2 | Make up name;http://madeuplink.com/romname2.zip 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NX-RomGet 2 | 3 | Download ROMs directly on the switch from user provided list (.txt) 4 | 5 | Requires: [PyNx](https://github.com/nx-python/Pynx) 6 | 7 | **Touch** support only 8 | 9 | # Guide: 10 | 11 | 1. Download PyNx and extract to sdmc:/switch/PyNx 12 | 2. Download NX-RomGet (main.py) and overwrite PyNx main.py 13 | 3. Create txt files in the PyNx folder in the following way 14 | 15 | (a) File name will determine where to save ROMs 16 | Ex; "Sega - Genesis.txt" will save ROMs from that list under sdmc:/Roms/Sega - Genesis/ 17 | 18 | (b) Each row will include name and download link separate by semi colon 19 | Ex; "Sonic 3 (USA);http://link.com/Sonic3.zip" 20 | 21 | **NOTE:** HTTPS link will give error, so try to rename to HTTP 22 | 23 | # Screenshots: 24 | 25 | ![Main screen](Screenshots/NXRG-main.jpg) 26 | 27 | ![Title screen](Screenshots/NXRG-titles.jpg) 28 | 29 | ![Download screen](Screenshots/NXRG-download.jpg) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 hotshotz79 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import imgui 2 | import imguihelper 3 | import os 4 | import _nx 5 | import runpy 6 | import sys 7 | from imgui.integrations.nx import NXRenderer 8 | from nx.utils import clear_terminal 9 | import time 10 | import urllib.request 11 | import urllib.parse 12 | import zipfile 13 | 14 | sys.argv = [""] # workaround needed for runpy 15 | 16 | def colorToFloat(t): 17 | nt = () 18 | for v in t: 19 | nt += ((1/255) * v, ) 20 | return nt 21 | 22 | # (r, g, b) 23 | FOLDER_COLOR = colorToFloat((230, 126, 34)) 24 | PYFILE_COLOR = colorToFloat((46, 204, 113)) 25 | FILE_COLOR = colorToFloat((41, 128, 185)) 26 | C_RED = (0.9, 0.0, 0.1) 27 | C_ORANGE = (0.9, 0.4, 0.0) 28 | C_YELLOW = (0.8, 0.9, 0.0) 29 | C_LIME = (0.5, 0.9, 0.0) 30 | C_GREEN = (0.0, 0.9, 0.2) 31 | C_AQUA = (0.0, 0.9, 0.6) 32 | C_BLUE = (0.0, 0.5, 0.9) 33 | C_NAVY = (0.2, 0.0, 0.9) 34 | C_PURPLE = (0.6, 0.0, 0.9) 35 | C_PINK = (0.9, 0.0, 0.8) 36 | 37 | TILED_DOUBLE = 1 38 | 39 | # Progress Bar--------------------------------------- 40 | def reporthook(count, block_size, total_size): 41 | global start_time 42 | if count == 0: 43 | start_time = time.time() 44 | return 45 | duration = time.time() - start_time 46 | progress_size = int(count * block_size) 47 | speed = int(progress_size / (1024 * duration)) 48 | percent = min(int(count*block_size*100/total_size),100) 49 | sys.stdout.write("\r...%d%%, %d / %d MB, %d KB/s, %d seconds passed" % 50 | (percent, progress_size / (1024 * 1024), total_size / (1024 * 1024), speed, duration)) 51 | #sys.stdout.write("\rPercent: %d%% | Downloaded: %d of %d MB | Speed: %d KB/s | Elapsed Time: %d seconds" % 52 | # (percent, progress_size / (1024 * 1024), total_size / (1024 * 1024), speed, duration)) 53 | sys.stdout.flush() 54 | 55 | # Start Download------------------------------------- 56 | def start(filename, url, consolefolder, extract): 57 | # clear both buffers 58 | imguihelper.clear() 59 | _nx.gfx_set_mode(TILED_DOUBLE) 60 | clear_terminal() 61 | 62 | full_file = urllib.parse.unquote(url.split('/')[-1]) 63 | # zippath = filename + ".zip" 64 | print("-------------------------------------------------------------------------------") 65 | print("\n _ _ __ __ ______ _____ _ " + 66 | "\n | \ | |\ \ / / | ___ \ | __ \ | | " + 67 | "\n | \| | \ V /______| |_/ /___ _ __ ___ | | \/ ___| |_ " + 68 | "\n | . ` | / \______| // _ \| '_ ` _ \| | __ / _ \ __|" + 69 | "\n | |\ |/ /^\ \ | |\ \ (_) | | | | | | |_\ \ __/ |_ " + 70 | "\n \_| \_/\/ \/ \_| \_\___/|_| |_| |_|\____/\___|\__|") 71 | print("\n-------------------------------------------------------------------------------\n") 72 | print("\n[Rom Selected] " + filename) 73 | print("\n[Download Path] sdmc:/Roms/" + consolefolder + "/") 74 | print("\n-------------------------------------------------------------------------------\n") 75 | print("Download Progress:\n") 76 | urllib.request.urlretrieve(url, "sdmc:/Roms/" + consolefolder + "/" + full_file, reporthook) 77 | print("\n\n File Downloaded") 78 | 79 | # Extraction Section 80 | if full_file.endswith(".zip"): 81 | if extract: 82 | print("\n-------------------------------------------------------------------------------\n") 83 | print("\n[Extraction Path] sdmc:/Roms/" + consolefolder + "/" + filename + "/") 84 | print("Extraction Progress:\n") 85 | path_to_extract = "sdmc:/Roms/" + consolefolder + "/" + filename 86 | zf = zipfile.ZipFile("sdmc:/Roms/" + consolefolder + "/" + zippath) 87 | uncompress_size = sum((file.file_size for file in zf.infolist())) 88 | extracted_size = 0 89 | 90 | i = len(zf.infolist()) 91 | x = 1 92 | 93 | for file in zf.infolist(): 94 | extracted_size += file.file_size 95 | print("Extracting " + str(x) + " of " + str(i) + ": " + file.filename + " | Size: " + str(file.file_size / 1000000)[0:5] + " MB | Progress: " + str((extracted_size * 100/uncompress_size))[0:3] + "%") 96 | zf.extractall(path_to_extract) 97 | x += 1 98 | 99 | imguihelper.initialize() 100 | 101 | # DISPLAY ROMS--------------------------------------- 102 | def romList(console_selected): 103 | # clear both buffers 104 | imguihelper.clear() 105 | _nx.gfx_set_mode(TILED_DOUBLE) 106 | clear_terminal() 107 | imguihelper.initialize() 108 | 109 | renderer = NXRenderer() 110 | checkbox_extract = False 111 | 112 | while True: 113 | renderer.handleinputs() 114 | 115 | imgui.new_frame() 116 | 117 | width, height = renderer.io.display_size 118 | imgui.set_next_window_size(width, height) 119 | imgui.set_next_window_position(0, 0) 120 | imgui.begin("", 121 | flags=imgui.WINDOW_NO_TITLE_BAR | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_SAVED_SETTINGS 122 | ) 123 | imgui.set_window_font_scale(1.2) 124 | imgui.text(console_selected.upper()) 125 | 126 | # TODO 127 | # ADD Checkbox for "Delete ZIP after Extract" 128 | 129 | # Create Selected Systems Directory 130 | directory = console_selected 131 | parent_dir = "sdmc:/Roms" 132 | path = os.path.join(parent_dir, directory) 133 | try: 134 | os.makedirs(path, exist_ok = True) 135 | except OSError as error: 136 | print("Directory '%s' can not be created" % directory) 137 | 138 | button_number = 0 139 | imgui.separator() 140 | imgui.new_line() 141 | 142 | # Go Back 143 | imgui.push_style_color(imgui.COLOR_BUTTON, *FOLDER_COLOR) 144 | if imgui.button("GO BACK", width=288, height=60): 145 | main() 146 | imgui.pop_style_color(1) 147 | 148 | # Checkbox for Extracting 149 | imgui.same_line(spacing=50) 150 | _, checkbox_extract = imgui.checkbox("EXTRACT .ZIP AFTER DOWNLOAD", checkbox_extract) 151 | 152 | imgui.new_line() 153 | 154 | imgui.separator() 155 | 156 | firstRow = True; 157 | txtFile = console_selected + ".txt" 158 | file = open(txtFile,"r") 159 | 160 | # Generate button for each record found 161 | for line in file: 162 | fields = line.split(";") 163 | title = fields[0] 164 | link = fields[1] 165 | 166 | if button_number == 4: 167 | imgui.new_line() 168 | button_number = 0 169 | else: 170 | imgui.same_line() 171 | 172 | if firstRow == True: 173 | imgui.new_line() 174 | firstRow = False 175 | 176 | imgui.push_style_color(imgui.COLOR_BUTTON, *FILE_COLOR) 177 | if imgui.button(title.upper(), width=288, height=60): 178 | start(title, link, console_selected, checkbox_extract) 179 | 180 | imgui.pop_style_color(1) 181 | 182 | button_number += 1 183 | 184 | file.close() 185 | 186 | imgui.end() 187 | 188 | imgui.render() 189 | renderer.render() 190 | 191 | renderer.shutdown() 192 | 193 | 194 | # MAIN----------------------------------------------- 195 | def main(): 196 | renderer = NXRenderer() 197 | currentDir = os.getcwd() 198 | 199 | while True: 200 | renderer.handleinputs() 201 | 202 | imgui.new_frame() 203 | 204 | width, height = renderer.io.display_size 205 | imgui.set_next_window_size(width, height) 206 | imgui.set_next_window_position(0, 0) 207 | imgui.begin("", 208 | flags=imgui.WINDOW_NO_TITLE_BAR | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_SAVED_SETTINGS 209 | ) 210 | imgui.set_window_font_scale(2.0) 211 | imgui.text("NX-RomGet (ver 0.1)") 212 | 213 | # Create ROMS folder if it doesnt exist 214 | directory = "Roms" 215 | parent_dir = "sdmc:/" 216 | path = os.path.join(parent_dir, directory) 217 | try: 218 | os.makedirs(path, exist_ok = True) 219 | except OSError as error: 220 | print("Directory '%s' can not be created" % directory) 221 | 222 | # ------------- COLORS ------------- 223 | # C_RED | C_ORANGE | C_YELLOW | C_LIME | C_GREEN 224 | # C_AQUA | C_BLUE | C_NAVY | C_PURPLE |C_PINK 225 | 226 | # Check which Console Files exist (.txt) 227 | console_files = [] 228 | for e in os.listdir(): 229 | if e.endswith(".txt"): 230 | console_files.append(e.replace(".txt", "")) 231 | console_files = sorted(console_files) 232 | 233 | btn_number = 0 234 | starting_row = True; 235 | 236 | # Generate buttons for each Console File found 237 | for e in console_files: 238 | 239 | if btn_number == 3: 240 | imgui.new_line() 241 | btn_number = 0 242 | else: 243 | imgui.same_line() 244 | 245 | if starting_row == True: 246 | imgui.new_line() 247 | starting_row = False 248 | 249 | if e.startswith("Nintendo"): 250 | imgui.push_style_color(imgui.COLOR_BUTTON, *C_RED) 251 | elif e.startswith("Sega"): 252 | imgui.push_style_color(imgui.COLOR_BUTTON, *C_NAVY) 253 | elif e.startswith("Sony"): 254 | imgui.push_style_color(imgui.COLOR_BUTTON, *C_PURPLE) 255 | elif e.startswith("Final"): 256 | imgui.push_style_color(imgui.COLOR_BUTTON, *C_GREEN) 257 | else: 258 | imgui.push_style_color(imgui.COLOR_BUTTON, *C_ORANGE) 259 | if imgui.button(e, width=390, height=150): 260 | romList(e) 261 | imgui.pop_style_color(1) 262 | 263 | btn_number += 1 264 | 265 | #------------------------------ 266 | 267 | imgui.end() 268 | 269 | imgui.render() 270 | renderer.render() 271 | 272 | renderer.shutdown() 273 | 274 | if __name__ == "__main__": 275 | main() 276 | --------------------------------------------------------------------------------