""" Stream controller - manages input sources and orchestrates the render stream. """ from engine.config import Config, get_config from engine.eventbus import EventBus from engine.events import EventType, StreamEvent from engine.mic import MicMonitor from engine.ntfy import NtfyPoller from engine.scroll import stream from engine.websocket_display import WebSocketDisplay def _get_display(config: Config): """Get the appropriate display based on config.""" if config.websocket: ws = WebSocketDisplay(host="0.0.0.0", port=config.websocket_port) ws.start_server() ws.start_http_server() return ws return None class StreamController: """Controls the stream lifecycle - initializes sources and runs the stream.""" def __init__(self, config: Config | None = None, event_bus: EventBus | None = None): self.config = config or get_config() self.event_bus = event_bus self.mic: MicMonitor | None = None self.ntfy: NtfyPoller | None = None def initialize_sources(self) -> tuple[bool, bool]: """Initialize microphone and ntfy sources. Returns: (mic_ok, ntfy_ok) - success status for each source """ self.mic = MicMonitor(threshold_db=self.config.mic_threshold_db) mic_ok = self.mic.start() if self.mic.available else False self.ntfy = NtfyPoller( self.config.ntfy_topic, reconnect_delay=self.config.ntfy_reconnect_delay, display_secs=self.config.message_display_secs, ) ntfy_ok = self.ntfy.start() return bool(mic_ok), ntfy_ok def run(self, items: list) -> None: """Run the stream with initialized sources.""" if self.mic is None or self.ntfy is None: self.initialize_sources() if self.event_bus: self.event_bus.publish( EventType.STREAM_START, StreamEvent( event_type=EventType.STREAM_START, headline_count=len(items), ), ) display = _get_display(self.config) stream(items, self.ntfy, self.mic, display) if display: display.cleanup() if self.event_bus: self.event_bus.publish( EventType.STREAM_END, StreamEvent( event_type=EventType.STREAM_END, headline_count=len(items), ), ) def cleanup(self) -> None: """Clean up resources.""" if self.mic: self.mic.stop()