294 lines
8.8 KiB
Python
294 lines
8.8 KiB
Python
import functools
|
|
import multiprocessing
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
from contextlib import contextmanager
|
|
from distutils.dir_util import copy_tree
|
|
from glob import glob
|
|
|
|
from adx import extract_loop_data_from_dir
|
|
|
|
OPERATING_SYSTEM = os.name
|
|
|
|
|
|
def process_se(cache_dir, extract_dir, update_dir):
|
|
copy_tree(
|
|
os.path.join(cache_dir, "Android/Asset/Sound/Se"),
|
|
os.path.join(extract_dir, "Se"),
|
|
)
|
|
|
|
from_dir = "Se"
|
|
to_dir = "Se_Extracted"
|
|
acb_prefix = "_vgmt_acb_ext"
|
|
|
|
pool = get_pool()
|
|
|
|
with change_cwd(extract_dir):
|
|
os.makedirs(to_dir, exist_ok=True)
|
|
|
|
to_del = glob("{}/**/*.wav".format(from_dir), recursive=True)
|
|
to_del.extend(glob("{}/**/*.hca".format(from_dir), recursive=True))
|
|
for file in to_del:
|
|
os.remove(file)
|
|
|
|
acb_files = [file for file in glob("{}/*.acb".format(from_dir))]
|
|
acb_cmd = get_dotnet_cmd("acb_extract.exe")
|
|
run_program(acb_files, cmd=acb_cmd)
|
|
|
|
hca_files = [
|
|
file for file in glob("{}/**/*.hca".format(from_dir), recursive=True)
|
|
]
|
|
run_program(hca_files, cmd="clHCA")
|
|
|
|
basenames = [os.path.splitext(os.path.basename(file))[0] for file in acb_files]
|
|
char_secs = [basename.split("_", maxsplit=1) for basename in basenames]
|
|
for cs in char_secs:
|
|
char = cs[0]
|
|
sec = str(cs[1]) if len(cs) == 2 else ""
|
|
os.makedirs(os.path.join(to_dir, char, sec), exist_ok=True)
|
|
wav_files = glob(
|
|
"{}/{}_{}/**/*.wav".format(from_dir, acb_prefix, "_".join(cs)),
|
|
recursive=True,
|
|
)
|
|
partial_ffmpeg_cmd = functools.partial(run_program, cmd="ffmpeg")
|
|
wav_cmds = [
|
|
[
|
|
"-i",
|
|
os.path.abspath(file),
|
|
"-acodec",
|
|
"libopus",
|
|
"-ab",
|
|
"192k",
|
|
"-af",
|
|
"aresample=48000",
|
|
os.path.abspath(
|
|
"{}/{}/{}/{}.opus".format(
|
|
to_dir,
|
|
char,
|
|
sec,
|
|
os.path.splitext(os.path.basename(file))[0],
|
|
)
|
|
),
|
|
"-n",
|
|
]
|
|
for file in wav_files
|
|
]
|
|
pool.map(partial_ffmpeg_cmd, wav_cmds)
|
|
|
|
copy_tree(os.path.join(extract_dir, to_dir), os.path.join(update_dir, "Se"))
|
|
|
|
|
|
def process_bgm(cache_dir, extract_dir, update_dir):
|
|
copy_tree(
|
|
os.path.join(cache_dir, "Android/Asset/Sound/Bgm"),
|
|
os.path.join(extract_dir, "Bgm"),
|
|
)
|
|
|
|
from_dir = "Bgm"
|
|
to_dir = "Bgm_Extracted"
|
|
loop_file = "loop.json"
|
|
|
|
pool = get_pool()
|
|
|
|
with change_cwd(extract_dir):
|
|
os.makedirs(to_dir, exist_ok=True)
|
|
|
|
to_del = glob("{}/**/*.adx".format(from_dir), recursive=True)
|
|
for file in to_del:
|
|
os.remove(file)
|
|
|
|
acb_files = [file for file in glob("{}/*.acb".format(from_dir))]
|
|
acb_cmd = get_dotnet_cmd("acb_extract.exe")
|
|
run_program(acb_files, cmd=acb_cmd)
|
|
|
|
adx_files = [
|
|
file for file in glob("{}/**/*.adx".format(from_dir), recursive=True)
|
|
]
|
|
partial_ffmpeg_cmd = functools.partial(run_program, cmd="ffmpeg")
|
|
wav_cmds = [
|
|
[
|
|
"-i",
|
|
os.path.abspath(file),
|
|
"-acodec",
|
|
"libopus",
|
|
"-ab",
|
|
"192k",
|
|
"-af",
|
|
"aresample=48000",
|
|
os.path.abspath(
|
|
"{}/{}.opus".format(
|
|
to_dir, os.path.splitext(os.path.basename(file))[0],
|
|
)
|
|
),
|
|
"-n",
|
|
]
|
|
for file in adx_files
|
|
]
|
|
pool.map(partial_ffmpeg_cmd, wav_cmds)
|
|
|
|
extract_loop_data_from_dir(from_dir, loop_file)
|
|
shutil.copy2(loop_file, os.path.join(to_dir, "BgmLoop.json"))
|
|
|
|
copy_tree(os.path.join(extract_dir, to_dir), os.path.join(update_dir, "Bgm"))
|
|
|
|
|
|
def process_voice(cache_dir, extract_dir, update_dir):
|
|
copy_tree(
|
|
os.path.join(cache_dir, "Android/Asset/Sound/Voice"),
|
|
os.path.join(extract_dir, "Voice"),
|
|
)
|
|
|
|
from_dir = "Voice"
|
|
to_dir = "Voice_Extracted"
|
|
acb_prefix = "_vgmt_acb_ext"
|
|
|
|
pool = get_pool()
|
|
|
|
with change_cwd(extract_dir):
|
|
os.makedirs(to_dir, exist_ok=True)
|
|
|
|
to_del = glob("{}/**/*.wav".format(from_dir), recursive=True)
|
|
to_del.extend(glob("{}/**/*.hca".format(from_dir), recursive=True))
|
|
for file in to_del:
|
|
os.remove(file)
|
|
|
|
acb_files = [file for file in glob("{}/*.acb".format(from_dir))]
|
|
acb_cmd = get_dotnet_cmd("acb_extract.exe")
|
|
run_program(acb_files, cmd=acb_cmd)
|
|
|
|
hca_files = [
|
|
file for file in glob("{}/**/*.hca".format(from_dir), recursive=True)
|
|
]
|
|
run_program(hca_files, cmd="clHCA")
|
|
|
|
basenames = [os.path.splitext(os.path.basename(file))[0] for file in acb_files]
|
|
char_secs = [basename.split("_", maxsplit=1) for basename in basenames]
|
|
for cs in char_secs:
|
|
char = cs[0]
|
|
sec = str(cs[1]) if len(cs) == 2 else ""
|
|
os.makedirs(os.path.join(to_dir, char, sec), exist_ok=True)
|
|
wav_files = glob(
|
|
"{}/{}_{}/**/*.wav".format(from_dir, acb_prefix, "_".join(cs)),
|
|
recursive=True,
|
|
)
|
|
partial_ffmpeg_cmd = functools.partial(run_program, cmd="ffmpeg")
|
|
|
|
wav_cmds = [
|
|
[
|
|
"-i",
|
|
os.path.abspath(file),
|
|
"-acodec",
|
|
"libopus",
|
|
"-ab",
|
|
"192k",
|
|
"-af",
|
|
"aresample=48000",
|
|
os.path.abspath(
|
|
"{}/{}/{}/{}.opus".format(
|
|
to_dir,
|
|
char,
|
|
sec,
|
|
os.path.splitext(os.path.basename(file))[0],
|
|
)
|
|
),
|
|
"-n",
|
|
]
|
|
for file in wav_files
|
|
]
|
|
pool.map(partial_ffmpeg_cmd, wav_cmds)
|
|
|
|
copy_tree(os.path.join(extract_dir, to_dir), os.path.join(update_dir, "Voice"))
|
|
|
|
|
|
def process_movie(cache_dir, extract_dir, update_dir):
|
|
copy_tree(
|
|
os.path.join(cache_dir, "Common/Asset/Movie"),
|
|
os.path.join(extract_dir, "Movie"),
|
|
)
|
|
|
|
from_dir = "Movie"
|
|
to_dir = "Movie_Extracted"
|
|
|
|
pool = get_pool()
|
|
|
|
with change_cwd(extract_dir):
|
|
os.makedirs(to_dir, exist_ok=True)
|
|
|
|
to_del = glob("{}/**/*.adx".format(from_dir), recursive=True)
|
|
to_del.extend(glob("{}/**/*.m2v".format(from_dir), recursive=True))
|
|
for file in to_del:
|
|
os.remove(file)
|
|
|
|
movie_paths = [
|
|
os.path.abspath(os.path.splitext(file)[0])
|
|
for file in glob("{}/*.usm".format(from_dir))
|
|
if not os.path.basename(file).startswith("mini_radio")
|
|
]
|
|
|
|
usm_files = [[path + ".usm"] for path in movie_paths]
|
|
usm_cmd = get_dotnet_cmd("usm_extract.exe")
|
|
partial_usm_cmd = functools.partial(run_program, cmd=usm_cmd)
|
|
pool.map(partial_usm_cmd, usm_files)
|
|
|
|
partial_ffmpeg_cmd = functools.partial(run_program, cmd="ffmpeg")
|
|
mux_cmds = [
|
|
[
|
|
"-i",
|
|
path + ".adx",
|
|
"-i",
|
|
path + ".m2v",
|
|
"-c:a",
|
|
"libopus",
|
|
"-b:a",
|
|
"196k",
|
|
"-af",
|
|
"aresample=48000",
|
|
"-c:v",
|
|
"libvpx",
|
|
"-b:v",
|
|
"1M",
|
|
"-threads",
|
|
"1",
|
|
os.path.abspath("{}/{}.webm".format(to_dir, os.path.basename(path))),
|
|
"-n",
|
|
]
|
|
for path in movie_paths
|
|
]
|
|
pool.map(partial_ffmpeg_cmd, mux_cmds)
|
|
|
|
copy_tree(
|
|
os.path.join(extract_dir, to_dir), os.path.join(update_dir, "Asset", "Movie")
|
|
)
|
|
|
|
|
|
@contextmanager
|
|
def change_cwd(new_path):
|
|
old_cwd = os.getcwd()
|
|
os.chdir(new_path)
|
|
try:
|
|
yield
|
|
finally:
|
|
os.chdir(old_cwd)
|
|
|
|
|
|
def get_dotnet_cmd(name):
|
|
ext = os.path.splitext(name)[1]
|
|
if ext != ".exe":
|
|
raise RuntimeError("This doesn't seem like a .NET program.")
|
|
path = shutil.which(name)
|
|
if OPERATING_SYSTEM == "nt":
|
|
return [path]
|
|
return ["mono", path]
|
|
|
|
|
|
def run_program(args, cmd=None):
|
|
if isinstance(cmd, str):
|
|
cmd = [cmd]
|
|
full_cmd = cmd + args
|
|
subprocess.run(full_cmd)
|
|
|
|
|
|
def get_pool(size=multiprocessing.cpu_count()):
|
|
pool = multiprocessing.Pool(size)
|
|
return pool
|