mirror of
https://github.com/NinjaCheetah/libWiiPy.git
synced 2025-04-26 13:21:01 -04:00
Rewrote nus.py to be functions instead of an NUSDownloader class because the class was unnecessary and made things more complex
This commit is contained in:
parent
60918f1a39
commit
ccbc2e262b
@ -12,32 +12,18 @@ from .tmd import TMD
|
|||||||
from .ticket import Ticket
|
from .ticket import Ticket
|
||||||
|
|
||||||
|
|
||||||
class NUSDownloader:
|
def download_title(title_id: str, title_version: int = None) -> Title:
|
||||||
"""
|
"""
|
||||||
An NUS Downloader class that allows for easy downloading of a title from the NUS.
|
Download an entire title and all of its contents, then load the downloaded components into a Title object for
|
||||||
|
further use. This method is NOT recommended for general use, as it has absolutely no verbosity. It is instead
|
||||||
|
recommended to call the individual download methods instead to provide more flexibility and output.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
title_id : str
|
title_id : str
|
||||||
The Title ID of the title you wish to download data for.
|
The Title ID of the title to download.
|
||||||
title_version : int, default: None
|
title_version : int, option
|
||||||
The version of the title you wish to download data for. Will assume latest if this is "None".
|
The version of the title to download. Defaults to latest if not set.
|
||||||
"""
|
|
||||||
def __init__(self, title_id: str, title_version: int = None):
|
|
||||||
self.title_id = title_id
|
|
||||||
self.title_version = title_version
|
|
||||||
# Data from the NUS
|
|
||||||
self.raw_tmd: bytes = b''
|
|
||||||
self.tmd: bytes = b''
|
|
||||||
self.cetk: bytes = b''
|
|
||||||
self.cert: bytes = b''
|
|
||||||
self.ticket: bytes = b''
|
|
||||||
self.content_list: List[bytes] = []
|
|
||||||
|
|
||||||
def download_title(self) -> Title:
|
|
||||||
"""
|
|
||||||
Download an entire title and all of its contents, then load the downloaded components into a Title object for
|
|
||||||
further use.
|
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@ -47,20 +33,28 @@ class NUSDownloader:
|
|||||||
# First, create the new title.
|
# First, create the new title.
|
||||||
title = Title()
|
title = Title()
|
||||||
# Download and load the TMD, Ticket, and certs.
|
# Download and load the TMD, Ticket, and certs.
|
||||||
title.load_tmd(self.download_tmd())
|
title.load_tmd(download_tmd(title_id, title_version))
|
||||||
title.load_ticket(self.download_ticket())
|
title.load_ticket(download_ticket(title_id))
|
||||||
title.wad.set_cert_data(self.download_cert())
|
title.wad.set_cert_data(download_cert())
|
||||||
# Download all contents
|
# Download all contents
|
||||||
title.load_content_records()
|
title.load_content_records()
|
||||||
title.content.content_list = self.download_contents(title.tmd)
|
title.content.content_list = download_contents(title_id, title.tmd)
|
||||||
# Return the completed title.
|
# Return the completed title.
|
||||||
return title
|
return title
|
||||||
|
|
||||||
def download_tmd(self) -> bytes:
|
|
||||||
|
def download_tmd(title_id: str, title_version: int = None) -> bytes:
|
||||||
"""
|
"""
|
||||||
Downloads the TMD of the Title specified in the object. Will download the latest version by default, or another
|
Downloads the TMD of the Title specified in the object. Will download the latest version by default, or another
|
||||||
version if it was manually specified in the object.
|
version if it was manually specified in the object.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
title_id : str
|
||||||
|
The Title ID of the title to download the TMD for.
|
||||||
|
title_version : int, option
|
||||||
|
The version of the TMD to download. Defaults to latest if not set.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
bytes
|
bytes
|
||||||
@ -68,10 +62,10 @@ class NUSDownloader:
|
|||||||
"""
|
"""
|
||||||
# Build the download URL. The structure is download/<TID>/tmd for latest and download/<TID>/tmd.<version> for
|
# Build the download URL. The structure is download/<TID>/tmd for latest and download/<TID>/tmd.<version> for
|
||||||
# when a specific version is requested.
|
# when a specific version is requested.
|
||||||
tmd_url = "http://ccs.shop.wii.com/ccs/download/" + self.title_id + "/tmd"
|
tmd_url = "http://ccs.shop.wii.com/ccs/download/" + title_id + "/tmd"
|
||||||
# Add the version to the URL if one was specified.
|
# Add the version to the URL if one was specified.
|
||||||
if self.title_version is not None:
|
if title_version is not None:
|
||||||
tmd_url += "." + str(self.title_version)
|
tmd_url += "." + str(title_version)
|
||||||
# Make the request.
|
# Make the request.
|
||||||
tmd_response = urllib3.request(method='GET', url=tmd_url, headers={'User-Agent': 'wii libnup/1.0'})
|
tmd_response = urllib3.request(method='GET', url=tmd_url, headers={'User-Agent': 'wii libnup/1.0'})
|
||||||
# Handle a 404 if the TID/version doesn't exist.
|
# Handle a 404 if the TID/version doesn't exist.
|
||||||
@ -79,18 +73,24 @@ class NUSDownloader:
|
|||||||
raise ValueError("The requested Title ID or TMD version does not exist. Please check the Title ID and Title"
|
raise ValueError("The requested Title ID or TMD version does not exist. Please check the Title ID and Title"
|
||||||
" version and then try again.")
|
" version and then try again.")
|
||||||
# Save the raw TMD.
|
# Save the raw TMD.
|
||||||
self.raw_tmd = tmd_response.data
|
raw_tmd = tmd_response.data
|
||||||
# Use a TMD object to load the data and then return only the actual TMD.
|
# Use a TMD object to load the data and then return only the actual TMD.
|
||||||
tmd_temp = TMD()
|
tmd_temp = TMD()
|
||||||
tmd_temp.load(self.raw_tmd)
|
tmd_temp.load(raw_tmd)
|
||||||
self.tmd = tmd_temp.dump()
|
tmd = tmd_temp.dump()
|
||||||
return self.tmd
|
return tmd
|
||||||
|
|
||||||
def download_ticket(self) -> bytes:
|
|
||||||
|
def download_ticket(title_id: str) -> bytes:
|
||||||
"""
|
"""
|
||||||
Downloads the Ticket of the Title specified in the object. This will only work if the Title ID specified is for
|
Downloads the Ticket of the Title specified in the object. This will only work if the Title ID specified is for
|
||||||
a free title.
|
a free title.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
title_id : str
|
||||||
|
The Title ID of the title to download the Ticket for.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
bytes
|
bytes
|
||||||
@ -98,21 +98,22 @@ class NUSDownloader:
|
|||||||
"""
|
"""
|
||||||
# Build the download URL. The structure is download/<TID>/cetk, and cetk will only exist if this is a free
|
# Build the download URL. The structure is download/<TID>/cetk, and cetk will only exist if this is a free
|
||||||
# title.
|
# title.
|
||||||
ticket_url = "http://ccs.shop.wii.com/ccs/download/" + self.title_id + "/cetk"
|
ticket_url = "http://ccs.shop.wii.com/ccs/download/" + title_id + "/cetk"
|
||||||
# Make the request.
|
# Make the request.
|
||||||
ticket_response = urllib3.request(method='GET', url=ticket_url, headers={'User-Agent': 'wii libnup/1.0'})
|
ticket_response = urllib3.request(method='GET', url=ticket_url, headers={'User-Agent': 'wii libnup/1.0'})
|
||||||
if ticket_response.status != 200:
|
if ticket_response.status != 200:
|
||||||
raise ValueError("The requested Title ID does not exist, or refers to a non-free title. Tickets can only"
|
raise ValueError("The requested Title ID does not exist, or refers to a non-free title. Tickets can only"
|
||||||
" be downloaded for titles that are free on the NUS.")
|
" be downloaded for titles that are free on the NUS.")
|
||||||
# Save the raw cetk file.
|
# Save the raw cetk file.
|
||||||
self.cetk = ticket_response.data
|
cetk = ticket_response.data
|
||||||
# Use a Ticket object to load only the Ticket data from cetk and return it.
|
# Use a Ticket object to load only the Ticket data from cetk and return it.
|
||||||
ticket_temp = Ticket()
|
ticket_temp = Ticket()
|
||||||
ticket_temp.load(self.cetk)
|
ticket_temp.load(cetk)
|
||||||
self.ticket = ticket_temp.dump()
|
ticket = ticket_temp.dump()
|
||||||
return self.ticket
|
return ticket
|
||||||
|
|
||||||
def download_cert(self) -> bytes:
|
|
||||||
|
def download_cert() -> bytes:
|
||||||
"""
|
"""
|
||||||
Downloads the signing certificate used by all WADs. This uses System Menu 4.3U as the source.
|
Downloads the signing certificate used by all WADs. This uses System Menu 4.3U as the source.
|
||||||
|
|
||||||
@ -135,18 +136,21 @@ class NUSDownloader:
|
|||||||
# XS data.
|
# XS data.
|
||||||
cert_data.write(cetk[0x2A4:0x2A4 + 768])
|
cert_data.write(cetk[0x2A4:0x2A4 + 768])
|
||||||
cert_data.seek(0x0)
|
cert_data.seek(0x0)
|
||||||
self.cert = cert_data.read()
|
cert = cert_data.read()
|
||||||
# Since the cert is always the same, check the hash to make sure nothing went wildly wrong.
|
# Since the cert is always the same, check the hash to make sure nothing went wildly wrong.
|
||||||
if hashlib.sha1(self.cert).hexdigest() != "ace0f15d2a851c383fe4657afc3840d6ffe30ad0":
|
if hashlib.sha1(cert).hexdigest() != "ace0f15d2a851c383fe4657afc3840d6ffe30ad0":
|
||||||
raise Exception("An unknown error has occurred downloading and creating the certificate.")
|
raise Exception("An unknown error has occurred downloading and creating the certificate.")
|
||||||
return self.cert
|
return cert
|
||||||
|
|
||||||
def download_content(self, content_id) -> bytes:
|
|
||||||
|
def download_content(title_id: str, content_id: int) -> bytes:
|
||||||
"""
|
"""
|
||||||
Downloads a specified content for the title specified in the object.
|
Downloads a specified content for the title specified in the object.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
title_id : str
|
||||||
|
The Title ID of the title to download content from.
|
||||||
content_id : int
|
content_id : int
|
||||||
The Content ID of the content you wish to download.
|
The Content ID of the content you wish to download.
|
||||||
|
|
||||||
@ -159,7 +163,7 @@ class NUSDownloader:
|
|||||||
content_id_hex = hex(content_id)[2:]
|
content_id_hex = hex(content_id)[2:]
|
||||||
if len(content_id_hex) < 2:
|
if len(content_id_hex) < 2:
|
||||||
content_id_hex = "0" + content_id_hex
|
content_id_hex = "0" + content_id_hex
|
||||||
content_url = "http://ccs.shop.wii.com/ccs/download/" + self.title_id + "/000000" + content_id_hex
|
content_url = "http://ccs.shop.wii.com/ccs/download/" + title_id + "/000000" + content_id_hex
|
||||||
# Make the request.
|
# Make the request.
|
||||||
content_response = urllib3.request(method='GET', url=content_url, headers={'User-Agent': 'wii libnup/1.0'})
|
content_response = urllib3.request(method='GET', url=content_url, headers={'User-Agent': 'wii libnup/1.0'})
|
||||||
if content_response.status != 200:
|
if content_response.status != 200:
|
||||||
@ -168,13 +172,16 @@ class NUSDownloader:
|
|||||||
content_id_hex)
|
content_id_hex)
|
||||||
return content_response.data
|
return content_response.data
|
||||||
|
|
||||||
def download_contents(self, tmd: TMD) -> List[bytes]:
|
|
||||||
|
def download_contents(title_id: str, tmd: TMD) -> List[bytes]:
|
||||||
"""
|
"""
|
||||||
Downloads all the contents for the title specified in the object. This requires a TMD to already be available
|
Downloads all the contents for the title specified in the object. This requires a TMD to already be available
|
||||||
so that the content records can be accessed.
|
so that the content records can be accessed.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
title_id : str
|
||||||
|
The Title ID of the title to download content from.
|
||||||
tmd : TMD
|
tmd : TMD
|
||||||
The TMD that matches the title that the contents being downloaded are from.
|
The TMD that matches the title that the contents being downloaded are from.
|
||||||
|
|
||||||
@ -190,8 +197,9 @@ class NUSDownloader:
|
|||||||
for content_record in content_records:
|
for content_record in content_records:
|
||||||
content_ids.append(content_record.content_id)
|
content_ids.append(content_record.content_id)
|
||||||
# Iterate over that list and download each content in it, then add it to the array of contents.
|
# Iterate over that list and download each content in it, then add it to the array of contents.
|
||||||
|
content_list = []
|
||||||
for content_id in content_ids:
|
for content_id in content_ids:
|
||||||
# Call self.download_content() for each Content ID.
|
# Call self.download_content() for each Content ID.
|
||||||
content = self.download_content(content_id)
|
content = download_content(title_id, content_id)
|
||||||
self.content_list.append(content)
|
content_list.append(content)
|
||||||
return self.content_list
|
return content_list
|
||||||
|
Loading…
x
Reference in New Issue
Block a user