"""Media controller services.""" import os import platform from pathlib import Path from typing import TYPE_CHECKING if TYPE_CHECKING: from .media_controller import MediaController _controller_instance: "MediaController | None" = None def _is_android() -> bool: """Check if running on Android (e.g., via Termux).""" # Check for Android-specific paths and environment android_indicators = [ Path("/system/build.prop").exists(), Path("/data/data/com.termux").exists(), "ANDROID_ROOT" in os.environ, "TERMUX_VERSION" in os.environ, ] return any(android_indicators) def get_media_controller() -> "MediaController": """Get the platform-specific media controller instance. Returns: The media controller for the current platform Raises: RuntimeError: If the platform is not supported """ global _controller_instance if _controller_instance is not None: return _controller_instance system = platform.system() if system == "Windows": from ..config import settings from .windows_media import WindowsMediaController _controller_instance = WindowsMediaController(audio_device=settings.audio_device) elif system == "Linux": # Check if running on Android if _is_android(): from .android_media import AndroidMediaController _controller_instance = AndroidMediaController() else: from .linux_media import LinuxMediaController _controller_instance = LinuxMediaController() elif system == "Darwin": # macOS from .macos_media import MacOSMediaController _controller_instance = MacOSMediaController() else: raise RuntimeError(f"Unsupported platform: {system}") return _controller_instance def get_current_album_art() -> bytes | None: """Get the current album art bytes (synchronous, Windows-cached path). Windows pre-populates a module-level cache via the WinRT polling thread, so this stays sync. For Linux/macOS the controller fetches on demand — use ``get_current_album_art_async()`` from FastAPI handlers instead. """ system = platform.system() if system == "Windows": from .windows_media import get_current_album_art as _get_art return _get_art() return None async def get_current_album_art_async() -> bytes | None: """Cross-platform album art fetch. Awaits the controller's impl. Falls back to the sync Windows cache when running on Windows so we don't pay an extra coroutine hop for the existing path. """ system = platform.system() if system == "Windows": return get_current_album_art() controller = get_media_controller() try: return await controller.get_album_art() except Exception: # noqa: BLE001 — art is best-effort; never break the route return None def get_audio_devices() -> list[dict[str, str]]: """Get list of available audio output devices (Windows only for now).""" system = platform.system() if system == "Windows": from .windows_media import WindowsMediaController return WindowsMediaController.get_audio_devices() return [] __all__ = [ "get_media_controller", "get_current_album_art", "get_current_album_art_async", "get_audio_devices", ]