From 057c83de767320b071ecc0318a95a07019ab3d71 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Thu, 27 Feb 2025 16:04:16 -0800 Subject: initial commit --- sdvx/sdvx_csv_to_tachi.py | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 sdvx/sdvx_csv_to_tachi.py (limited to 'sdvx/sdvx_csv_to_tachi.py') diff --git a/sdvx/sdvx_csv_to_tachi.py b/sdvx/sdvx_csv_to_tachi.py new file mode 100644 index 0000000..062b0f4 --- /dev/null +++ b/sdvx/sdvx_csv_to_tachi.py @@ -0,0 +1,101 @@ +import csv +import json +import argparse + +DIFFICULTY_MAPPING = { + "NOVICE": "NOV", + "ADVANCED": "ADV", + "EXHAUST": "EXH", + "INFINITE": "INF", + "GRAVITY": "GRV", + "HEAVENLY": "HVN", + "VIVD": "VVD", + "EXCEED": "EXCEED", + "MAXIMUM": "MXM" +} + +LAMP_MAPPING = { + "PLAYED": "FAILED", + "COMPLETE": "CLEAR", +} + +def convert_sdvx_csv_to_tachi_json(csv_file, game, playtype, service): + encodings = ['utf-8-sig', 'utf-8', 'shift-jis', 'cp932'] + + for encoding in encodings: + try: + batch_manual = { + "meta": { + "game": game, + "playtype": playtype, + "service": service + }, + "scores": [] + } + + with open(csv_file, newline='', encoding=encoding) as f: + reader = csv.DictReader(f) + fieldnames = reader.fieldnames + required_fields = ["楽曲名", "難易度", "クリアランク", "ハイスコア"] + if not all(field in fieldnames for field in required_fields): + continue + + + for row in reader: + lamp = LAMP_MAPPING[row["クリアランク"].upper()] + if row.get("ULTIMATE CHAIN"): + lamp = "ULTIMATE CHAIN" + if row.get("PERFECT"): + lamp = "PERFECT ULTIMATE CHAIN" + + score_entry = { + "score": int(row["ハイスコア"]), + "lamp": lamp, + "matchType": "songTitle", + "identifier": row["楽曲名"], + "difficulty": DIFFICULTY_MAPPING[row["難易度"].upper()], + } + optional_fields = {} + if row.get("EXスコア"): + optional_fields["exScore"] = int(row["EXスコア"]) + if row.get("fast"): + optional_fields["fast"] = int(row["fast"]) + if row.get("slow"): + optional_fields["slow"] = int(row["slow"]) + if row.get("maxCombo"): + optional_fields["maxCombo"] = int(row["maxCombo"]) + if row.get("gauge"): + optional_fields["gauge"] = float(row["gauge"]) + if optional_fields: + score_entry["optional"] = optional_fields + batch_manual["scores"].append(score_entry) + return batch_manual + except UnicodeDecodeError: + continue + except Exception as e: + print(f"Error with encoding {encoding}: {str(e)}") + continue + + raise ValueError("Failed to read CSV file with any supported encoding") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog="sdvx_csv_to_tachi", + description="Converts CSV data exported from SDVX eAmuse site to Tachi compatibile JSON", + epilog="Note that not all information can be derived from the CSV so some fields will be missing from Tachi" + ) + parser.add_argument("csv_filename", help="Path to the CSV file") + parser.add_argument("-s", "--service", help="Service description to be shown on Tachi (Note for where this score came from)", default="SDVX Arcade Import") + parser.add_argument("-o", "--output", help="Output filename", default="sdvx_tachi.json") + args = parser.parse_args() + +try: + output_json = convert_sdvx_csv_to_tachi_json(args.csv_filename, "sdvx", "Single", args.service) + + with open(args.output, "w", encoding="utf-8") as json_file: + json.dump(output_json, json_file, ensure_ascii=False, indent=4) + + print("Conversion completed. JSON saved as " + args.output) +except Exception as e: + print(f"Error: {str(e)}") -- cgit v1.2.3