Loading nixos/modules/services/audio/music-assistant.nix +12 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,18 @@ in PYTHONPATH = finalPackage.pythonPath; }; path = with pkgs; [ lsof ] ++ lib.optionals (lib.elem "librespot" cfg.providers) [ librespot ] ++ lib.optionals (lib.elem "snapcast" cfg.providers) [ snapcast ]; serviceConfig = { ExecStart = utils.escapeSystemdExecArgs ( [ Loading pkgs/by-name/mu/music-assistant/dont-install-deps.patch +19 −7 Original line number Diff line number Diff line diff --git a/music_assistant/helpers/util.py b/music_assistant/helpers/util.py index 8daf159d..af5a6f38 100644 index 74540dd3..14f8f864 100644 --- a/music_assistant/helpers/util.py +++ b/music_assistant/helpers/util.py @@ -429,30 +429,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider def _get_provider_module(domain: str) -> ProviderModuleType: return importlib.import_module(f".{domain}", "music_assistant.providers") @@ -434,30 +434,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider "ProviderModuleType", importlib.import_module(f".{domain}", "music_assistant.providers") ) - # ensure module requirements are met - for requirement in requirements: Loading @@ -30,7 +30,19 @@ index 8daf159d..af5a6f38 100644 - # this will fail if something else is wrong (as it should) - return await asyncio.to_thread(_get_provider_module, domain) - + raise RuntimeError(f"Missing dependencies for provider {domain}.") + raise RuntimeError(f"Configure {domain} in `services.music-assistant.providers` to install the required dependencies.") def create_tempfile(): """Return a (named) temporary file.""" async def has_tmpfs_mount() -> bool: """Check if we have a tmpfs mount.""" diff --git a/music_assistant/providers/ytmusic/__init__.py b/music_assistant/providers/ytmusic/__init__.py index 52a7544a..816d0425 100644 --- a/music_assistant/providers/ytmusic/__init__.py +++ b/music_assistant/providers/ytmusic/__init__.py @@ -197,7 +197,6 @@ class YoutubeMusicProvider(MusicProvider): async def handle_async_init(self) -> None: """Set up the YTMusic provider.""" logging.getLogger("yt_dlp").setLevel(self.logger.level + 10) - await self._install_packages() self._cookie = self.config.get_value(CONF_COOKIE) self._po_token_server_url = ( self.config.get_value(CONF_PO_TOKEN_SERVER_URL) or DEFAULT_PO_TOKEN_SERVER_URL pkgs/by-name/mu/music-assistant/librespot.patch +0 −29 Original line number Diff line number Diff line diff --git a/music_assistant/providers/spotify/helpers.py b/music_assistant/providers/spotify/helpers.py index 8b6c4e78..20c2a269 100644 --- a/music_assistant/providers/spotify/helpers.py +++ b/music_assistant/providers/spotify/helpers.py @@ -11,23 +11,4 @@ from music_assistant.helpers.process import check_output async def get_librespot_binary() -> str: """Find the correct librespot binary belonging to the platform.""" - # ruff: noqa: SIM102 - async def check_librespot(librespot_path: str) -> str | None: - try: - returncode, output = await check_output(librespot_path, "--version") - if returncode == 0 and b"librespot" in output: - return librespot_path - except OSError: - return None - - base_path = os.path.join(os.path.dirname(__file__), "bin") - system = platform.system().lower().replace("darwin", "macos") - architecture = platform.machine().lower() - - if bridge_binary := await check_librespot( - os.path.join(base_path, f"librespot-{system}-{architecture}") - ): - return bridge_binary - - msg = f"Unable to locate Librespot for {system}/{architecture}" - raise RuntimeError(msg) + return "@librespot@" pkgs/by-name/mu/music-assistant/package.nix +10 −6 Original line number Diff line number Diff line Loading @@ -3,7 +3,6 @@ python3, fetchFromGitHub, ffmpeg-headless, librespot, nixosTests, replaceVars, providers ? [ ], Loading Loading @@ -48,14 +47,14 @@ assert python.pkgs.buildPythonApplication rec { pname = "music-assistant"; version = "2.5.5"; version = "2.5.8"; pyproject = true; src = fetchFromGitHub { owner = "music-assistant"; repo = "server"; tag = version; hash = "sha256-v9xFUjjk7KHsUtuZjQWLtc1m3f6VOUPlQtSBtUR6Pcg="; hash = "sha256-7Q+BYw7wnT7QdqrDjagaxupzD0iKTc26z4TfxNtugdA="; }; patches = [ Loading @@ -63,9 +62,9 @@ python.pkgs.buildPythonApplication rec { ffmpeg = "${lib.getBin ffmpeg-headless}/bin/ffmpeg"; ffprobe = "${lib.getBin ffmpeg-headless}/bin/ffprobe"; }) (replaceVars ./librespot.patch { librespot = lib.getExe librespot; }) # Look up librespot from PATH at runtime ./librespot.patch # Disable interactive dependency resolution, which clashes with the immutable Python environment ./dont-install-deps.patch Loading Loading @@ -95,6 +94,11 @@ python.pkgs.buildPythonApplication rec { "zeroconf" ]; pythonRemoveDeps = [ # no runtime dependency resolution "uv" ]; dependencies = with python.pkgs; [ Loading pkgs/by-name/mu/music-assistant/providers.nix +3 −2 Original line number Diff line number Diff line # Do not edit manually, run ./update-providers.py { version = "2.5.5"; version = "2.5.8"; providers = { airplay = ps: [ ]; Loading Loading @@ -131,9 +131,10 @@ ]; ytmusic = ps: with ps; [ bgutil-ytdlp-pot-provider duration-parser yt-dlp ytmusicapi ]; # missing bgutil-ytdlp-pot-provider ]; }; } Loading
nixos/modules/services/audio/music-assistant.nix +12 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,18 @@ in PYTHONPATH = finalPackage.pythonPath; }; path = with pkgs; [ lsof ] ++ lib.optionals (lib.elem "librespot" cfg.providers) [ librespot ] ++ lib.optionals (lib.elem "snapcast" cfg.providers) [ snapcast ]; serviceConfig = { ExecStart = utils.escapeSystemdExecArgs ( [ Loading
pkgs/by-name/mu/music-assistant/dont-install-deps.patch +19 −7 Original line number Diff line number Diff line diff --git a/music_assistant/helpers/util.py b/music_assistant/helpers/util.py index 8daf159d..af5a6f38 100644 index 74540dd3..14f8f864 100644 --- a/music_assistant/helpers/util.py +++ b/music_assistant/helpers/util.py @@ -429,30 +429,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider def _get_provider_module(domain: str) -> ProviderModuleType: return importlib.import_module(f".{domain}", "music_assistant.providers") @@ -434,30 +434,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider "ProviderModuleType", importlib.import_module(f".{domain}", "music_assistant.providers") ) - # ensure module requirements are met - for requirement in requirements: Loading @@ -30,7 +30,19 @@ index 8daf159d..af5a6f38 100644 - # this will fail if something else is wrong (as it should) - return await asyncio.to_thread(_get_provider_module, domain) - + raise RuntimeError(f"Missing dependencies for provider {domain}.") + raise RuntimeError(f"Configure {domain} in `services.music-assistant.providers` to install the required dependencies.") def create_tempfile(): """Return a (named) temporary file.""" async def has_tmpfs_mount() -> bool: """Check if we have a tmpfs mount.""" diff --git a/music_assistant/providers/ytmusic/__init__.py b/music_assistant/providers/ytmusic/__init__.py index 52a7544a..816d0425 100644 --- a/music_assistant/providers/ytmusic/__init__.py +++ b/music_assistant/providers/ytmusic/__init__.py @@ -197,7 +197,6 @@ class YoutubeMusicProvider(MusicProvider): async def handle_async_init(self) -> None: """Set up the YTMusic provider.""" logging.getLogger("yt_dlp").setLevel(self.logger.level + 10) - await self._install_packages() self._cookie = self.config.get_value(CONF_COOKIE) self._po_token_server_url = ( self.config.get_value(CONF_PO_TOKEN_SERVER_URL) or DEFAULT_PO_TOKEN_SERVER_URL
pkgs/by-name/mu/music-assistant/librespot.patch +0 −29 Original line number Diff line number Diff line diff --git a/music_assistant/providers/spotify/helpers.py b/music_assistant/providers/spotify/helpers.py index 8b6c4e78..20c2a269 100644 --- a/music_assistant/providers/spotify/helpers.py +++ b/music_assistant/providers/spotify/helpers.py @@ -11,23 +11,4 @@ from music_assistant.helpers.process import check_output async def get_librespot_binary() -> str: """Find the correct librespot binary belonging to the platform.""" - # ruff: noqa: SIM102 - async def check_librespot(librespot_path: str) -> str | None: - try: - returncode, output = await check_output(librespot_path, "--version") - if returncode == 0 and b"librespot" in output: - return librespot_path - except OSError: - return None - - base_path = os.path.join(os.path.dirname(__file__), "bin") - system = platform.system().lower().replace("darwin", "macos") - architecture = platform.machine().lower() - - if bridge_binary := await check_librespot( - os.path.join(base_path, f"librespot-{system}-{architecture}") - ): - return bridge_binary - - msg = f"Unable to locate Librespot for {system}/{architecture}" - raise RuntimeError(msg) + return "@librespot@"
pkgs/by-name/mu/music-assistant/package.nix +10 −6 Original line number Diff line number Diff line Loading @@ -3,7 +3,6 @@ python3, fetchFromGitHub, ffmpeg-headless, librespot, nixosTests, replaceVars, providers ? [ ], Loading Loading @@ -48,14 +47,14 @@ assert python.pkgs.buildPythonApplication rec { pname = "music-assistant"; version = "2.5.5"; version = "2.5.8"; pyproject = true; src = fetchFromGitHub { owner = "music-assistant"; repo = "server"; tag = version; hash = "sha256-v9xFUjjk7KHsUtuZjQWLtc1m3f6VOUPlQtSBtUR6Pcg="; hash = "sha256-7Q+BYw7wnT7QdqrDjagaxupzD0iKTc26z4TfxNtugdA="; }; patches = [ Loading @@ -63,9 +62,9 @@ python.pkgs.buildPythonApplication rec { ffmpeg = "${lib.getBin ffmpeg-headless}/bin/ffmpeg"; ffprobe = "${lib.getBin ffmpeg-headless}/bin/ffprobe"; }) (replaceVars ./librespot.patch { librespot = lib.getExe librespot; }) # Look up librespot from PATH at runtime ./librespot.patch # Disable interactive dependency resolution, which clashes with the immutable Python environment ./dont-install-deps.patch Loading Loading @@ -95,6 +94,11 @@ python.pkgs.buildPythonApplication rec { "zeroconf" ]; pythonRemoveDeps = [ # no runtime dependency resolution "uv" ]; dependencies = with python.pkgs; [ Loading
pkgs/by-name/mu/music-assistant/providers.nix +3 −2 Original line number Diff line number Diff line # Do not edit manually, run ./update-providers.py { version = "2.5.5"; version = "2.5.8"; providers = { airplay = ps: [ ]; Loading Loading @@ -131,9 +131,10 @@ ]; ytmusic = ps: with ps; [ bgutil-ytdlp-pot-provider duration-parser yt-dlp ytmusicapi ]; # missing bgutil-ytdlp-pot-provider ]; }; }