aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-28 04:24:06 -0400
committerhistoria <historiavg@proton.me>2026-08-28 04:24:06 -0400
commit0dda9a5921eafd03853d233e077138ff72d64e4d (patch)
treecbe811a8b0fe81745577ab3d8bdf680d77ff19d2
parent876a6eb3ba9974d0eadc1fd3f628dafdc56d8716 (diff)
downloadtts-audiobook-generator-0dda9a5921eafd03853d233e077138ff72d64e4d.tar.gz
feat: .wav hints for all voice directory pickers in tui
-rw-r--r--app/backends/audiocpp/wizard.py1
-rwxr-xr-xapp/backends/faster.py3
-rw-r--r--app/tests/test_backends_audiocpp.py4
-rw-r--r--app/tests/test_backends_faster.py5
-rw-r--r--app/tests/test_hub.py3
-rw-r--r--app/tests/test_tui.py21
-rw-r--r--app/ui/hub.py1
-rw-r--r--app/ui/tui.py2
8 files changed, 39 insertions, 1 deletions
diff --git a/app/backends/audiocpp/wizard.py b/app/backends/audiocpp/wizard.py
index 849ad5a..d85076a 100644
--- a/app/backends/audiocpp/wizard.py
+++ b/app/backends/audiocpp/wizard.py
@@ -464,6 +464,7 @@ def _wizard(stdscr, args: argparse.Namespace, parser: argparse.ArgumentParser
wav_field = {
"key": "wav_dir", "label": "Voice clone .wav directory",
"kind": "dir", "value": Path(wav_start) if wav_start else None,
+ "info": common.wav_dir_info, "preview": common.wav_dir_preview,
"visible": lambda fs: bool(s["include_clone"]),
}
fields.append(wav_field)
diff --git a/app/backends/faster.py b/app/backends/faster.py
index 3f279f8..285d865 100755
--- a/app/backends/faster.py
+++ b/app/backends/faster.py
@@ -217,7 +217,8 @@ def _wizard(stdscr, args: argparse.Namespace) -> Optional[dict]:
fields: List[dict] = [
{"key": "wav_dir", "label": "Voices directory", "kind": "dir",
"value": Path(args.input_dir) if args.input_dir is not None
- else wav_start},
+ else wav_start,
+ "info": common.wav_dir_info, "preview": common.wav_dir_preview},
{"key": "language", "label": "Language", "kind": "text",
"value": default_language,
"validate": lambda s: None if _try_language(s)
diff --git a/app/tests/test_backends_audiocpp.py b/app/tests/test_backends_audiocpp.py
index 4a8ee5f..95f8bec 100644
--- a/app/tests/test_backends_audiocpp.py
+++ b/app/tests/test_backends_audiocpp.py
@@ -2713,6 +2713,10 @@ class WizardNavigationTests(unittest.TestCase):
by_key = {f["key"]: f for f in fields}
self.assertEqual(by_key["wav_dir"]["value"],
Path(recorded_voices))
+ # The directory browser alerts on the .wavs it lists.
+ self.assertIs(by_key["wav_dir"]["info"], common.wav_dir_info)
+ self.assertIs(by_key["wav_dir"]["preview"],
+ common.wav_dir_preview)
return {f["key"]: f["value"] for f in fields}
with patch.object(make_server.build, "find_local_checkout",
diff --git a/app/tests/test_backends_faster.py b/app/tests/test_backends_faster.py
index 44f4907..2f21377 100644
--- a/app/tests/test_backends_faster.py
+++ b/app/tests/test_backends_faster.py
@@ -273,6 +273,11 @@ class WizardFormTests(unittest.TestCase):
captured["title"] = title
captured["keys"] = [f["key"] for f in fields]
by_key = {f["key"]: f for f in fields}
+ # The directory browser alerts on the .wavs it lists.
+ self.assertIs(by_key["wav_dir"]["info"],
+ make_voices.common.wav_dir_info)
+ self.assertIs(by_key["wav_dir"]["preview"],
+ make_voices.common.wav_dir_preview)
by_key["wav_dir"]["value"] = folder
return {f["key"]: f["value"] for f in fields}
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py
index 0bdf2d5..ee1425d 100644
--- a/app/tests/test_hub.py
+++ b/app/tests/test_hub.py
@@ -1596,6 +1596,9 @@ class ConvertFlowTests(unittest.TestCase):
mode_field["choices"]}, {13})
speaker_field = self._field("speaker")
clone_dir_field = self._field("clone_dir")
+ # The .wav directory browser alerts on the .wavs it lists.
+ self.assertIs(clone_dir_field["info"], hub.common.wav_dir_info)
+ self.assertIs(clone_dir_field["preview"], hub.common.wav_dir_preview)
clone_field = self._field("clone")
design_field = self._field("qwen_instructions")
# Speaker shows in custom mode; the .wav directory browser and
diff --git a/app/tests/test_tui.py b/app/tests/test_tui.py
index a0e0309..6fc3fd5 100644
--- a/app/tests/test_tui.py
+++ b/app/tests/test_tui.py
@@ -965,6 +965,27 @@ class FormTests(TuiTestCase):
self.assertEqual(Path(mk_browser.call_args[1]["start"]),
Path("/start"))
+ def test_dir_field_passes_info_and_preview_to_the_browser(self):
+ # A dir field may carry info/preview callbacks (e.g. the .wav
+ # count alerts); the form forwards them to the browser untouched.
+ def info(directory):
+ return ("info text", "ok")
+
+ def preview(directory):
+ return ("preview text", "warn")
+
+ picked = Path("/picked/voices")
+ fields = [{"key": "voices", "label": "Voices directory",
+ "kind": "dir", "value": Path("/start"),
+ "info": info, "preview": preview}]
+ with patch.object(tui, "browse_directory",
+ return_value=picked) as mk_browser:
+ screen = FakeScreen(keys=[10, 10])
+ result = tui.form(screen, "Settings", fields)
+ self.assertEqual(result, {"voices": picked})
+ self.assertIs(mk_browser.call_args[1]["info"], info)
+ self.assertIs(mk_browser.call_args[1]["preview"], preview)
+
def test_dir_pick_moves_focus_to_the_accept_button(self):
# Accepting a directory is a completed choice: focus lands on
# Save, so the very next Enter submits — no Tab hunting.
diff --git a/app/ui/hub.py b/app/ui/hub.py
index e17e862..8a6fda7 100644
--- a/app/ui/hub.py
+++ b/app/ui/hub.py
@@ -1428,6 +1428,7 @@ def _qwen_fields(remote_modes: Optional[list] = None,
"visible": lambda fs: _field_value(fs, prefix + "mode") == "custom"},
{"key": prefix + "clone_dir", "label": "Clone .wav directory",
"kind": "dir", "value": common.VOICES_DIR,
+ "info": common.wav_dir_info, "preview": common.wav_dir_preview,
"on_change": reset_clone_wav,
"visible": lambda fs: _field_value(fs, prefix + "mode") == "clone"},
{"key": prefix + "clone", "label": "Voice to clone",
diff --git a/app/ui/tui.py b/app/ui/tui.py
index e2216a3..b22a186 100644
--- a/app/ui/tui.py
+++ b/app/ui/tui.py
@@ -1207,6 +1207,8 @@ def form(scr, title: str, fields: Sequence[dict],
picked = browse_directory(
scr, field_label(field), start=start,
validate=field.get("validate"),
+ info=field.get("info"),
+ preview=field.get("preview"),
back_value=edit_cancel)
if picked is not edit_cancel:
field["value"] = picked