From ac3c1e79a9d497f85b19fd1cf69301db58b4165c Mon Sep 17 00:00:00 2001 From: Bennett <2165217440@qq.com> Date: Sat, 10 May 2025 08:39:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ab2png.py | 26 +++++++++++++++ acb2mp3.py | 53 ++++++++++++++++++++++++++++++ getchart.py | 0 search.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 ab2png.py create mode 100644 acb2mp3.py create mode 100644 getchart.py create mode 100644 search.py diff --git a/ab2png.py b/ab2png.py new file mode 100644 index 0000000..a621fbf --- /dev/null +++ b/ab2png.py @@ -0,0 +1,26 @@ +import UnityPy +from PIL import Image + + +def convert_ab_to_png(assetbundle_path, output_png_path): + env = UnityPy.load(assetbundle_path) + + for obj in env.objects: + if obj.type == 28: # ClassID 28 = Texture2D + texture2d = obj.read() + image = texture2d.image + image.save(output_png_path) + print(f"已提取 Texture2D 并保存到 {output_png_path}") + return + + raise Exception("AssetBundle 中没有找到 Texture2D。") + + +# 示例用法 +if __name__ == "__main__": + import sys + + if len(sys.argv) != 3: + print("用法: python ab2png.py 输入.ab 输出.png") + else: + convert_ab_to_png(sys.argv[1], sys.argv[2]) diff --git a/acb2mp3.py b/acb2mp3.py new file mode 100644 index 0000000..8215b8f --- /dev/null +++ b/acb2mp3.py @@ -0,0 +1,53 @@ +import os +import sys +from pathlib import Path +from subprocess import run +from loguru import logger +# 设置工作目录 +WORK_DIR = Path("work/audio") + +# 确保工作目录存在 +WORK_DIR.mkdir(parents=True, exist_ok=True) + + +def convert_awb_to_wav(awb, output_wav): + """使用 vgmstream-cli 将 AWB 文件转换为 WAV 文件""" + run(["vgmstream-cli","-o",output_wav,awb]) + + +def convert_wav_to_mp3(wav, output_mp3): + """使用 ffmpeg 将 WAV 文件转换为 MP3 文件""" + run(["ffmpeg", "-i", wav, f"{output_mp3}"]) + + +if __name__ == "__main__": + if len(sys.argv) < 3: + logger.info("用法: python acb2mp3.py 输入文件 输出文件") + sys.exit(1) + + input_file = sys.argv[1] + output_file = sys.argv[2] + + # 获取输入文件的扩展名 + input_path = Path(input_file) + output_path = Path(output_file) + + # 判断输入文件是否是 .acb 文件 + if input_path.suffix.lower() == ".acb": + # 假设输入文件关联的 .awb 文件在同一目录下 + awb_file = input_path.with_suffix(".awb") + logger.info(awb_file) + if awb_file.exists(): + # 将 .awb 转换为 WAV + wav_file = WORK_DIR / "output.wav" + convert_awb_to_wav(str(awb_file), str(wav_file)) + logger.info(f"AWB 转换成功,生成文件: {wav_file}") + + # 将 WAV 转换为 MP3 + mp3_file = output_path.with_suffix(".mp3") + convert_wav_to_mp3(str(wav_file), str(mp3_file)) + logger.info(f"WAV 转换为 MP3 成功,生成文件: {mp3_file}") + else: + logger.error(f"未找到对应的 AWB 文件: {awb_file}") + else: + logger.error(f"输入文件不是 .acb 文件: {input_path}") diff --git a/getchart.py b/getchart.py new file mode 100644 index 0000000..e69de29 diff --git a/search.py b/search.py new file mode 100644 index 0000000..47015f7 --- /dev/null +++ b/search.py @@ -0,0 +1,95 @@ +import os +from ReadOpt import parse_music_xml, level_name + +# 根目录 +streaming_assets = "/Users/bennett/Downloads/SDEZ/Package/Sinmai_Data/StreamingAssets" + +def search_music_by_id(search_id): + for asset_dir in os.listdir(streaming_assets): + root_dir = os.path.join(streaming_assets, asset_dir) + music_dir = os.path.join(root_dir, "music") + if not os.path.isdir(music_dir): + continue + + for music_subdir in os.listdir(music_dir): + sub_path = os.path.join(music_dir, music_subdir) + music_xml_path = os.path.join(sub_path, "Music.xml") + if not os.path.isfile(music_xml_path): + continue + + music_id, name, artist, notes = parse_music_xml(music_xml_path) + if music_id == search_id: + print(f"\n【找到曲目:{name}】") + print(f" ID:{music_id}") + print(f" 艺术家:{artist}") + print(f" 所在分区:{asset_dir}") + print(" 谱面信息:") + for i, note in enumerate(notes): + level_str = level_name[i] if i < len(level_name) else f"Diff{i}" + print(f" - {level_str}: 定数 {note['level']} / 显示 {note['levelshow']} / 谱师 {note['designer']}") + + # ma2 文件 + ma2_files = [f for f in os.listdir(sub_path) if f.endswith(".ma2")] + ma2_paths = [os.path.join(sub_path, f) for f in ma2_files] + if ma2_files: + print(" MA2 文件:") + for f in ma2_files: + print(f" - {os.path.join(sub_path, f)}") + else: + print(" MA2 文件:未找到") + + # 曲绘(查 jacket 文件夹) + jacket_dir = os.path.join(root_dir, "AssetBundleImages", "jacket") + jacket_ab = f"ui_jacket_00{int(music_id)-10000}.ab" + alt_exts = [".png", ".jpg", ".jpeg"] + alt_jacket = next((f for f in os.listdir(jacket_dir) + if f.startswith(f"ui_jacket_{music_id}") + and os.path.splitext(f)[1].lower() in alt_exts), None) + + print(" 曲绘文件:") + + if os.path.exists(os.path.join(jacket_dir, jacket_ab)): + print(f" - {os.path.join(jacket_dir, jacket_ab)}") + elif alt_jacket: + print(f" - {os.path.join(jacket_dir, alt_jacket)}") + else: + print(" - 未找到") + + # 音频文件(SoundData) + sound_dir = os.path.join(root_dir, "SoundData") + audio_prefix = f"music00{int(music_id)-10000}" + audio_files = [f for f in os.listdir(sound_dir) if f.lower().startswith(audio_prefix)] + print(" 音频文件:") + if audio_files: + for f in audio_files: + print(f" - {os.path.join(sound_dir, f)}") + else: + print(" - 未找到") + + audio_lists = [] + for f in audio_files: + audio_lists.append(os.path.join(sound_dir, f)) + + # 视频 dat 文件(MovieData) + movie_dir = os.path.join(root_dir, "MovieData") + dat_name = f"00{int(music_id)-10000}.dat" + dat_path = os.path.join(movie_dir, dat_name) + print(" 视频 DAT 文件:") + print(f" - {dat_path}" if os.path.exists(dat_path) else " - 未找到") + + return [[music_id, name, artist,notes],ma2_paths,os.path.join(jacket_dir, jacket_ab),audio_lists,dat_path] + + print(f"\n未找到 ID 为 {search_id} 的曲目信息。") + return None + + + + +if __name__ == "__main__": + target_id = input("请输入要搜索的曲目 ID:").strip() + result = search_music_by_id(target_id) + print(result) + + + +