fix(ui): escape device names and test errors in the audio status label (#1043)
The Settings audio status label is set with Pango markup. A microphone named with '&' or '<' (or an audio test error carrying them) made the markup invalid, so GTK dropped the text. Escape both with GLib.markup_escape_text. Also correct the v0.17.0 notes in docs/UPDATE.md: the Snap never bundled VOSK; it installs the project without extras.
This commit is contained in:
+1
-1
@@ -324,7 +324,7 @@ See the [full changelog](https://github.com/VocaHQ/vocalinux/releases/tag/v0.18.
|
||||
- Distro matrix runs `install.sh` (#810)
|
||||
- `install.sh` Faster Whisper box is CPU CTranslate2 / INT8, not NVIDIA CUDA. The whisper.cpp GPU step does not install the CUDA toolkit; Vulkan is first, CUDA only if a toolkit is already on the machine (#826)
|
||||
|
||||
AppImage and Flatpak remain whisper.cpp only. Snap ships whisper.cpp plus VOSK. Faster Whisper and Parakeet are optional extras on `install.sh` / source installs.
|
||||
AppImage, Flatpak and Snap remain whisper.cpp only. Faster Whisper and Parakeet are optional extras on `install.sh` / source installs.
|
||||
|
||||
See the [full changelog](https://github.com/VocaHQ/vocalinux/releases/tag/v0.17.0).
|
||||
|
||||
|
||||
@@ -9977,7 +9977,10 @@ For now, the engine has been reverted to VOSK."""
|
||||
self.speech_engine.set_audio_device(device_index, device_name)
|
||||
|
||||
logger.info(f"Audio device changed to: [{device_index}] {device_name}")
|
||||
self.audio_test_status.set_markup(f"<i>Selected: {device_label}</i>")
|
||||
# Device names are free text ("Mic & Line", "<A2DP>"); escape them for Pango.
|
||||
self.audio_test_status.set_markup(
|
||||
f"<i>Selected: {GLib.markup_escape_text(device_label or '')}</i>"
|
||||
)
|
||||
|
||||
def _cancel_audio_test(self, *_args: object) -> None:
|
||||
"""Cancel capture and invalidate any queued result when Settings closes."""
|
||||
@@ -10048,7 +10051,7 @@ For now, the engine has been reverted to VOSK."""
|
||||
"<small>Check if microphone is muted or try a different device</small>"
|
||||
)
|
||||
else:
|
||||
error_msg = result.get("error", "Unknown error")
|
||||
error_msg = GLib.markup_escape_text(str(result.get("error", "Unknown error")))
|
||||
self.audio_test_status.set_markup(
|
||||
f"<span foreground='#c01c28'>✗ Test failed:</span> {error_msg}"
|
||||
)
|
||||
|
||||
@@ -679,6 +679,38 @@ class TestAudioDeviceTooltip:
|
||||
dialog.audio_device_combo.set_tooltip_text.assert_called_with(self._SOF)
|
||||
|
||||
|
||||
class TestAudioStatusMarkup:
|
||||
"""Device names and errors are free text; the status label parses Pango markup."""
|
||||
|
||||
def _glib(self) -> MagicMock:
|
||||
from xml.sax.saxutils import escape
|
||||
|
||||
return MagicMock(markup_escape_text=MagicMock(side_effect=escape))
|
||||
|
||||
def test_selected_device_name_is_escaped(self) -> None:
|
||||
settings_dialog = _load_settings_dialog()
|
||||
dialog = MagicMock(_initializing=False, _pulse_source_names={})
|
||||
dialog.audio_device_combo.get_active_id.return_value = "2"
|
||||
dialog.audio_device_combo.get_active_text.return_value = "Mic & Line <A2DP>"
|
||||
with patch.object(settings_dialog, "GLib", self._glib()):
|
||||
settings_dialog.SettingsDialog._on_audio_device_changed(dialog, None)
|
||||
dialog.audio_test_status.set_markup.assert_called_with(
|
||||
"<i>Selected: Mic & Line <A2DP></i>"
|
||||
)
|
||||
|
||||
def test_test_failure_message_is_escaped(self) -> None:
|
||||
settings_dialog = _load_settings_dialog()
|
||||
dialog = MagicMock()
|
||||
with patch.object(settings_dialog, "GLib", self._glib()):
|
||||
settings_dialog.SettingsDialog._handle_audio_test_result(
|
||||
dialog, {"success": False, "error": "Invalid device <hw:0,6> & busy"}
|
||||
)
|
||||
dialog.audio_test_status.set_markup.assert_called_with(
|
||||
"<span foreground='#c01c28'>✗ Test failed:</span> "
|
||||
"Invalid device <hw:0,6> & busy"
|
||||
)
|
||||
|
||||
|
||||
def _load_settings_dialog() -> ModuleType:
|
||||
"""Import settings_dialog with real GTK base classes so its methods are callable.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user