87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Delete failed (near-silent) generations and rename every SFX candidate to a
|
|
canonical `SFX-<family>-<number>-<event_name>.v<NN>.mp3` scheme taken from the
|
|
contract's SFX ledger, keeping processed files, sidecars and raw archives aligned.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
CANDIDATES = ROOT / "docs/audio/sfx/candidates/sfx"
|
|
RAW = ROOT / "docs/audio/sfx/candidates/sfx/raw"
|
|
CONTRACT = ROOT / "docs/04_ART_ANIMATION_AUDIO.md"
|
|
|
|
FAILED = [
|
|
"SFX-EQP-015-cloth_wrap_drawn_back_from_an_artifact.v01.mp3",
|
|
"SFX-ORD-002-tile_moved_a_short_distance_across_felt.v01.mp3",
|
|
"SFX-ORD-004-tile_bumped_against_a_blocked_edge_and_r.v01.mp3",
|
|
"SFX-ORD-015-new_tile_added_to_the_board_with_a_firm_.v01.mp3",
|
|
"SFX-RES-010-rope_snapped_taut_and_the_channel_releas.v01.mp3",
|
|
"SFX-UI-003-muted_cloth-covered_tap_that_goes_nowher.v01.mp3",
|
|
"SFX-UI-019-brass_stamp_lifted_away_before_contact_a.v01.mp3",
|
|
"SFX-UI-023-cloth_wiped_across_a_wooden_desk.v01.mp3",
|
|
]
|
|
|
|
PATTERN = re.compile(r"^(SFX-(?:UI|SHP|EQP|ORD|RES|RUN)-\d{3})-.*?\.(v\d+)\.mp3$")
|
|
|
|
|
|
def load_event_names() -> dict[str, str]:
|
|
names: dict[str, str] = {}
|
|
for line in CONTRACT.read_text().splitlines():
|
|
match = re.match(r"^(SFX-(?:UI|SHP|EQP|ORD|RES|RUN)-\d{3})\s+(\S+)\s*$", line.strip())
|
|
if match:
|
|
names[match.group(1)] = match.group(2)
|
|
return names
|
|
|
|
|
|
def main() -> int:
|
|
names = load_event_names()
|
|
removed = 0
|
|
for name in FAILED:
|
|
for path in (CANDIDATES / name, CANDIDATES / f"{name}.meta.json", RAW / name):
|
|
if path.exists():
|
|
path.unlink()
|
|
if path.parent == CANDIDATES:
|
|
removed += 1
|
|
renamed = 0
|
|
for path in sorted(CANDIDATES.glob("*.mp3")):
|
|
match = PATTERN.match(path.name)
|
|
if not match:
|
|
continue
|
|
event_id, variant = match.group(1), match.group(2)
|
|
event_name = names.get(event_id)
|
|
if not event_name:
|
|
print(f"WARN no contract name for {event_id}")
|
|
continue
|
|
target = path.with_name(f"{event_id}-{event_name}.{variant}.mp3")
|
|
if target == path:
|
|
continue
|
|
if target.exists():
|
|
print(f"SKIP collision {target.name}")
|
|
continue
|
|
path.rename(target)
|
|
sidecar = path.with_name(path.name + ".meta.json")
|
|
if sidecar.exists():
|
|
sidecar.rename(target.with_name(target.name + ".meta.json"))
|
|
raw_source = RAW / path.name
|
|
if raw_source.exists():
|
|
raw_source.rename(RAW / target.name)
|
|
renamed += 1
|
|
for sidecar in sorted(CANDIDATES.glob("*.meta.json")):
|
|
text = sidecar.read_text()
|
|
try:
|
|
record = json.loads(text)
|
|
except json.JSONDecodeError:
|
|
continue
|
|
record["path"] = str(CANDIDATES / sidecar.name.removesuffix(".meta.json"))
|
|
sidecar.write_text(json.dumps(record, ensure_ascii=False, indent=1))
|
|
print(f"removed_failed={removed} renamed={renamed} total={len(list(CANDIDATES.glob('*.mp3')))}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|