diff --git a/nixos/modules/services/audio/music-assistant.nix b/nixos/modules/services/audio/music-assistant.nix index 7757310817a1..c0aaacc756b6 100644 --- a/nixos/modules/services/audio/music-assistant.nix +++ b/nixos/modules/services/audio/music-assistant.nix @@ -82,7 +82,8 @@ in allowedTCPPorts = lib.optional cfg.enable 8097 # Music Assistant stream port ++ lib.optional (lib.elem "airplay" cfg.providers) 7000 - ++ lib.optional (lib.elem "sendspin" cfg.providers) 8927; + ++ lib.optional (lib.elem "sendspin" cfg.providers) 8927 + ++ lib.optional (lib.elem "snapcast" cfg.providers) 1780; # The information published by Apple 1 seem to not apply to libraop. # The closest we could find that represents the port range being used as observed by tcpdump is the ephemeral port range. # 1: https://support.apple.com/en-us/103229#:~:text=49152%E2%80%93-,65535,-TCP%2C%20UDP @@ -97,6 +98,7 @@ in services.avahi = lib.mkIf (lib.elem "airplay_receiver" cfg.providers) { enable = true; + openFirewall = lib.mkIf cfg.openFirewall true; publish = { enable = true; userServices = true; @@ -129,7 +131,7 @@ in ++ lib.optionals (lib.elem "airplay_receiver" cfg.providers) [ shairport-sync ] - ++ lib.optionals (lib.elem "spotify" cfg.providers) [ + ++ lib.optionals (lib.elem "spotify" cfg.providers || lib.elem "spotify_connect" cfg.providers) [ librespot-ma ] ++ lib.optionals (lib.elem "snapcast" cfg.providers) [ diff --git a/pkgs/by-name/cl/cliairplay/package.nix b/pkgs/by-name/cl/cliairplay/package.nix index 9b5aa51a4fe9..389e973e6cb6 100644 --- a/pkgs/by-name/cl/cliairplay/package.nix +++ b/pkgs/by-name/cl/cliairplay/package.nix @@ -4,7 +4,6 @@ bison, curl, fetchFromGitHub, - fetchpatch, ffmpeg-headless, flex, gperf, @@ -26,26 +25,18 @@ stdenv.mkDerivation { pname = "cliairplay"; # see the beginning of configure.ac for the upstream version number - version = "0.2-unstable-2025-12-30"; + version = "1.1-unstable-2026-03-16"; src = fetchFromGitHub { owner = "music-assistant"; repo = "cliairplay"; # we try to closely match the commit used in the last music-assistant release from # https://github.com/music-assistant/server/tree/stable/music_assistant/providers/airplay/bin - rev = "4660d886585d6bf8f32e889feec2a0e8975c51dc"; + rev = "991c65acc2afa17ffe32e279dbc585b0b7f530f8"; fetchSubmodules = true; - hash = "sha256-oDStn9LdLYWKhZNm7Qfdibs4qsct8gE3RZbTKooQeOM="; + hash = "sha256-m1O4l6gFEGNAyskYcRHcA15cubZnNgkaYjdVThRRX7w="; }; - patches = [ - # Support gettext 0.25 - (fetchpatch { - url = "https://github.com/music-assistant/cliairplay/commit/92a2445d64c476d740feba1f31c7e5bc768701b7.patch"; - hash = "sha256-/YnopvAGHHnQhfr2X1OenLMoF4ZlUq9x8tQZha/XfbQ="; - }) - ]; - nativeBuildInputs = [ autoreconfHook bison diff --git a/pkgs/by-name/li/libraop/package.nix b/pkgs/by-name/li/libraop/package.nix index 036cc1e311da..580213bc0865 100644 --- a/pkgs/by-name/li/libraop/package.nix +++ b/pkgs/by-name/li/libraop/package.nix @@ -16,16 +16,16 @@ let in stdenv.mkDerivation { pname = "libraop"; - version = "0-unstable-2026-02-09"; + version = "0-unstable-2026-02-20"; src = fetchFromGitHub { owner = "music-assistant"; repo = "libraop"; # we try to closely match the commit used in the last music-assistant release from # https://github.com/music-assistant/server/tree/stable/music_assistant/providers/airplay/bin - rev = "f49284282ea4ea740d07fabc230b4182f8c69a74"; + rev = "df3c055674c147eeaa9307b7d554b9d46ed6418a"; fetchSubmodules = true; - hash = "sha256-m1ll5vRZx4d/5IWCG24yY/SWEIIz2k/iU84vQKHlCdo="; + hash = "sha256-zD1DggBQjbiD7B/u0hmogXj8NhrzYgVXMyzvHkaM4Hg="; }; patches = [ diff --git a/pkgs/by-name/mu/music-assistant/builtin-snapcast-server.patch b/pkgs/by-name/mu/music-assistant/builtin-snapcast-server.patch index f361e9a7c235..27da1d878827 100644 --- a/pkgs/by-name/mu/music-assistant/builtin-snapcast-server.patch +++ b/pkgs/by-name/mu/music-assistant/builtin-snapcast-server.patch @@ -1,8 +1,8 @@ diff --git a/music_assistant/providers/snapcast/constants.py b/music_assistant/providers/snapcast/constants.py -index eb5ecb1a..92f03212 100644 +index 8c897c72..d89a0cd2 100644 --- a/music_assistant/providers/snapcast/constants.py +++ b/music_assistant/providers/snapcast/constants.py -@@ -43,7 +43,8 @@ CONTROL_SOCKET_PATH_TEMPLATE = "/tmp/ma-snapcast-{queue_id}.sock" # noqa: S108 +@@ -46,7 +46,8 @@ MASS_STREAM_PREFIX = "Music Assistant - " MASS_ANNOUNCEMENT_POSTFIX = " (announcement)" SNAPWEB_DIR = pathlib.Path(__file__).parent.resolve().joinpath("snapweb") @@ -13,18 +13,18 @@ index eb5ecb1a..92f03212 100644 DEFAULT_SNAPCAST_FORMAT = AudioFormat( content_type=ContentType.PCM_S16LE, diff --git a/music_assistant/providers/snapcast/provider.py b/music_assistant/providers/snapcast/provider.py -index 94c197fc..9a344f53 100644 +index 049fb934..316b6cf8 100644 --- a/music_assistant/providers/snapcast/provider.py +++ b/music_assistant/providers/snapcast/provider.py -@@ -32,6 +32,7 @@ from music_assistant.providers.snapcast.constants import ( +@@ -35,6 +35,7 @@ CONF_STREAM_IDLE_THRESHOLD, CONF_USE_EXTERNAL_SERVER, CONTROL_SCRIPT, + CONTROL_SCRIPT_DIR, - CONTROL_SOCKET_PATH_TEMPLATE, + DEFAULT_SNAPSERVER_CONFIG_FILE, + DEFAULT_SNAPSERVER_PLUGIN_DIR, DEFAULT_SNAPSERVER_PORT, - SNAPWEB_DIR, -@@ -215,6 +216,10 @@ class SnapCastProvider(PlayerProvider): +@@ -270,6 +271,10 @@ async def _builtin_server_runner(self) -> None: args = [ "snapserver", @@ -34,23 +34,14 @@ index 94c197fc..9a344f53 100644 + "--config=/dev/null", # config settings taken from # https://raw.githubusercontent.com/badaix/snapcast/86cd4b2b63e750a72e0dfe6a46d47caf01426c8d/server/etc/snapserver.conf - f"--server.datadir={self.mass.storage_path}", -@@ -227,6 +232,7 @@ class SnapCastProvider(PlayerProvider): - f"--stream.buffer={self._snapcast_server_buffer_size}", - f"--stream.chunk_ms={self._snapcast_server_chunk_ms}", - f"--stream.codec={self._snapcast_server_transport_codec}", -+ f"--stream.plugin_dir={CONTROL_SCRIPT_DIR}", + f"--config={self._snapcast_server_config_file}", +@@ -286,8 +291,7 @@ async def _builtin_server_runner(self) -> None: f"--stream.send_to_muted={str(self._snapcast_server_send_to_muted).lower()}", f"--streaming_client.initial_volume={self._snapcast_server_initial_volume}", ] -@@ -243,9 +249,7 @@ class SnapCastProvider(PlayerProvider): - # Copy control script after snapserver starts - # (run in executor to avoid blocking) - loop = asyncio.get_running_loop() -- self._controlscript_available = await loop.run_in_executor( -- None, self._setup_controlscript -- ) -+ self._controlscript_available = True - - def _get_ma_id(self, snap_client_id: str) -> str: - search_dict = self._ids_map.inverse +- loop = asyncio.get_running_loop() +- plugin_dir = await loop.run_in_executor(None, self._setup_controlscript) ++ plugin_dir = CONTROL_SCRIPT_DIR + if plugin_dir is not None: + args.append(f"--stream.plugin_dir={plugin_dir}") + self._controlscript_available = True diff --git a/pkgs/by-name/mu/music-assistant/cliraop-cliap2.patch b/pkgs/by-name/mu/music-assistant/cliraop-cliap2.patch index 33b856711eed..670de7d1bfe8 100644 --- a/pkgs/by-name/mu/music-assistant/cliraop-cliap2.patch +++ b/pkgs/by-name/mu/music-assistant/cliraop-cliap2.patch @@ -1,16 +1,16 @@ diff --git a/music_assistant/providers/airplay/helpers.py b/music_assistant/providers/airplay/helpers.py -index c5fef7eb..a628622d 100644 +index 0d03b2cd..9cd59cf0 100644 --- a/music_assistant/providers/airplay/helpers.py +++ b/music_assistant/providers/airplay/helpers.py -@@ -6,6 +6,7 @@ - import os - import platform +@@ -9,6 +9,7 @@ + import socket import time + from ipaddress import ip_address +from shutil import which from typing import TYPE_CHECKING - from zeroconf import IPVersion -@@ -176,7 +177,6 @@ async def check_binary(cli_path: str) -> str | None: + from music_assistant_models.enums import ContentType +@@ -226,7 +227,6 @@ async def check_binary(cli_path: str) -> str | None: pass return None @@ -18,7 +18,7 @@ index c5fef7eb..a628622d 100644 system = platform.system().lower().replace("darwin", "macos") architecture = platform.machine().lower() -@@ -188,7 +188,7 @@ async def check_binary(cli_path: str) -> str | None: +@@ -238,7 +238,7 @@ async def check_binary(cli_path: str) -> str | None: raise RuntimeError(f"Unsupported streaming protocol requested: {protocol}") if bridge_binary := await check_binary( diff --git a/pkgs/by-name/mu/music-assistant/dont-install-deps.patch b/pkgs/by-name/mu/music-assistant/dont-install-deps.patch index 0c6569078400..d074e18fa67c 100644 --- a/pkgs/by-name/mu/music-assistant/dont-install-deps.patch +++ b/pkgs/by-name/mu/music-assistant/dont-install-deps.patch @@ -1,8 +1,8 @@ diff --git a/music_assistant/helpers/util.py b/music_assistant/helpers/util.py -index bc14912b..0527a831 100644 +index e91cd933..ed96d9b5 100644 --- a/music_assistant/helpers/util.py +++ b/music_assistant/helpers/util.py -@@ -495,30 +495,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider +@@ -602,30 +602,11 @@ def _get_provider_module(domain: str) -> ProviderModuleType: "ProviderModuleType", importlib.import_module(f".{domain}", "music_assistant.providers") ) @@ -35,10 +35,10 @@ index bc14912b..0527a831 100644 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 9cc5981a..dc424b0b 100644 +index 0ac8a70f..5d74e25b 100644 --- a/music_assistant/providers/ytmusic/__init__.py +++ b/music_assistant/providers/ytmusic/__init__.py -@@ -200,7 +200,6 @@ class YoutubeMusicProvider(MusicProvider): +@@ -203,7 +203,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) @@ -46,7 +46,7 @@ index 9cc5981a..dc424b0b 100644 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 -@@ -1091,8 +1090,6 @@ class YoutubeMusicProvider(MusicProvider): +@@ -1103,8 +1102,6 @@ async def _install_packages(self) -> None: # NOTE: Google breaks things quite often which requires us to update # some packages very frequently. Installing them dynamically prevents # us from having to update MA to ensure this provider works. diff --git a/pkgs/by-name/mu/music-assistant/ffmpeg.patch b/pkgs/by-name/mu/music-assistant/ffmpeg.patch index 7f503117877e..a9af5333b828 100644 --- a/pkgs/by-name/mu/music-assistant/ffmpeg.patch +++ b/pkgs/by-name/mu/music-assistant/ffmpeg.patch @@ -1,10 +1,10 @@ diff --git a/music_assistant/controllers/streams/smart_fades/fades.py b/music_assistant/controllers/streams/smart_fades/fades.py -index 03c11ef9..460d53a6 100644 +index 59246cce..673c3a10 100644 --- a/music_assistant/controllers/streams/smart_fades/fades.py +++ b/music_assistant/controllers/streams/smart_fades/fades.py -@@ -76,7 +76,7 @@ class SmartFade(ABC): - async with aiofiles.open(fadeout_filename, "wb") as outfile: +@@ -86,7 +86,7 @@ async def apply( await outfile.write(fade_out_part) + args = [ - "ffmpeg", + "@ffmpeg@", @@ -12,19 +12,19 @@ index 03c11ef9..460d53a6 100644 "-loglevel", "error", diff --git a/music_assistant/helpers/audio.py b/music_assistant/helpers/audio.py -index 0674b009..53158f4d 100644 +index f7828a58..698751f9 100644 --- a/music_assistant/helpers/audio.py +++ b/music_assistant/helpers/audio.py -@@ -103,7 +103,7 @@ async def strip_silence( - reverse: bool = False, - ) -> bytes: - """Strip silence from begin or end of pcm audio using ffmpeg.""" +@@ -114,7 +114,7 @@ async def strip_silence( + :param pcm_format: AudioFormat of the audio data. + :param reverse: If True, strip from end instead of beginning. + """ - args = ["ffmpeg", "-hide_banner", "-loglevel", "quiet"] + args = ["@ffmpeg@", "-hide_banner", "-loglevel", "quiet"] args += [ "-acodec", pcm_format.content_type.name.lower(), -@@ -1134,7 +1134,7 @@ async def get_silence( +@@ -300,7 +300,7 @@ async def get_silence( return # use ffmpeg for all other encodings args = [ @@ -34,10 +34,10 @@ index 0674b009..53158f4d 100644 "-loglevel", "quiet", diff --git a/music_assistant/helpers/ffmpeg.py b/music_assistant/helpers/ffmpeg.py -index 9ea5ea0c..51b1d62b 100644 +index 9b7b1bbb..822424dc 100644 --- a/music_assistant/helpers/ffmpeg.py +++ b/music_assistant/helpers/ffmpeg.py -@@ -249,7 +249,7 @@ def get_ffmpeg_args( # noqa: PLR0915 +@@ -267,7 +267,7 @@ def get_ffmpeg_args( # noqa: PLR0915 extra_output_args = [] # generic args generic_args = [ @@ -46,7 +46,7 @@ index 9ea5ea0c..51b1d62b 100644 "-hide_banner", "-loglevel", loglevel, -@@ -416,7 +416,7 @@ async def check_ffmpeg_version() -> None: +@@ -434,7 +434,7 @@ async def check_ffmpeg_version() -> None: """Check if ffmpeg is present (with libsoxr support).""" # check for FFmpeg presence try: @@ -56,10 +56,10 @@ index 9ea5ea0c..51b1d62b 100644 raise AudioError( "FFmpeg binary is missing from system. " diff --git a/music_assistant/helpers/tags.py b/music_assistant/helpers/tags.py -index fe83301c..d35760b6 100644 +index b50633f0..51e8ec7b 100644 --- a/music_assistant/helpers/tags.py +++ b/music_assistant/helpers/tags.py -@@ -484,7 +484,7 @@ def parse_tags( +@@ -666,7 +666,7 @@ def parse_tags( Input_file may be a (local) filename or URL accessible by ffmpeg. """ args = ( @@ -68,7 +68,7 @@ index fe83301c..d35760b6 100644 "-hide_banner", "-loglevel", "fatal", -@@ -551,7 +551,7 @@ def get_file_duration(input_file: str) -> float: +@@ -737,7 +737,7 @@ def get_file_duration(input_file: str) -> float: NOT Async friendly. """ args = ( @@ -77,7 +77,7 @@ index fe83301c..d35760b6 100644 "-hide_banner", "-loglevel", "info", -@@ -707,7 +707,7 @@ async def get_embedded_image(input_file: str) -> bytes | None: +@@ -1368,7 +1368,7 @@ async def get_embedded_image(input_file: str) -> bytes | None: # Use FFmpeg for all other cases (URLs, ID3 tags, Vorbis comments, etc.) args = [ diff --git a/pkgs/by-name/mu/music-assistant/fix-webserver-tests-in-sandbox.patch b/pkgs/by-name/mu/music-assistant/fix-webserver-tests-in-sandbox.patch index 69b6a0f3f52b..abcc674c972c 100644 --- a/pkgs/by-name/mu/music-assistant/fix-webserver-tests-in-sandbox.patch +++ b/pkgs/by-name/mu/music-assistant/fix-webserver-tests-in-sandbox.patch @@ -1,8 +1,8 @@ diff --git a/music_assistant/helpers/util.py b/music_assistant/helpers/util.py -index 377c7221..aaf6460d 100644 +index e91cd933..088e76b7 100644 --- a/music_assistant/helpers/util.py +++ b/music_assistant/helpers/util.py -@@ -305,7 +305,7 @@ async def get_ip_addresses(include_ipv6: bool = False) -> tuple[str, ...]: +@@ -365,7 +365,7 @@ def call() -> tuple[str, ...]: continue # ifaddr returns IPv6 addresses as (address, flowinfo, scope_id) tuples ip_str = ip.ip[0] if isinstance(ip.ip, tuple) else ip.ip diff --git a/pkgs/by-name/mu/music-assistant/frontend.nix b/pkgs/by-name/mu/music-assistant/frontend.nix index b401e501ccc1..ab091182c71e 100644 --- a/pkgs/by-name/mu/music-assistant/frontend.nix +++ b/pkgs/by-name/mu/music-assistant/frontend.nix @@ -2,18 +2,19 @@ lib, buildPythonPackage, fetchPypi, + music-assistant, setuptools, }: buildPythonPackage rec { pname = "music-assistant-frontend"; - version = "2.17.73"; + version = "2.17.146"; pyproject = true; src = fetchPypi { pname = "music_assistant_frontend"; inherit version; - hash = "sha256-vmZa98pT5Cg22fa73/KTrMUqP4Axc1y4x710HCxBzIY="; + hash = "sha256-VU2SXL6SLFiKntmJJtCabBOYOeImYFPHYxvMPmnhmEc="; }; build-system = [ setuptools ]; @@ -27,6 +28,6 @@ buildPythonPackage rec { description = "Music Assistant frontend"; homepage = "https://github.com/music-assistant/frontend"; license = lib.licenses.asl20; - maintainers = with lib.maintainers; [ hexa ]; + inherit (music-assistant.meta) maintainers; }; } diff --git a/pkgs/by-name/mu/music-assistant/librespot.patch b/pkgs/by-name/mu/music-assistant/librespot.patch index 268b7339834c..053d9df434c4 100644 --- a/pkgs/by-name/mu/music-assistant/librespot.patch +++ b/pkgs/by-name/mu/music-assistant/librespot.patch @@ -2,7 +2,7 @@ diff --git a/music_assistant/providers/spotify/helpers.py b/music_assistant/prov index fe7af648..3f5121de 100644 --- a/music_assistant/providers/spotify/helpers.py +++ b/music_assistant/providers/spotify/helpers.py -@@ -6,6 +6,7 @@ import asyncio +@@ -6,6 +6,7 @@ import os import platform import time @@ -10,7 +10,7 @@ index fe7af648..3f5121de 100644 from typing import TYPE_CHECKING, Any from urllib.parse import urlencode -@@ -35,12 +36,8 @@ async def get_librespot_binary() -> str: +@@ -35,12 +36,8 @@ async def check_librespot(librespot_path: str) -> str | None: except OSError: return None diff --git a/pkgs/by-name/mu/music-assistant/package.nix b/pkgs/by-name/mu/music-assistant/package.nix index bf28c26fbe79..f98fb76bfcce 100644 --- a/pkgs/by-name/mu/music-assistant/package.nix +++ b/pkgs/by-name/mu/music-assistant/package.nix @@ -14,20 +14,12 @@ let packageOverrides = self: super: { music-assistant-frontend = self.callPackage ./frontend.nix { }; - music-assistant-models = super.music-assistant-models.overridePythonAttrs (oldAttrs: rec { - version = "1.1.86"; + music-assistant-models = super.music-assistant-models.overridePythonAttrs (oldAttrs: { + version = "1.1.115"; - src = fetchFromGitHub { - owner = "music-assistant"; - repo = "models"; - tag = version; - hash = "sha256-dQwFsuelp/3s2CO/5jxNrZcmWxE9xYhrpx0O37Tq/TQ="; + src = oldAttrs.src.override { + hash = "sha256-oEXL0B8JNH4PcltpES375ov7QGs+gtYKlMGr1B7BlKY="; }; - - postPatch = '' - substituteInPlace pyproject.toml \ - --replace-fail "0.0.0" "${version}" - ''; }); }; }; @@ -40,16 +32,20 @@ let pythonPath = python.pkgs.makePythonPath providerDependencies; in + +assert + (lib.elem "ariacast" providers) -> throw "music-assistant: ariacast has not been packaged, yet."; + python.pkgs.buildPythonApplication rec { pname = "music-assistant"; - version = "2.7.11"; + version = "2.8.4"; pyproject = true; src = fetchFromGitHub { owner = "music-assistant"; repo = "server"; tag = version; - hash = "sha256-HLd7PAYdBzpzdfCRPc4elPq3KfzusIXYXTV8fRmo1lU="; + hash = "sha256-/yKnUklNQMsumzj68KIfMN/h7Xsr3Brmwpicam9xuAY="; }; patches = [ @@ -86,16 +82,14 @@ python.pkgs.buildPythonApplication rec { postPatch = '' substituteInPlace pyproject.toml \ - --replace-fail "0.0.0" "${version}" - - # get-mac is a deprecated alias of getmac since 2018 - substituteInPlace pyproject.toml \ - --replace-fail "get-mac" "getmac" + --replace-fail "0.0.0" "${version}" \ + --replace-fail "==" ">=" rm -rv \ music_assistant/providers/airplay/bin/{cliap2-*,cliraop-*} \ music_assistant/providers/airplay_receiver/bin/{build_binaries.sh,shairport-sync-*} \ - music_assistant/providers/spotify/bin + music_assistant/providers/ariacast_receiver/bin/ariacast_* \ + music_assistant/providers/spotify/bin/librespot-* found_bins=$(find music_assistant/ -wholename '*/bin/*' -type f -executable -print0 | tr '\0' ' ') if [[ -n $found_bins ]]; then @@ -109,21 +103,12 @@ python.pkgs.buildPythonApplication rec { ]; pythonRelaxDeps = [ - "aiofiles" "aiohttp" "aiosqlite" - "certifi" - "colorlog" "cryptography" - "getmac" "mashumaro" - "numpy" "orjson" - "pillow" - "podcastparser" - "pycares" "xmltodict" - "zeroconf" ]; pythonRemoveDeps = [ @@ -131,44 +116,50 @@ python.pkgs.buildPythonApplication rec { "uv" ]; - dependencies = with python.pkgs; [ - # Only packages required in pyproject.toml - aiodns - aiofiles - aiohttp - aiohttp-asyncmdnsresolver - aiohttp-fast-zlib - aiortc - aiorun - aiosqlite - awesomeversion - brotli - certifi - chardet - colorlog - cryptography - getmac - gql - ifaddr - librosa - mashumaro - music-assistant-frontend - music-assistant-models - mutagen - orjson - pillow - podcastparser - propcache - python-slugify - shortuuid - unidecode - xmltodict - zeroconf + dependencies = + with python.pkgs; + [ + # Only packages required in pyproject.toml + aiodns + aiofiles + aiohttp + aiohttp-asyncmdnsresolver + aiohttp-fast-zlib + aiohttp-socks + aiortc + aiosqlite + awesomeversion + brotli + certifi + chardet + colorlog + cryptography + getmac + gql + ifaddr + librosa + mashumaro + music-assistant-frontend + music-assistant-models + mutagen + numpy + orjson + pillow + podcastparser + propcache + pyjwt + python-slugify + shortuuid + unidecode + xmltodict + zeroconf - # Used in music_assistant/controllers/webserver/helpers/auth_providers.py - # but somehow not part of pyproject.toml - hass-client - ]; + # Used in music_assistant/controllers/webserver/helpers/auth_providers.py + # but somehow not part of pyproject.toml + hass-client + ] + ++ gql.optional-dependencies.all + ++ pyjwt.optional-dependencies.crypto; optional-dependencies = with python.pkgs; { # Required subset of optional-dependencies in pyproject.toml @@ -185,19 +176,26 @@ python.pkgs.buildPythonApplication rec { pytestCheckHook ] ++ lib.concatAttrValues optional-dependencies + ++ (providerPackages.audible python.pkgs) + ++ (providerPackages.dlna python.pkgs) ++ (providerPackages.jellyfin python.pkgs) ++ (providerPackages.opensubsonic python.pkgs) + ++ (providerPackages.sendspin python.pkgs) ++ (providerPackages.tidal python.pkgs); disabledTestPaths = [ # no multicast support in build sandbox: # "OSError: [Errno 19] No such device" - "tests/providers/jellyfin/test_init.py::test_initial_sync" - "tests/core/test_server_base.py::test_start_and_stop_server" - "tests/core/test_server_base.py::test_events" + "tests/core/test_genres.py" # provider is missing dependencies - "tests/providers/nicovideo" "tests/providers/apple_music" + "tests/providers/bandcamp" + "tests/providers/kion_music" + "tests/providers/nicovideo" + "tests/providers/yandex_music" + "tests/providers/zvuk_music" + # mocking music_assistant.providers.airplay.pairing.AirPlayPairing does not work + "tests/providers/airplay/test_player.py::test_start_pairing__pin_decision" ]; pythonImportsCheck = [ "music_assistant" ]; diff --git a/pkgs/by-name/mu/music-assistant/providers.nix b/pkgs/by-name/mu/music-assistant/providers.nix index caac5bb1170b..85b96a55d5de 100644 --- a/pkgs/by-name/mu/music-assistant/providers.nix +++ b/pkgs/by-name/mu/music-assistant/providers.nix @@ -1,7 +1,7 @@ # Do not edit manually, run ./update-providers.py { - version = "2.7.11"; + version = "2.8.4"; providers = { airplay = ps: with ps; [ @@ -19,6 +19,8 @@ ps: with ps; [ gql ]; + ariacast_receiver = ps: [ + ]; audible = ps: with ps; [ audible @@ -27,6 +29,8 @@ ps: with ps; [ aioaudiobookshelf ]; + bandcamp = ps: [ + ]; # missing bandcamp-async-api bbc_sounds = ps: with ps; [ pytz @@ -41,6 +45,10 @@ ps: with ps; [ pychromecast ]; + coverartarchive = ps: [ + ]; + dashie_kiosk = ps: [ + ]; deezer = ps: with ps; [ deezer-python-async @@ -51,11 +59,16 @@ dlna = ps: with ps; [ async-upnp-client + defusedxml ]; + emby = ps: [ + ]; fanarttv = ps: [ ]; filesystem_local = ps: [ ]; + filesystem_nfs = ps: [ + ]; filesystem_smb = ps: [ ]; fully_kiosk = @@ -72,6 +85,10 @@ ]; hass_players = ps: [ ]; + heos = + ps: with ps; [ + pyheos + ]; ibroadcast = ps: [ ]; # missing ibroadcastaio internet_archive = ps: [ @@ -82,6 +99,8 @@ ps: with ps; [ aiojellyfin ]; + kion_music = ps: [ + ]; # missing yandex-music lastfm_scrobble = ps: with ps; [ pylast @@ -106,6 +125,12 @@ ps: with ps; [ py-opensonic ]; + orf_radiothek = ps: [ + ]; + pandora = ps: [ + ]; + party = ps: [ + ]; phishin = ps: [ ]; plex = @@ -146,6 +171,8 @@ snapcast websocket-client ]; + somafm = ps: [ + ]; sonos = ps: with ps; [ aiosonos @@ -163,14 +190,18 @@ ps: with ps; [ pkce ]; - spotify_connect = ps: [ - ]; + spotify_connect = + ps: with ps; [ + pkce + ]; squeezelite = ps: with ps; [ aioslimproto ]; subsonic_scrobble = ps: [ ]; + sync_group = ps: [ + ]; test = ps: [ ]; theaudiodb = ps: [ @@ -183,10 +214,16 @@ ]; universal_group = ps: [ ]; + universal_player = ps: [ + ]; vban_receiver = ps: with ps; [ aiovban ]; + yandex_music = ps: [ + ]; # missing yandex-music + yousee = ps: [ + ]; ytmusic = ps: with ps; [ bgutil-ytdlp-pot-provider @@ -194,5 +231,7 @@ yt-dlp ytmusicapi ]; # missing deno + zvuk_music = ps: [ + ]; # missing zvuk-music }; } diff --git a/pkgs/by-name/mu/music-assistant/shairport-sync.patch b/pkgs/by-name/mu/music-assistant/shairport-sync.patch index 298d06f59449..a1bbf8176b67 100644 --- a/pkgs/by-name/mu/music-assistant/shairport-sync.patch +++ b/pkgs/by-name/mu/music-assistant/shairport-sync.patch @@ -1,5 +1,5 @@ diff --git a/music_assistant/providers/airplay_receiver/helpers.py b/music_assistant/providers/airplay_receiver/helpers.py -index 6f2b35df..dd839b73 100644 +index 6f2b35df..d80dd112 100644 --- a/music_assistant/providers/airplay_receiver/helpers.py +++ b/music_assistant/providers/airplay_receiver/helpers.py @@ -22,15 +22,9 @@ async def check_shairport_sync(shairport_path: str) -> str | None: diff --git a/pkgs/by-name/mu/music-assistant/update-providers.py b/pkgs/by-name/mu/music-assistant/update-providers.py index cf581050e43c..c464fc1cd5b1 100755 --- a/pkgs/by-name/mu/music-assistant/update-providers.py +++ b/pkgs/by-name/mu/music-assistant/update-providers.py @@ -222,7 +222,7 @@ async def resolve_providers(manifests) -> Set: version = await get_package_version(attr) if version not in requirement.specifier: - errors.append(f"{requirement} not satisifed by version {version}") + errors.append(f"{requirement} not satisfied by version {version}") providers.add(provider) if errors: print("\n - ", end="") diff --git a/pkgs/development/python-modules/aioaudiobookshelf/default.nix b/pkgs/development/python-modules/aioaudiobookshelf/default.nix index d3fc84314876..ca0e964e5674 100644 --- a/pkgs/development/python-modules/aioaudiobookshelf/default.nix +++ b/pkgs/development/python-modules/aioaudiobookshelf/default.nix @@ -10,14 +10,14 @@ buildPythonPackage rec { pname = "aioaudiobookshelf"; - version = "0.1.13"; + version = "0.1.20"; pyproject = true; src = fetchFromGitHub { owner = "music-assistant"; repo = "aioaudiobookshelf"; tag = version; - hash = "sha256-63QqoINXY9gKZnyB0at+2C7c6epuda3UQ1/XwzLKnS0="; + hash = "sha256-MEkIcPtNNHvWUBLGRhJGbMnS5cMclGqINuLqvGK8Ivg="; }; build-system = [ diff --git a/pkgs/development/python-modules/aiosendspin/default.nix b/pkgs/development/python-modules/aiosendspin/default.nix index f9c5f4a92c0f..c7cf72fbf1fd 100644 --- a/pkgs/development/python-modules/aiosendspin/default.nix +++ b/pkgs/development/python-modules/aiosendspin/default.nix @@ -10,27 +10,37 @@ aiohttp, av, mashumaro, + numpy, orjson, pillow, zeroconf, + # test dependencies + pytest-aiohttp, + pytest-cov-stub, + pytest-timeout, + pytest-xdist, + pytestCheckHook, + # meta music-assistant, + + nixosTests, }: buildPythonPackage rec { pname = "aiosendspin"; - version = "2.1.0"; + version = "4.4.0"; pyproject = true; src = fetchFromGitHub { owner = "Sendspin"; repo = "aiosendspin"; tag = version; - hash = "sha256-9VhNtfXH2r/cGkscz51PIK2/66pPOGv0S0IpO0wFvO4="; + hash = "sha256-7edFCGNbECW5rrTbF7vJ4lJUc2IrQZD9VTR3IxJRP08="; }; - # https://github.com/Sendspin/aiosendspin/blob/1.2.0/pyproject.toml#L7 + # https://github.com/Sendspin/aiosendspin/blob/4.4.0/pyproject.toml#L7 postPatch = '' substituteInPlace pyproject.toml \ --replace-fail 'version = "0.0.0"' 'version = "${version}"' @@ -44,19 +54,29 @@ buildPythonPackage rec { aiohttp av mashumaro + numpy orjson pillow zeroconf ]; - doCheck = false; # no tests + nativeCheckInputs = [ + pytest-aiohttp + pytest-cov-stub + pytest-timeout + pytest-xdist + pytestCheckHook + ]; pythonImportsCheck = [ "aiosendspin" ]; - # needs manual compat testing with music-assistant (sendspin provider) - passthru.skipBulkUpdate = true; # nixpkgs-update: no auto update + passthru = { + # needs manual compat testing with music-assistant (sendspin provider) + skipBulkUpdate = true; # nixpkgs-update: no auto update + tests = nixosTests.music-assistant; + }; meta = { changelog = "https://github.com/Sendspin/aiosendspin/releases/tag/${src.tag}"; diff --git a/pkgs/development/python-modules/liblistenbrainz/default.nix b/pkgs/development/python-modules/liblistenbrainz/default.nix index 867fc84fa7d5..4a067f9a4849 100644 --- a/pkgs/development/python-modules/liblistenbrainz/default.nix +++ b/pkgs/development/python-modules/liblistenbrainz/default.nix @@ -11,14 +11,14 @@ buildPythonPackage rec { pname = "liblistenbrainz"; - version = "0.6.1"; + version = "0.7.0"; pyproject = true; src = fetchFromGitHub { owner = "metabrainz"; repo = "liblistenbrainz"; - tag = "v${version}"; - hash = "sha256-2/EUzkC+8u6SQZYstIqJnlWcz74f5UpuXh/r4ImNd0g="; + tag = version; + hash = "sha256-fZgIVGDUJ4Dh/7CIOugvpRP7FoijpsgA3bBKJMmDd7o="; }; build-system = [ diff --git a/pkgs/development/python-modules/music-assistant-models/default.nix b/pkgs/development/python-modules/music-assistant-models/default.nix index 2f9ebf8addda..74607350c725 100644 --- a/pkgs/development/python-modules/music-assistant-models/default.nix +++ b/pkgs/development/python-modules/music-assistant-models/default.nix @@ -15,10 +15,11 @@ pytest-cov-stub, # reverse dependencies + music-assistant, music-assistant-client, }: -buildPythonPackage rec { +buildPythonPackage (finalAttrs: { pname = "music-assistant-models"; # Must be compatible with music-assistant-client package # nixpkgs-update: no auto update @@ -28,13 +29,13 @@ buildPythonPackage rec { src = fetchFromGitHub { owner = "music-assistant"; repo = "models"; - tag = version; + tag = finalAttrs.version; hash = "sha256-/eNCgAB5G8g1r2fcW27lySEqg+q/1bJvwwyntigGWjo="; }; postPatch = '' substituteInPlace pyproject.toml \ - --replace-fail "0.0.0" "${version}" + --replace-fail "0.0.0" "${finalAttrs.version}" ''; build-system = [ setuptools ]; @@ -54,14 +55,14 @@ buildPythonPackage rec { ]; passthru.tests = { - inherit music-assistant-client; + inherit music-assistant music-assistant-client; }; meta = { - description = "Models used by Music Assistant (shared by client and server"; + description = "Models used by Music Assistant (shared by client and server)"; homepage = "https://github.com/music-assistant/models"; - changelog = "https://github.com/music-assistant/models/releases/tag/${src.tag}"; + changelog = "https://github.com/music-assistant/models/releases/tag/${finalAttrs.src.tag}"; license = lib.licenses.asl20; maintainers = [ ]; }; -} +}) diff --git a/pkgs/development/python-modules/py-opensonic/default.nix b/pkgs/development/python-modules/py-opensonic/default.nix index a753d84b06fa..f67b8bfc7c02 100644 --- a/pkgs/development/python-modules/py-opensonic/default.nix +++ b/pkgs/development/python-modules/py-opensonic/default.nix @@ -10,14 +10,14 @@ buildPythonPackage rec { pname = "py-opensonic"; - version = "8.1.2"; + version = "8.1.3"; pyproject = true; src = fetchFromGitHub { owner = "khers"; repo = "py-opensonic"; tag = "v${version}"; - hash = "sha256-lpPRkPLWHzsXhpZ1PVvgNWTQUuuU8N0g7ntqyOAbPlM="; + hash = "sha256-p8vcH0rL2ebFzZCouIEJ1EZCJaxpjQeOUtQug3B88T8="; }; build-system = [ setuptools ];