文档整理: - 重写 game/操作说明.md 为项目主文档(6游戏/6手势/旁白/模型生成音频/TTS两步流程) - 归档过时文档至 other_docs/(林夏原始设计、旧执行文档) - 新增 docs/音频制作执行手册.md(从零制作游戏音频的完整流程) - docs/ 下保留旁白音色提示词、音频脚本 代码清理: - 删除旧架构死代码: story.js / gestures.js / profile.js - 删除耦合旧架构的过时测试目录 game/tests/ 脚本配置修正: - check_tts_env.sh: 启动脚本路径 AutoVideo → tts-server(实际位置) - gen_narrator_samples.py: 硬编码地址改为环境变量,默认对齐 tts-server 端口 8000
96 lines
3.4 KiB
Python
96 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
为各游戏脚本注入 narrateAudio 字段
|
||
|
||
用法:
|
||
python audio/inject_narrateAudio.py --game shouye --dry-run
|
||
python audio/inject_narrateAudio.py --game shouye
|
||
|
||
说明:
|
||
扫描 audio/mp3/narrator/{game_id}/ 目录下已生成的 MP3,
|
||
打印出对应游戏脚本中应添加的 narrateAudio 字段。
|
||
由于游戏脚本结构各异,本脚本只做"报告",不直接修改 JS 文件。
|
||
|
||
输出示例(复制粘贴到对应 scene 对象中):
|
||
s01: {
|
||
narrateAudio: '../audio/mp3/narrator/shouye/shouye_s01_narrate.mp3',
|
||
narrate: '...', // 保留原文作 TTS 兜底
|
||
...
|
||
}
|
||
"""
|
||
import os
|
||
import argparse
|
||
import glob
|
||
|
||
PROJECT_DIR = "/home/xsl/blind"
|
||
NARRATOR_DIR = os.path.join(PROJECT_DIR, "audio", "mp3", "narrator")
|
||
# 相对于 game/js/games/{game}.js 的音频路径
|
||
AUDIO_REL = "../../audio/mp3/narrator"
|
||
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser()
|
||
parser.add_argument("--game", required=True,
|
||
help="游戏 ID (linxia/yinian/shouye/houzhen/yisheng/fu)")
|
||
parser.add_argument("--dry-run", action="store_true",
|
||
help="只列出可用文件,不输出注入建议")
|
||
args = parser.parse_args()
|
||
|
||
game_dir = os.path.join(NARRATOR_DIR, args.game)
|
||
if not os.path.isdir(game_dir):
|
||
print(f"[错误] 目录不存在: {game_dir}")
|
||
print(f"请先运行 batch_narrator_tts.py 生成音频。")
|
||
return
|
||
|
||
files = sorted(glob.glob(os.path.join(game_dir, "*.mp3")))
|
||
if not files:
|
||
print(f"[空] {game_dir}/ 中没有 MP3 文件。")
|
||
return
|
||
|
||
print(f"\n已生成的 {args.game} 旁白音频 ({len(files)} 条):\n")
|
||
|
||
if args.dry_run:
|
||
for f in files:
|
||
print(f" {os.path.basename(f)}")
|
||
return
|
||
|
||
print("// ── 将以下 narrateAudio 字段添加到对应 scene/action 对象中 ──")
|
||
print("// (保留 narrate 文字作 TTS 兜底;有了 narrateAudio 后引擎会优先播放文件)\n")
|
||
|
||
for f in files:
|
||
name = os.path.basename(f) # e.g. shouye_s01_narrate.mp3
|
||
stem = name[:-4] # e.g. shouye_s01_narrate
|
||
# 推断 scene/action key
|
||
parts = stem.split("_") # ['shouye', 's01', 'narrate']
|
||
rel_path = f"{AUDIO_REL}/{args.game}/{name}"
|
||
|
||
# 判断类型
|
||
if parts[-1] == "narrate" or parts[-1].startswith("narrate"):
|
||
field = "narrateAudio"
|
||
note = f"// → scene {parts[1]}"
|
||
elif parts[-1] == "tap" or parts[-1].startswith("tap"):
|
||
field = "narrateAudio"
|
||
note = f"// → scene {parts[1]} / tap"
|
||
elif parts[-1] == "dt":
|
||
field = "narrateAudio"
|
||
note = f"// → scene {parts[1]} / doubleTap"
|
||
elif parts[-1] == "intro":
|
||
field = "// game.introAudio"
|
||
note = "// → game 对象 intro 字段(engine.run 中用 narrateAudio 处理)"
|
||
elif "ending" in parts:
|
||
ending_id = "_".join(parts[parts.index("ending"):])
|
||
field = "narrateAudio"
|
||
note = f"// → endings.{ending_id.replace('ending_', '')} 对象"
|
||
else:
|
||
field = "narrateAudio"
|
||
note = ""
|
||
|
||
print(f" {field}: '{rel_path}', {note}")
|
||
|
||
print("\n// 提示:intro 的 narrateAudio 需在 engine.run() 里单独处理,")
|
||
print("// 或在 game 对象中加 introAudio 字段并在 engine 中检查。")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|