From c41c1e2ee5f52f17a307306960c26b80ba66dcf9 Mon Sep 17 00:00:00 2001 From: Farewell_ Date: Mon, 20 Nov 2023 12:31:57 +0100 Subject: [PATCH] Added sortAlphabetically.py Cleaned the other scripts a bit, added more details in readme. --- README.md | 30 ++++++-- checkDatatables.py | 84 +++++--------------- helpers.py | 74 ++++++++++++++++++ sortAlphabetically.py | 174 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 290 insertions(+), 72 deletions(-) create mode 100644 helpers.py create mode 100644 sortAlphabetically.py diff --git a/README.md b/README.md index ad9d673..7ff338f 100644 --- a/README.md +++ b/README.md @@ -28,20 +28,38 @@ class Keys(Enum): you also need to install the pip module `cryptography`: > pip install cryptography -here's some examples : +here's some usage examples : ```py # Display the help message -py .\encryption.py --help +py encryption.py --help # Decrypting a datatable : -py .\encryption.py --input "data.bin" --output "data.json" +py encryption.py --input "data.bin" --output "data.json" # Encrypting a datatable : -py .\encryption.py --enc --input "data.json" --output "data.bin" +py encryption.py --enc --input "data.json" --output "data.bin" # Encrypting a fumen for use in CHN : -py .\encryption.py --enc --fumen --input "data_e.bin" --output "data_e.bin" +py encryption.py --enc --fumen --input "data_e.bin" --output "data_e.bin" +``` + +## sortAlphabetically.py + +This script generates an alphabetically sorted music_order.bin file for a given language. +Possible languages are : japaneseText, englishUsText, chineseTText, chineseSText and koreanText + +Here's some usage examples : + +```py +# Display the help message +py sortAlphabetically.py --help + +# Sort file by english name +py sortAlphabetically.py --language "englishUsText" + +# Restore a backup of the original music_order file +py sortAlphabetically.py --restore ``` ## checkDatatables.py @@ -58,6 +76,6 @@ This script generates a comprehensive list of various informations regarding you To run this one you simply need to call it like so: -> py .\checkDatatables.py +> py checkDatatables.py The output will be written in a file named `checks.json` diff --git a/checkDatatables.py b/checkDatatables.py index 344ab1c..c8048be 100644 --- a/checkDatatables.py +++ b/checkDatatables.py @@ -4,6 +4,15 @@ from encryption import decrypt_file import json import os +from helpers import ( + doesPathExist, + findAllObjects, + findDoubloninList, + findKeyInList, + isChn, + loadFile, +) + # "japaneseText" # "englishUsText" # "chineseTText" @@ -11,73 +20,16 @@ import os # "chineseSText" language = "englishUsText" -isCHN = False +isChn = isChn() # region Loading files checkFile = {} -# Loading musicinfo.bin -try: - infos = json.load(gzip.open("./Data/x64/datatable/musicinfo.bin", "rb"))["items"] -except: - try: - infos = json.loads( - decrypt_file(input_file="./Data/x64/datatable/musicinfo.bin") - )["items"] - isCHN = True - except: - print("Couldn't load musicinfo.bin, exiting.") - exit(0) - -# Loading music_usbsetting.bin -try: - usb = ( - json.loads( - decrypt_file(input_file="./Data/x64/datatable/music_usbsetting.bin") - )["items"] - if isCHN - else None - ) -except: - usb = None - -# Loading music_order.bin -try: - order = ( - json.loads(decrypt_file(input_file="./Data/x64/datatable/music_order.bin"))[ - "items" - ] - if isCHN - else json.load(gzip.open("./Data/x64/datatable/music_order.bin", "rb"))["items"] - ) -except: - order = None - -# Loading music_attribute.bin -try: - attributes = ( - json.loads(decrypt_file(input_file="./Data/x64/datatable/music_attribute.bin"))[ - "items" - ] - if isCHN - else json.load(gzip.open("./Data/x64/datatable/music_attribute.bin", "rb"))[ - "items" - ] - ) -except: - attributes = None - -# Loading wordlist.bin -try: - words = ( - json.loads(decrypt_file(input_file="./Data/x64/datatable/wordlist.bin"))[ - "items" - ] - if isCHN - else json.load(gzip.open("./Data/x64/datatable/wordlist.bin", "rb"))["items"] - ) -except: - words = None +infos = loadFile(path="./Data/x64/datatable/musicinfo.bin") +usb = loadFile(path="./Data/x64/datatable/music_usbsetting.bin") +order = loadFile(path="./Data/x64/datatable/music_order.bin") +attributes = loadFile(path="./Data/x64/datatable/music_attribute.bin") +words = loadFile(path="./Data/x64/datatable/wordlist.bin") # endregion # Forcing japanese language on 08.18 as this is what is usually used for omnimix. @@ -94,9 +46,9 @@ class Genres(Enum): Vocaloid = 3 GameMusic = 4 NamcoOriginal = 5 - Variety = 6 if not isCHN else 7 - Classical = 7 if not isCHN else 8 - if not isCHN: + Variety = 6 if not isChn else 7 + Classical = 7 if not isChn else 8 + if not isChn: Custom = 9 @classmethod diff --git a/helpers.py b/helpers.py new file mode 100644 index 0000000..04585a6 --- /dev/null +++ b/helpers.py @@ -0,0 +1,74 @@ +import gzip +import json +import os + +from encryption import decrypt_file + + +def isChn(): + return os.path.exists("./Data/x64/datatable/music_usbsetting.bin") + + +def loadFile(path: str): + if doesPathExist(path): + try: + if not isChn(): + # Loading files for 08.18 + return json.load(gzip.open(path, "rb"))["items"] + else: + # Loading files for 32.09 CHN + return json.loads(decrypt_file(input_file=path))["items"] + except Exception as error: + print(error) + print("Couldn't load", path) + return None + else: + print(path, "doesn't exist") + + +def findKeyInList(list: list, key: str, keyValue, value=None): + for object in list: + try: + if object[key] == keyValue: + if value is not None: + return object[value] + else: + return object + except: + if value is not None: + print( + value + + " doesn't exist in " + + str(object) + + ", are you using the right language ?" + ) + exit(0) + + if value is not None: + return "" + else: + return None + + +def findAllObjects(list: list, key: str, keyValue): + templist = [] + templist.append(list) + objects = [] + + for element in templist[0]: + if element[key] == keyValue: + objects.append(element) + + return objects + + +def findDoubloninList(list: list, key: str, keyValue): + if len(findAllObjects(list=list, key=key, keyValue=keyValue)) > 1: + return True + return False + + +def doesPathExist(path: str): + if os.path.exists(path): + return True + return False diff --git a/sortAlphabetically.py b/sortAlphabetically.py new file mode 100644 index 0000000..f73a87c --- /dev/null +++ b/sortAlphabetically.py @@ -0,0 +1,174 @@ +from argparse import ArgumentParser +import gzip +from io import StringIO +import json +import os +import shutil + +from helpers import doesPathExist, isChn, findKeyInList, loadFile + +from encryption import encrypt_file + +language = "" + +order = None +words = None + + +def loadFiles(): + global order, words + # Loading music_order.bin and wordlist.bin + order = loadFile(path="./Data/x64/datatable/music_order.bin") + words = loadFile(path="./Data/x64/datatable/wordlist.bin") + + if any([order == None, words == None]): + print( + "Couldn't load files. Consider restoring your music_order file using the --restore flag." + ) + exit(0) + + +class Entry: + name = "" + genreNo = -1 + id = "" + uniqueId = -1 + closeDispType = -1 + + def __init__(self, name, genreNo, id, uniqueId, closeDispType): + self.name = name + self.genreNo = genreNo + self.id = id + self.uniqueId = uniqueId + self.closeDispType = closeDispType + + def toJson(self): + return { + # "name": self.name, + "genreNo": self.genreNo, + "id": self.id, + "uniqueId": self.uniqueId, + "closeDispType": self.closeDispType, + } + + +def sort(reverse: bool): + # Adding all the existing songs in song_order in an array + entries = [] + for entry in order: + name = findKeyInList( + list=words, + key="key", + keyValue="song_" + entry["id"], + value=language, + ) + + if name == "": + print(entry["id"] + " is missing a name") + + entries.append( + Entry( + name=name, + genreNo=entry["genreNo"], + id=entry["id"], + uniqueId=entry["uniqueId"], + closeDispType=entry["closeDispType"], + ) + ) + + print("Sorting", str(len(entries)), "entries") + + # Sorting names alphabetically. + if reverse: + print("Reversed sorting order!") + entries.sort(key=lambda x: x.name, reverse=reverse) + + # Backing up the original order file + if not doesPathExist(path="./Data/x64/datatable/music_order.bin.bak"): + print("Backed up music_order") + shutil.move( + "./Data/x64/datatable/music_order.bin", + "./Data/x64/datatable/music_order.bin.bak", + ) + + file = {"items": []} + for entry in entries: + file["items"].append(entry.toJson()) + # Writing song_order.bin + json_object = json.dumps(file, ensure_ascii=False, indent="\t") + if not isChn(): + # Saving compressed bin file for 08.18 + with open("./Data/x64/datatable/music_order.bin", "wb") as outfile: + outfile.write(gzip.compress(bytes(json_object, encoding="utf-8"))) + else: + # Saving encrypted compressed bin file for 32.09 CHN + # This is terrible but it works fine :)) + with open( + "./Data/x64/datatable/music_order.json", "w", encoding="utf-8" + ) as outfile: + outfile.write(json_object) + encrypted_object = encrypt_file( + input_file="./Data/x64/datatable/music_order.json" + ) + os.remove("./Data/x64/datatable/music_order.json") + with open("./Data/x64/datatable/music_order.bin", "wb") as outfile: + outfile.write(encrypted_object) + + +def restore(): + # Checking if we have a backup + if doesPathExist(path="./Data/x64/datatable/music_order.bin.bak"): + print("Restoring music_order") + # Removing current music_order file + if os.path.isfile("./Data/x64/datatable/music_order.bin"): + os.remove("./Data/x64/datatable/music_order.bin") + # Restoring backup + shutil.move( + "./Data/x64/datatable/music_order.bin.bak", + "./Data/x64/datatable/music_order.bin", + ) + else: + print("There is no backup to restore.") + + +if __name__ == "__main__": + parser = ArgumentParser() + parser.add_argument( + "--restore", + action="store_true", + default=False, + help="Use this flag to restore a backup of the original file", + ) + parser.add_argument( + "--reverse", + action="store_true", + default=False, + help="Revert sorting order", + ) + parser.add_argument( + "-l", + "--language", + default="englishUsText", + help="This sets the language used for sorting the files. Possible values are : japaneseText, englishUsText, chineseTText, chineseSText and koreanText", + ) + + args = parser.parse_args() + language = args.language + + if language not in [ + "japaneseText", + "englishUsText", + "chineseTText", + "chineseSText", + "koreanText", + ]: + print( + "Invalid language, Possible values are : japaneseText, englishUsText, chineseTText, chineseSText and koreanText" + ) + exit(1) + + if not args.restore: + loadFiles() + sort(args.reverse) + else: + restore()