1
0
mirror of https://github.com/Escartem/AnimeWwise.git synced 2026-06-05 07:50:23 +08:00
Files
AnimeWwise/extract.py
Escartem f55f188d43 cleanup
2024-07-24 09:58:43 +02:00

226 lines
5.6 KiB
Python

import os
import io
import sys
import time
import shutil
import filecmp
import tempfile
import wavescan
import subprocess
from mapper import Mapper
from allocator import Allocator
from filereader import FileReader
cwd = os.getcwd()
path = lambda path: os.path.join(cwd, path)
call = lambda args: subprocess.call(args, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
# TODO: handle hdiff, helper :
# hpathz.exe -f original.pck patch.hdiff output.pck
# diff = filecmp.dircmp(original, patched)
# new_files, changed_files = diff.right_only, diff.diff_files
class WwiseExtract:
def __init__(self):
self.allocator = Allocator()
### loading files ###
def load_folder(self, _map, path):
self.mapper = None
if _map is not None:
self.mapper = Mapper(os.path.join(os.getcwd(), f"maps/{_map}"))
self.file_structure = {"folders": {}, "files": []}
files = [f for f in os.listdir(path) if f.endswith(".pck")]
if len(files) == 0:
return None
for file in files:
self.load_file(os.path.join(path, file))
return self.file_structure
def load_file(self, _input):
with open(_input, "rb") as f:
data = f.read()
f.close()
self.get_wems(data, os.path.basename(_input))
def get_wems(self, data, filename):
reader = FileReader(io.BytesIO(data), "little")
files = wavescan.get_data(reader)
self.map_names(files, filename)
def map_names(self, files, filename):
mapper = self.mapper
base = self.file_structure
for file in files:
if mapper is not None:
key = mapper.get_key(file[0].split(".")[0])
else:
key = None
if key is not None:
self.add_to_structure(f"{filename}\\{key[0]}.wem".split("\\"), [file[1], file[2]])
else:
temp = base["folders"]
if filename not in temp:
temp[filename] = {"folders": {}, "files": []}
temp = temp[filename]["folders"]
if "unmapped" not in temp:
temp["unmapped"] = {"folders": {}, "files": []}
temp["unmapped"]["files"].append(file)
self.file_structure = base
def add_to_structure(self, parts, meta):
current_level = self.file_structure
for part in parts[:-1]:
if "folders" not in current_level:
current_level["folders"] = {}
if part not in current_level["folders"]:
current_level["folders"][part] = {"folders": {}, "files": []}
current_level = current_level["folders"][part]
if "files" not in current_level:
current_level["files"] = []
current_level["files"].append([parts[-1], meta[0], meta[1]])
### extracting files ###
def extract_files(self, _input, files, output, _format, progress):
temp_dir = tempfile.TemporaryDirectory()
self.progress = progress
self.steps = {
"wem": 1,
"wav": 2,
"mp3": 3,
"ogg": 3
}[_format]
# wem
if _format == "wem":
output_folder = output
else:
output_folder = os.path.join(temp_dir.name, "wem")
self.extract_wem(_input, files, output_folder)
if _format == "wem":
temp_dir.cleanup()
return
# wav
new_input = output_folder
files = [os.path.join("/".join(file["path"]), file["name"]) for file in files]
if _format == "wav":
output_folder = output
else:
output_folder = os.path.join(temp_dir.name, "wav")
self.extract_wav(new_input, files, output_folder)
if _format == "wav":
temp_dir.cleanup()
return
# mp3 & ogg
files = [os.path.join(os.path.dirname(file), f'{os.path.basename(file).split(".")[0]}.wav') for file in files]
new_input = output_folder
output_folder = output
self.extract_ffmpeg(new_input, files, output_folder, _format)
temp_dir.cleanup()
return
def extract_wem(self, _input, files, output):
print(": Extracting audio as wem")
all_sources = list(set([e["source"] for e in files]))
for source in all_sources:
self.allocator.load_file(os.path.join(_input, source))
pos = 0
for file in files:
pos += 1
self.update_progress(pos, len(files), 1)
data = self.allocator.read_at(file["source"], file["offset"], file["size"])
filepath = os.path.join("/".join(file["path"]), file["name"])
fullpath = os.path.join(output, filepath)
os.makedirs(os.path.dirname(fullpath), exist_ok=True)
with open(fullpath, "wb") as f:
f.write(data)
f.close()
self.allocator.free_mem()
def extract_wav(self, _input, files, output):
print(": Converting audio to wav")
pos = 0
for file in files:
pos += 1
self.update_progress(pos, len(files), 2)
filename = f'{os.path.basename(file).split(".")[0]}.wav'
filepath = os.path.join(output, os.path.dirname(file), filename)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
args = [
path("tools/vgmstream/vgmstream-cli.exe"),
"-o",
filepath,
os.path.join(_input, file)
]
call(args)
def extract_ffmpeg(self, _input, files, output, _format):
print(f": Converting audio to {_format}")
encoders = {
"mp3": "libmp3lame",
"ogg": "libvorbis"
}
encoder = encoders[_format]
pos = 0
for file in files:
pos += 1
self.update_progress(pos, len(files), 3)
filename = f'{os.path.basename(file).split(".")[0]}.{_format}'
filepath = os.path.join(output, os.path.dirname(file), filename)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
args = [
path("tools/ffmpeg/ffmpeg.exe"),
"-i",
os.path.join(_input, file),
"-acodec",
encoder,
"-b:a",
"192k", # 192|4
filepath
]
call(args)
### other ###
def update_progress(self, current, total, step):
base = 100 / self.steps
self.progress(["total", current * base // total + base * (step - 1)])
self.progress(["file", current * 100 // total])
def reset(self):
if self.mapper is not None:
self.mapper.reset()
self.allocator.free_mem()