Initial parallelization attempt

This commit is contained in:
Oracle 2026-05-19 17:41:17 +02:00
parent 12c05afa57
commit 35e49044f1
Signed by: Oracle
SSH key fingerprint: SHA256:x4/RtnjUyuHkdvmwNDsWSfcfF1V5PNr3OpriZqOvCX8
10 changed files with 321 additions and 143 deletions

View file

@ -26,6 +26,7 @@ import zlib
import shutil
import requests
from bs4 import BeautifulSoup
from typing import Any, Optional
try:
@ -44,23 +45,25 @@ GET_IRD_NET_LOC = 'http://jonnysp.bplaced.net/ird/'
# Utility functions
def to_int(data, byteorder='big'):
def to_int(data: bytes, byteorder: str = 'big') -> int:
"""Convert bytes to integer"""
if isinstance(data, bytes):
return int.from_bytes(data, byteorder)
return 0
def to_bytes(data):
def to_bytes(data: str) -> Optional[bytes]:
"""Convert a string of HEX to bytes"""
if isinstance(data, str):
return bytes(bytearray.fromhex(data))
return None
ISO_SECRET = to_bytes("380bcf0b53455b3c7817ab4fa3ba90ed")
ISO_IV = to_bytes("69474772af6fdab342743aefaa186287")
def size(path):
def size(path: str) -> int:
"""Get size of a file or block device in bytes"""
pathstat = os.stat(path)
@ -74,7 +77,7 @@ def size(path):
return pathstat.st_size
def read_seven_bit_encoded_int(fileobj, order):
def read_seven_bit_encoded_int(fileobj, order: str) -> int:
"""Read an Int32, 7 bits at a time."""
# The highest bit of the byte, when on, means to continue reading more bytes.
count = 0
@ -90,27 +93,27 @@ def read_seven_bit_encoded_int(fileobj, order):
return count
def error(msg):
def error(msg: str) -> None:
"""Print fatal error message and terminate"""
print('[ERROR] %s' % msg, file=sys.stderr)
print(f'[ERROR] {msg}', file=sys.stderr)
sys.exit(1)
def warning(msg, args):
def warning(msg: str, args) -> None:
"""Print a warning message. Warning messages can be silenced with --quiet"""
if not args.quiet:
print('[WARNING] %s. Continuing regardless.' % msg, file=sys.stderr)
print(f'[WARNING] {msg}. Continuing regardless.', file=sys.stderr)
def vprint(msg, args):
def vprint(msg: str, args) -> None:
"""Vprint, verbose print, can be silenced with --quiet"""
if not args.quiet:
print('[*] ' + msg)
print(f'[*] {msg}')
def download_ird(ird_name):
def download_ird(ird_name: str) -> None:
"""Download an .ird from GET_IRD_NET_LOC"""
# Check if file already exists and skip if it does
@ -118,14 +121,14 @@ def download_ird(ird_name):
return
ird_link = GET_IRD_NET_LOC + ird_name
r = requests.get(ird_link, stream=True)
r = requests.get(ird_link, stream=True, timeout=30)
with open(ird_name, 'wb') as ird_file:
r.raw.decode_content = True
shutil.copyfileobj(r.raw, ird_file)
def ird_by_game_id(game_id):
def ird_by_game_id(game_id: str) -> Optional[str]:
"""Using a game_id, download the responding .ird from ALL_IRD_NET_LOC"""
gameid = game_id.replace('-', '')
try:
@ -148,26 +151,28 @@ def ird_by_game_id(game_id):
return (ird_name)
def crc32(filename, keep_going=[True]):
def crc32(filename: str, keep_going: Optional[list] = None) -> Optional[str]:
"""Calculate crc32 for file"""
if keep_going is None:
keep_going = [True]
with open(filename, 'rb') as infile:
crc32 = 0
crc_val = 0
while keep_going[0] == True:
while keep_going[0] is True:
data = infile.read(65536)
if not data:
break
crc32 = zlib.crc32(data, crc32)
crc_val = zlib.crc32(data, crc_val)
if keep_going[0] == False:
if keep_going[0] is False:
return None
return "%08X" % (crc32 & 0xFFFFFFFF)
return f"{crc_val & 0xFFFFFFFF:08X}"
def serial_country(title):
def serial_country(title: str) -> str:
"""Get country from disc serial / productcode / title_id"""
if title[2] == 'A':
@ -188,7 +193,7 @@ def serial_country(title):
raise ValueError('Unknown country?!')
def multiman_title(title):
def multiman_title(title: str) -> str:
"""Fix special characters in title for Multiman style"""
replace = {
@ -206,7 +211,7 @@ def multiman_title(title):
# Main functions
def info(args):
def info(args: Any) -> None:
"""Print information about .iso and then quit."""
if args.iso:
@ -220,7 +225,7 @@ def info(args):
sys.exit()
def decrypt(args):
def decrypt(args: Any) -> None:
"""Try to decrypt a given .iso using relevant .ird or encryption key from argparse
If no .ird is given this will try to automatically download an .ird file with the encryption/decryption key for the given game .iso
@ -232,7 +237,7 @@ def decrypt(args):
input_iso.decrypt(args)
def encrypt(args):
def encrypt(args: Any) -> None:
"""Try to re-encrypt a decrypted .iso using relevant .ird or encryption key from argparse
If no .ird is given this will try to automatically download an .ird file with the encryption/decryption key for the given game .iso