diff options
| author | Pinapelz <yukais@pinapelz.com> | 2025-04-02 05:13:57 -0700 |
|---|---|---|
| committer | Pinapelz <yukais@pinapelz.com> | 2025-04-02 05:13:57 -0700 |
| commit | 550053e5ebeadba457efeee6faf2b5589caef625 (patch) | |
| tree | 046228e3d0d89a44cd934f466beff3c98b806b84 | |
| parent | 7e345deced5a3f583ecca54b5a210924bac4c393 (diff) | |
| parent | 123393533f5e938e24ddbfefbd84f170db2aa690 (diff) | |
Merge branch 'main' of https://github.com/pinapelz/more-tachi-import-scripts
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | chuni/aquadx/chuni_aquadx_to_tachi.py | 36 | ||||
| -rw-r--r-- | mai2/aquadx/mai_aquadx_to_tachi.py | 71 | ||||
| -rw-r--r-- | ongeki/aquadx/ongeki_aquadx_to_tachi.py | 58 | ||||
| -rw-r--r-- | wacca/aquadx/wacca_aquadx_to_tachi.py | 54 |
5 files changed, 166 insertions, 57 deletions
@@ -7,3 +7,7 @@ Use with caution as there may be some cases missing. - AquaDX (Online Hosted) maimai DX User Data JSON - AquaDX (Online Hosted) O.N.G.E.K.I API recently played (no export functionality in AquaNet yet) - AquaDX (Online Hosted) WACCA API recently played (no export functionality in AquaNet yet) + + +> [!CAUTION] +> If you are using Kamaitachi or using someone else's Tachi instance please check the rules to ensure that you are complying with the rules before importing your scores!!! diff --git a/chuni/aquadx/chuni_aquadx_to_tachi.py b/chuni/aquadx/chuni_aquadx_to_tachi.py index 3046277..4a7455e 100644 --- a/chuni/aquadx/chuni_aquadx_to_tachi.py +++ b/chuni/aquadx/chuni_aquadx_to_tachi.py @@ -1,5 +1,7 @@ import argparse import json +import urllib.request +import os DIFFICULTY_MAPPING = { 0: "BASIC", @@ -10,10 +12,11 @@ DIFFICULTY_MAPPING = { 5: "WORLD'S END", } -def convert_from_aquadx_json_to_tachi_json(input_json: str, output_file: str, service: str): - with open(input_json, "r", encoding="utf-8") as f: - raw_data = json.load(f) +headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" +} +def convert_from_aquadx_json_to_tachi_json(raw_data: str, output_file: str, service: str): batch_manual = { "meta": {"game": "chunithm", "playtype": "Single", "service": service}, "scores": [], @@ -91,15 +94,38 @@ if __name__ == "__main__": description="Converts AquaDX score data for Chuni to Tachi compatible JSON", epilog="Fast/Slow can't be derived (I think)", ) - parser.add_argument("input_file", help="Path to the input JSON file exported from AquaDX") + parser.add_argument("-f", "--file", help="Manual. Specify path to the input exported score JSON file exported from AquaDX", required=False) parser.add_argument( "-s", "--service", help="Service description to be shown on Tachi (Note for where this score came from)", default="AquaDX Chuni Import", ) + parser.add_argument("-t", "--token", help="Use AquaNet Token to directly grab data from API. Get it from Network tab in your browser and check the API request it makes ?token=???", required=False) + parser.add_argument("-u", "--url", help="AquaNet API endpoint. No need to use this unless you self-host AquaDX", default="https://aquadx.net/aqua") parser.add_argument( "-o", "--output", help="Output filename", default="aquadx_chuni_tachi.json" ) args = parser.parse_args() - convert_from_aquadx_json_to_tachi_json(args.input_file, args.output, args.service) + # Some checks to make sure input is valid + if args.token is None and args.file is None: + print("ERROR: No valid input method specified. You must specify either --file or --token") + exit(1) + aquadx_url = args.url + if not aquadx_url.startswith("https://") and not aquadx_url.startswith("http://"): + aquadx_url = "https://" + aquadx_url + + + if args.file is not None: + print("An input file has been specified, using local file as input") + if not os.path.exists(args.file): + print(f"ERROR: The file {args.file} does not exist.") + exit(1) + with open(args.file, "r", encoding="utf-8") as f: + raw_data = json.load(f) + else: + print("Pulling Chuni playdata from remote AquaDX at: " + aquadx_url) + req = urllib.request.Request(aquadx_url+"/api/v2/game/chu3/export?token="+args.token, headers=headers) + with urllib.request.urlopen(req) as response: + raw_data = json.load(response) + convert_from_aquadx_json_to_tachi_json(raw_data, args.output, args.service) diff --git a/mai2/aquadx/mai_aquadx_to_tachi.py b/mai2/aquadx/mai_aquadx_to_tachi.py index 399a4ff..70faf0f 100644 --- a/mai2/aquadx/mai_aquadx_to_tachi.py +++ b/mai2/aquadx/mai_aquadx_to_tachi.py @@ -1,6 +1,7 @@ import argparse import json import urllib.request +import os MAI2_AQUADX_JSON = "https://aquadx.net/d/mai2/00/all-music.json" @@ -16,18 +17,7 @@ headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" } -def convert_from_aquadx_json_to_tachi_json(input_json: str, output_file: str, service: str, music_json: str): - if music_json == "online": - req = urllib.request.Request(MAI2_AQUADX_JSON, headers=headers) - with urllib.request.urlopen(req) as response: - music_json = json.load(response) - else: - with open(music_json, "r", encoding="utf-8") as file: - music_json = json.load(file) - - with open(input_json, "r", encoding="utf-8") as f: - raw_data = json.load(f) - +def convert_from_aquadx_json_to_tachi_json(raw_data: str, output_file: str, service: str, music_json: str): batch_manual = { "meta": {"game": "maimaidx", "playtype": "Single", "service": service}, "scores": [], @@ -44,18 +34,26 @@ def convert_from_aquadx_json_to_tachi_json(input_json: str, output_file: str, se continue processed_count += 1 - song_title = music_json[str(entry["musicId"])]["name"] + try: + song_title = music_json[str(entry["musicId"])]["name"] + except KeyError: + skipped_count += 1 + continue - raw_score_value = float(entry.get("achievement", 0)) - score_value = raw_score_value/10000 + raw_score_value = entry.get("achievement", 0) + score_value = float(raw_score_value/10000) is_clear = entry.get("isClear", False) is_full_combo = entry.get("isFullCombo", False) is_all_perfect = entry.get("isAllPerfect", False) lamp = "FAILED" if is_all_perfect: lamp = "ALL PERFECT" + if entry.get("tapGreat") == 0: + lamp == "ALL PERFECT+" elif is_full_combo: lamp = "FULL COMBO" + if entry.get("tapGood") == 0: + lamp = "FULL COMBO+" elif is_clear: lamp = "CLEAR" timestamp = entry.get("loginDate", None) @@ -107,16 +105,49 @@ if __name__ == "__main__": description="Converts AquaDX score data for maimai (DX) to Tachi compatible JSON", epilog="Dan and matchingClass not implemented. Please just use other methods for that kind of static info" ) - parser.add_argument("input_file", help="Path to the input JSON file exported from AquaDX") + parser.add_argument("-f", "--file", help="Manual. Specify path to the input exported score JSON file exported from AquaDX", required=False) parser.add_argument( "-s", "--service", help="Service description to be shown on Tachi (Note for where this score came from)", - default="AquaDX maimaidx Import", + default="AquaDX Chuni Import", ) + parser.add_argument("-t", "--token", help="Use AquaNet Token to directly grab data from API. Get it from Network tab in your browser and check the API request it makes ?token=???", required=False) + parser.add_argument("-u", "--url", help="AquaNet API endpoint. No need to use this unless you self-host AquaDX", default="https://aquadx.net/aqua") parser.add_argument( - "-o", "--output", help="Output filename", default="aquadx_mai_tachi.json" + "-o", "--output", help="Output filename", default="aquadx_mai2_tachi.json" ) - parser.add_argument("--music", "--music-file", help="JSON file containing the mappings of song names to IDs. Check README for moe info", default="online") + parser.add_argument("-m", "--music", help="all-music.json from AquaNet that maps song id to name (required for Tachi). It will automatically pull from main AquaDX if not specified", default="online") + args = parser.parse_args() + # Some checks to make sure input is valid + if args.token is None and args.file is None: + print("ERROR: No valid input method specified. You must specify either --file or --token") + exit(1) + aquadx_url = args.url + if not aquadx_url.startswith("https://") and not aquadx_url.startswith("http://"): + aquadx_url = "https://" + aquadx_url + + + if args.file is not None: + print("An input file has been specified, using local file as input") + if not os.path.exists(args.file): + print(f"ERROR: The file {args.file} does not exist.") + exit(1) + with open(args.file, "r", encoding="utf-8") as f: + raw_data = json.load(f) + else: + print("Pulling mai2 playdata from remote AquaDX at: " + aquadx_url) + req = urllib.request.Request(aquadx_url+"/api/v2/game/mai2/export?token="+args.token, headers=headers) + with urllib.request.urlopen(req) as response: + raw_data = json.load(response) + + if args.music == "online": + req = urllib.request.Request(MAI2_AQUADX_JSON, headers=headers) + with urllib.request.urlopen(req) as response: + music_json = json.load(response) + else: + with open(args.music, "r", encoding="utf-8") as file: + music_json = json.load(file) + args = parser.parse_args() - convert_from_aquadx_json_to_tachi_json(args.input_file, args.output, args.service, args.music) + convert_from_aquadx_json_to_tachi_json(raw_data, args.output, args.service, music_json) diff --git a/ongeki/aquadx/ongeki_aquadx_to_tachi.py b/ongeki/aquadx/ongeki_aquadx_to_tachi.py index 70d7c19..3280c3f 100644 --- a/ongeki/aquadx/ongeki_aquadx_to_tachi.py +++ b/ongeki/aquadx/ongeki_aquadx_to_tachi.py @@ -1,6 +1,9 @@ import argparse import json import urllib.request +import os +import pytz +from datetime import datetime ONGEKI_AQUADX_JSON = "https://aquadx.net/d/ongeki/00/all-music.json" @@ -16,17 +19,7 @@ headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" } -def convert_from_aquadx_json_to_tachi_json(input_json: str, output_file: str, service: str, music_json: str): - if music_json == "online": - req = urllib.request.Request(ONGEKI_AQUADX_JSON, headers=headers) - with urllib.request.urlopen(req) as response: - music_json = json.load(response) - else: - with open(music_json, "r", encoding="utf-8") as file: - music_json = json.load(file) - - with open(input_json, "r", encoding="utf-8") as f: - raw_data = json.load(f) +def convert_from_aquadx_json_to_tachi_json(raw_data: str, output_file: str, service: str, music_json: str): batch_manual = { "meta": {"game": "ongeki", "playtype": "Single", "service": service}, @@ -64,7 +57,8 @@ def convert_from_aquadx_json_to_tachi_json(input_json: str, output_file: str, se bell_lamp = "FULL BELL" if is_full_bell else "NONE" - timestamp = entry.get("sortNumber", None) + dt = datetime.fromisoformat(entry.get("userPlayDate").rstrip("Z")).replace(tzinfo=pytz.UTC) + timestamp = int(dt.timestamp()) combo = entry.get("maxCombo",0) bell_count = entry.get("bellCount",0) total_bell_count = entry.get("totalBellCount", 0) @@ -112,16 +106,48 @@ if __name__ == "__main__": description="Converts AquaDX API JSON for O.N.G.E.K.I to Tachi compatible JSON", epilog="damage, fast, slow, unavailable on the webui" ) - parser.add_argument("input_file", help="Path to the input JSON file exported from AquaDX") + parser.add_argument("-f", "--file", help="Manual. Specify path to the input exported score JSON file exported from AquaDX", required=False) parser.add_argument( "-s", "--service", help="Service description to be shown on Tachi (Note for where this score came from)", - default="AquaDX O.N.G.E.K.I Import (API JSON)", + default="AquaDX Chuni Import", ) + parser.add_argument("-t", "--token", help="Use AquaNet Token to directly grab data from API. Get it from Network tab in your browser and check the API request it makes ?token=???", required=False) + parser.add_argument("-u", "--url", help="AquaNet API endpoint. No need to use this unless you self-host AquaDX", default="https://aquadx.net/aqua") parser.add_argument( "-o", "--output", help="Output filename", default="aquadx_ongeki_tachi.json" ) - parser.add_argument("--music", "--music-file", help="JSON file containing the mappings of song names to IDs. Check README for moe info", default="online") + parser.add_argument("-m", "--music", help="all-music.json from AquaNet that maps song id to name (required for Tachi). It will automatically pull from main AquaDX if not specified", default="online") + args = parser.parse_args() + # Some checks to make sure input is valid + if args.token is None and args.file is None: + print("ERROR: No valid input method specified. You must specify either --file or --token") + exit(1) + aquadx_url = args.url + if not aquadx_url.startswith("https://") and not aquadx_url.startswith("http://"): + aquadx_url = "https://" + aquadx_url + + + if args.file is not None: + print("An input file has been specified, using local file as input") + if not os.path.exists(args.file): + print(f"ERROR: The file {args.file} does not exist.") + exit(1) + with open(args.file, "r", encoding="utf-8") as f: + raw_data = json.load(f) + else: + print("Pulling mu3/ONGEKI playdata from remote AquaDX at: " + aquadx_url) + req = urllib.request.Request(aquadx_url+"/api/v2/game/ongeki/user-summary?username=pinapelz&token="+args.token, headers=headers) + with urllib.request.urlopen(req) as response: + raw_data = json.load(response) + + if args.music == "online": + req = urllib.request.Request(ONGEKI_AQUADX_JSON, headers=headers) + with urllib.request.urlopen(req) as response: + music_json = json.load(response) + else: + with open(args.music, "r", encoding="utf-8") as file: + music_json = json.load(file) args = parser.parse_args() - convert_from_aquadx_json_to_tachi_json(args.input_file, args.output, args.service, args.music) + convert_from_aquadx_json_to_tachi_json(raw_data, args.output, args.service, music_json) diff --git a/wacca/aquadx/wacca_aquadx_to_tachi.py b/wacca/aquadx/wacca_aquadx_to_tachi.py index 6a2c763..e1af59c 100644 --- a/wacca/aquadx/wacca_aquadx_to_tachi.py +++ b/wacca/aquadx/wacca_aquadx_to_tachi.py @@ -2,9 +2,10 @@ import argparse import json import urllib.request import pytz +import os from datetime import datetime -ONGEKI_AQUADX_JSON = "https://aquadx.net/d/wacca/00/all-music.json" +WACCA_AQUADX_JSON = "https://aquadx.net/d/wacca/00/all-music.json" DIFFICULTY_MAPPING = { 0: "NORMAL", @@ -18,17 +19,6 @@ headers = { } def convert_to_aquadx_json_to_tachi_json(input_json: str, output_file: str, service: str, music_json: str): - if music_json == "online": - req = urllib.request.Request(ONGEKI_AQUADX_JSON, headers=headers) - with urllib.request.urlopen(req) as response: - music_json = json.load(response) - else: - with open(music_json, "r", encoding="utf-8") as file: - music_json = json.load(file) - - with open(input_json, "r", encoding="utf-8") as f: - raw_data = json.load(f) - batch_manual = { "meta": {"game": "wacca", "playtype": "Single", "service": service}, "scores": [], @@ -107,16 +97,48 @@ if __name__ == "__main__": description="Converts AquaDX API JSON for WACCA to Tachi compatible JSON", epilog="damage, fast, slow, unavailable on the webui" ) - parser.add_argument("input_file", help="Path to the input JSON file exported from AquaDX") + parser.add_argument("-f", "--file", help="Manual. Specify path to the input exported score JSON file exported from AquaDX", required=False) parser.add_argument( "-s", "--service", help="Service description to be shown on Tachi (Note for where this score came from)", - default="AquaDX WACCA Import (API JSON)", + default="AquaDX Chuni Import", ) + parser.add_argument("-t", "--token", help="Use AquaNet Token to directly grab data from API. Get it from Network tab in your browser and check the API request it makes ?token=???", required=False) + parser.add_argument("-u", "--url", help="AquaNet API endpoint. No need to use this unless you self-host AquaDX", default="https://aquadx.net/aqua") parser.add_argument( "-o", "--output", help="Output filename", default="aquadx_wacca_tachi.json" ) - parser.add_argument("--music", "--music-file", help="JSON file containing the mappings of song names to IDs. Check README for moe info", default="online") + parser.add_argument("-m", "--music", help="all-music.json from AquaNet that maps song id to name (required for Tachi). It will automatically pull from main AquaDX if not specified", default="online") + args = parser.parse_args() + # Some checks to make sure input is valid + if args.token is None and args.file is None: + print("ERROR: No valid input method specified. You must specify either --file or --token") + exit(1) + aquadx_url = args.url + if not aquadx_url.startswith("https://") and not aquadx_url.startswith("http://"): + aquadx_url = "https://" + aquadx_url + + + if args.file is not None: + print("An input file has been specified, using local file as input") + if not os.path.exists(args.file): + print(f"ERROR: The file {args.file} does not exist.") + exit(1) + with open(args.file, "r", encoding="utf-8") as f: + raw_data = json.load(f) + else: + print("Pulling WACCA playdata from remote AquaDX at: " + aquadx_url) + req = urllib.request.Request(aquadx_url+"/api/v2/game/wacca/user-summary?username=pinapelz&token="+args.token, headers=headers) + with urllib.request.urlopen(req) as response: + raw_data = json.load(response) + + if args.music == "online": + req = urllib.request.Request(WACCA_AQUADX_JSON, headers=headers) + with urllib.request.urlopen(req) as response: + music_json = json.load(response) + else: + with open(args.music, "r", encoding="utf-8") as file: + music_json = json.load(file) args = parser.parse_args() - convert_to_aquadx_json_to_tachi_json(args.input_file, args.output, args.service, args.music) + convert_to_aquadx_json_to_tachi_json(raw_data, args.output, args.service, music_json) |
