feat(app): Mikrofon-Monitor in App integriert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 18:15:59 +02:00
parent d0aca751bd
commit 8e05c5b62d
+52
View File
@@ -5,6 +5,7 @@ import logging
import sys import sys
from whisper_local.config import Config, load_config from whisper_local.config import Config, load_config
from whisper_local.microphone import create_monitor
from whisper_local.hotkey import create_listener from whisper_local.hotkey import create_listener
from whisper_local.inserter import create_inserter from whisper_local.inserter import create_inserter
from whisper_local.media import create_media_controller from whisper_local.media import create_media_controller
@@ -52,6 +53,10 @@ class App:
self.hotkey = create_listener(key_name=config.hotkey) self.hotkey = create_listener(key_name=config.hotkey)
self.hotkey.on_press = self.on_press self.hotkey.on_press = self.on_press
self.hotkey.on_release = self.on_release self.hotkey.on_release = self.on_release
self.monitor = create_monitor(config.microphone or None)
self.monitor.on_device_added = self._on_microphone_added
self.monitor.on_device_removed = self._on_microphone_removed
self.monitor.on_configured_missing = self._on_configured_microphone_missing
self.tray = create_tray(on_settings=self._open_settings, on_quit=self._quit) self.tray = create_tray(on_settings=self._open_settings, on_quit=self._quit)
async def on_press(self) -> None: async def on_press(self) -> None:
@@ -93,6 +98,44 @@ class App:
from whisper_local.tray._settings import SettingsDialog from whisper_local.tray._settings import SettingsDialog
SettingsDialog(config=self._config, on_save=self._on_config_reload).open() SettingsDialog(config=self._config, on_save=self._on_config_reload).open()
async def _on_configured_microphone_missing(self) -> None:
"""Konfiguriertes Mikrofon nicht gefunden — auf Standard wechseln."""
from whisper_local.tray._notification import notify
device_name = self._config.microphone or "Mikrofon"
logger.warning("Konfiguriertes Mikrofon '%s' nicht gefunden, nutze Standard", device_name)
self.recorder = Recorder(
sample_rate=self._config.sample_rate,
channels=self._config.channels,
min_duration=self._config.min_duration,
device=None,
)
notify(
"Mikrofon nicht gefunden",
f'{device_name}“ ist nicht verfügbar. Standard-Mikrofon wird verwendet.',
)
self.tray.set_warning("Mikrofon nicht gefunden")
async def _on_microphone_added(self, device_name: str) -> None:
"""Neues Mikrofon erkannt — konfiguriertes Gerät ggf. wiederherstellen."""
if device_name != self._config.microphone:
return
from whisper_local.tray._notification import notify
logger.info("Konfiguriertes Mikrofon '%s' wieder verfügbar", device_name)
self.recorder = Recorder(
sample_rate=self._config.sample_rate,
channels=self._config.channels,
min_duration=self._config.min_duration,
device=self._config.microphone or None,
)
notify("Mikrofon verbunden", f'{device_name}" ist wieder verfügbar.')
self.tray.set_warning(None)
async def _on_microphone_removed(self, device_name: str) -> None:
"""Mikrofon entfernt — konfiguriertes Gerät → Fallback auslösen."""
logger.info("Mikrofon entfernt: %s", device_name)
if device_name == self._config.microphone:
await self._on_configured_microphone_missing()
def _on_config_reload(self, new_config: Config) -> None: def _on_config_reload(self, new_config: Config) -> None:
"""Übernimmt neue Konfiguration ohne App-Neustart.""" """Übernimmt neue Konfiguration ohne App-Neustart."""
self._config = new_config self._config = new_config
@@ -102,6 +145,14 @@ class App:
min_duration=new_config.min_duration, min_duration=new_config.min_duration,
device=new_config.microphone or None, device=new_config.microphone or None,
) )
self.monitor.stop()
self.monitor = create_monitor(new_config.microphone or None)
self.monitor.on_device_added = self._on_microphone_added
self.monitor.on_device_removed = self._on_microphone_removed
self.monitor.on_configured_missing = self._on_configured_microphone_missing
if self._loop is not None:
asyncio.run_coroutine_threadsafe(self.monitor.start(), self._loop)
self.tray.set_warning(None)
old_media = self.media old_media = self.media
self.media = create_media_controller( self.media = create_media_controller(
enabled=new_config.pause_media_during_recording enabled=new_config.pause_media_during_recording
@@ -128,6 +179,7 @@ class App:
logger.info("whisper-local gestartet, warte auf Hotkey...") logger.info("whisper-local gestartet, warte auf Hotkey...")
self.tray.start() self.tray.start()
self._hotkey_task = asyncio.create_task(self.hotkey.listen()) self._hotkey_task = asyncio.create_task(self.hotkey.listen())
asyncio.create_task(self.monitor.start())
await self._quit_event.wait() await self._quit_event.wait()