import os import random from run_utils import AMBIENCE_PATH, AMBIENCE_OPTIONS_PATH, AUDIO_DIR, parse_ambience_options try: import miniaudio HAS_AUDIO = True except ImportError: HAS_AUDIO = False class AmbiencePlayer: def __init__(self): self.current_ambience = 'silence' self._last_mtime = 0 self._options = {} self._device = None self._stream = None self._muted = False self.load_options() @property def available(self): return HAS_AUDIO @property def ambience_name(self): return self.current_ambience @property def is_muted(self): return self._muted def toggle_mute(self): self._muted = not self._muted if self._muted: self._stop() else: self._load_current() def load_options(self): self._options = parse_ambience_options() def _stop(self): if self._device: try: self._device.close() except Exception: pass self._device = None self._stream = None def poll(self): if not HAS_AUDIO: return try: mtime = os.path.getmtime(AMBIENCE_PATH) except OSError: return if mtime == self._last_mtime: return self._last_mtime = mtime try: name = AMBIENCE_PATH.read_text().strip().lower() except OSError: return self.current_ambience = name self._stop() if not self._muted and name != 'silence' and name in self._options: self._play_current() def _switch_to(self, name): if name == self.current_ambience: return self.current_ambience = name self._stop() if self._muted or name == 'silence' or name not in self._options: return self._play_current() def _play_current(self): tracks = self._options.get(self.current_ambience, []) valid = [t for t in tracks if t.exists()] if not valid: return track = random.choice(valid) try: self._stream = miniaudio.stream_file(str(track)) self._device = miniaudio.PlaybackDevice() self._device.start(self._stream) except Exception: self.current_ambience = None self._stop() def _load_current(self): if self.current_ambience and self.current_ambience != 'silence': self._play_current()