Allow for using the Wii U NUS for faster downloads (libWiiPy v0.2.3 beta)

This commit is contained in:
Campbell 2024-05-02 00:50:20 -04:00
parent 466f914ad9
commit 625131873b
Signed by: NinjaCheetah
GPG Key ID: B547958AF96ED344
4 changed files with 53 additions and 29 deletions

View File

@ -5,6 +5,7 @@ import sys
import os
import json
import pathlib
from importlib.metadata import version
import libWiiPy
@ -58,12 +59,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# noinspection PyUnresolvedReferences
self.ui.title_tree.header().setSectionResizeMode(QHeaderView.ResizeToContents)
# Basic intro text set to automatically show when the app loads. This may be changed in the future.
self.ui.log_text_browser.setText("NUSGet v1.0\nDeveloped by NinjaCheetah\nPowered by libWiiPy\n\n"
"Select a title from the list on the left, or enter a Title ID to begin.\n\n"
"Titles marked with a checkmark are free and have a ticket available, and can"
" be decrypted and packed into a WAD. Titles with an X do not have a ticket,"
" and only their encrypted contents can be saved.")
# Tree building code.
libwiipy_version = "v" + version("libWiiPy")
self.ui.log_text_browser.setText(f"NUSGet v1.0\nDeveloped by NinjaCheetah\nPowered by libWiiPy "
f"{libwiipy_version}\n\nSelect a title from the list on the left, or enter a "
f"Title ID to begin.\n\nTitles marked with a checkmark are free and have a "
f"ticket available, and can be decrypted and packed into a WAD. Titles with an"
f" X do not have a ticket, and only their encrypted contents can be saved.")
# Title tree building code.
tree = self.ui.title_tree
self.tree_categories = []
global regions
@ -79,9 +81,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
for region in title["Versions"]:
new_region = QTreeWidgetItem()
new_region.setText(0, region)
for version in title["Versions"][region]:
for title_version in title["Versions"][region]:
new_version = QTreeWidgetItem()
new_version.setText(0, "v" + str(version))
new_version.setText(0, "v" + str(title_version))
new_region.addChild(new_version)
new_title.addChild(new_region)
# Set an indicator icon to show if a ticket is offered for this title or not.
@ -177,6 +179,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.ui.keep_enc_chkbox.setEnabled(False)
self.ui.create_dec_chkbox.setEnabled(False)
self.ui.use_local_chkbox.setEnabled(False)
self.ui.use_wiiu_nus_chkbox.setEnabled(False)
self.ui.wad_file_entry.setEnabled(False)
self.log_text = ""
self.ui.log_text_browser.setText(self.log_text)
@ -230,6 +233,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.ui.keep_enc_chkbox.setEnabled(True)
self.ui.create_dec_chkbox.setEnabled(True)
self.ui.use_local_chkbox.setEnabled(True)
self.ui.use_wiiu_nus_chkbox.setEnabled(True)
if self.ui.pack_wad_chkbox.isChecked() is True:
self.ui.wad_file_entry.setEnabled(True)
@ -242,12 +246,14 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# An error here is acceptable, because it may just mean the box is empty. Or the version string is nonsense.
# Either way, just fall back on downloading the latest version of the title.
try:
version = int(self.ui.version_entry.text())
title_version = int(self.ui.version_entry.text())
except ValueError:
version = None
title_version = None
# Set variables for these two options so that their state can be compared against the user's choices later.
pack_wad_enabled = self.ui.pack_wad_chkbox.isChecked()
decrypt_contents_enabled = self.ui.create_dec_chkbox.isChecked()
# Check whether we're going to be using the "fallback" (but faster) Wii U NUS or not.
fallback_enabled = self.ui.use_wiiu_nus_chkbox.isChecked()
# Create a new libWiiPy Title.
title = libWiiPy.Title()
# Make a directory for this title if it doesn't exist.
@ -255,27 +261,27 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if not title_dir.is_dir():
title_dir.mkdir()
# Announce the title being downloaded, and the version if applicable.
if version is not None:
progress_callback.emit("Downloading title " + tid + " v" + str(version) + ", please wait...")
if title_version is not None:
progress_callback.emit("Downloading title " + tid + " v" + str(title_version) + ", please wait...")
else:
progress_callback.emit("Downloading title " + tid + " vLatest, please wait...")
progress_callback.emit(" - Downloading and parsing TMD...")
# Download a specific TMD version if a version was specified, otherwise just download the latest TMD.
try:
if version is not None:
title.load_tmd(libWiiPy.download_tmd(tid, version))
if title_version is not None:
title.load_tmd(libWiiPy.download_tmd(tid, title_version, fallback_endpoint=fallback_enabled))
else:
title.load_tmd(libWiiPy.download_tmd(tid))
version = title.tmd.title_version
title.load_tmd(libWiiPy.download_tmd(tid, fallback_endpoint=fallback_enabled))
title_version = title.tmd.title_version
# If libWiiPy returns an error, that means that either the TID or version doesn't exist, so return code -2.
except ValueError:
return -2
# Make a directory for this version if it doesn't exist.
version_dir = pathlib.Path(os.path.join(title_dir, str(version)))
version_dir = pathlib.Path(os.path.join(title_dir, str(title_version)))
if not version_dir.is_dir():
version_dir.mkdir()
# Write out the TMD to a file.
tmd_out = open(os.path.join(version_dir, "tmd." + str(version)), "wb")
tmd_out = open(os.path.join(version_dir, "tmd." + str(title_version)), "wb")
tmd_out.write(title.tmd.dump())
tmd_out.close()
# Use a local ticket, if one exists and "use local files" is enabled.
@ -286,7 +292,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
else:
progress_callback.emit(" - Downloading and parsing Ticket...")
try:
title.load_ticket(libWiiPy.download_ticket(tid))
title.load_ticket(libWiiPy.download_ticket(tid, fallback_endpoint=fallback_enabled))
ticket_out = open(os.path.join(version_dir, "tik"), "wb")
ticket_out.write(title.ticket.dump())
ticket_out.close()
@ -316,7 +322,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
progress_callback.emit(" - Downloading content " + str(content + 1) + " of " +
str(len(title.tmd.content_records)) + " (" +
str(title.tmd.content_records[content].content_size) + " bytes)...")
content_list.append(libWiiPy.download_content(tid, title.tmd.content_records[content].content_id))
content_list.append(libWiiPy.download_content(tid, title.tmd.content_records[content].content_id,
fallback_endpoint=fallback_enabled))
progress_callback.emit(" - Done!")
# If keep encrypted contents is on, write out each content after its downloaded.
if self.ui.keep_enc_chkbox.isChecked() is True:
@ -346,7 +353,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if pack_wad_enabled is True:
# Get the WAD certificate chain, courtesy of libWiiPy.
progress_callback.emit(" - Building certificate...")
title.wad.set_cert_data(libWiiPy.download_cert())
title.wad.set_cert_data(libWiiPy.download_cert(fallback_endpoint=fallback_enabled))
# Use a typed WAD name if there is one, and auto generate one based on the TID and version if there isn't.
progress_callback.emit("Packing WAD...")
if self.ui.wad_file_entry.text() != "":
@ -354,7 +361,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if wad_file_name[-4:] != ".wad":
wad_file_name = wad_file_name + ".wad"
else:
wad_file_name = tid + "-v" + str(version) + ".wad"
wad_file_name = tid + "-v" + str(title_version) + ".wad"
# Have libWiiPy dump the WAD, and write that data out.
file = open(os.path.join(version_dir, wad_file_name), "wb")
file.write(title.dump_wad())

View File

@ -24,9 +24,9 @@ class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(610, 605)
MainWindow.setMinimumSize(QSize(610, 605))
MainWindow.setMaximumSize(QSize(610, 605))
MainWindow.resize(610, 625)
MainWindow.setMinimumSize(QSize(610, 625))
MainWindow.setMaximumSize(QSize(610, 625))
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.horizontalLayout_3 = QHBoxLayout(self.centralwidget)
@ -123,6 +123,12 @@ class Ui_MainWindow(object):
self.verticalLayout_3.addWidget(self.use_local_chkbox)
self.use_wiiu_nus_chkbox = QCheckBox(self.centralwidget)
self.use_wiiu_nus_chkbox.setObjectName(u"use_wiiu_nus_chkbox")
self.use_wiiu_nus_chkbox.setChecked(True)
self.verticalLayout_3.addWidget(self.use_wiiu_nus_chkbox)
self.horizontalLayout_3.addLayout(self.verticalLayout_3)
@ -156,5 +162,6 @@ class Ui_MainWindow(object):
self.keep_enc_chkbox.setText(QCoreApplication.translate("MainWindow", u"Keep encrypted contents", None))
self.create_dec_chkbox.setText(QCoreApplication.translate("MainWindow", u"Create decrypted contents (*.app)", None))
self.use_local_chkbox.setText(QCoreApplication.translate("MainWindow", u"Use local files, if they exist", None))
self.use_wiiu_nus_chkbox.setText(QCoreApplication.translate("MainWindow", u"Use the Wii U NUS (faster, NOT vWii titles)", None))
# retranslateUi

View File

@ -7,19 +7,19 @@
<x>0</x>
<y>0</y>
<width>610</width>
<height>605</height>
<height>625</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>610</width>
<height>605</height>
<height>625</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>610</width>
<height>605</height>
<height>625</height>
</size>
</property>
<property name="windowTitle">
@ -173,6 +173,16 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_wiiu_nus_chkbox">
<property name="text">
<string>Use the Wii U NUS (faster, NOT vWii titles)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -1,4 +1,4 @@
pyside6
nuitka
libWiiPy
git+https://github.com/NinjaCheetah/libWiipy
zstandard