music-assistant: 2.3.6 -> 2.4.2 (#387392)

authored by Martin Weinelt and committed by GitHub 925ac765 274ea258

+229 -46
+5 -4
pkgs/by-name/mu/music-assistant/dont-install-deps.patch
··· 1 1 diff --git a/music_assistant/helpers/util.py b/music_assistant/helpers/util.py 2 - index b6e5f2b4..0edead16 100644 2 + index 8daf159d..af5a6f38 100644 3 3 --- a/music_assistant/helpers/util.py 4 4 +++ b/music_assistant/helpers/util.py 5 - @@ -424,29 +424,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider 5 + @@ -429,30 +429,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider 6 6 def _get_provider_module(domain: str) -> ProviderModuleType: 7 7 return importlib.import_module(f".{domain}", "music_assistant.providers") 8 8 ··· 29 29 - # try loading the provider again to be safe 30 30 - # this will fail if something else is wrong (as it should) 31 31 - return await asyncio.to_thread(_get_provider_module, domain) 32 - + raise RuntimeError(f"Missing dependencies for provider {domain}") 33 - 32 + - 33 + + raise RuntimeError(f"Missing dependencies for provider {domain}.") 34 34 35 35 def create_tempfile(): 36 + """Return a (named) temporary file."""
+19 -19
pkgs/by-name/mu/music-assistant/ffmpeg.patch
··· 1 1 diff --git a/music_assistant/helpers/audio.py b/music_assistant/helpers/audio.py 2 - index dad3c5db..d1398d66 100644 2 + index 482ab8e8..a02fc435 100644 3 3 --- a/music_assistant/helpers/audio.py 4 4 +++ b/music_assistant/helpers/audio.py 5 - @@ -74,7 +74,7 @@ async def crossfade_pcm_parts( 5 + @@ -80,7 +80,7 @@ async def crossfade_pcm_parts( 6 6 await outfile.write(fade_out_part) 7 7 args = [ 8 8 # generic args ··· 11 11 "-hide_banner", 12 12 "-loglevel", 13 13 "quiet", 14 - @@ -135,7 +135,7 @@ async def strip_silence( 14 + @@ -141,7 +141,7 @@ async def strip_silence( 15 15 reverse: bool = False, 16 16 ) -> bytes: 17 17 """Strip silence from begin or end of pcm audio using ffmpeg.""" ··· 20 20 args += [ 21 21 "-acodec", 22 22 pcm_format.content_type.name.lower(), 23 - @@ -734,7 +734,7 @@ async def get_file_stream( 24 - async def check_audio_support() -> tuple[bool, bool, str]: 25 - """Check if ffmpeg is present (with/without libsoxr support).""" 26 - # check for FFmpeg presence 27 - - returncode, output = await check_output("ffmpeg", "-version") 28 - + returncode, output = await check_output("@ffmpeg@", "-version") 29 - ffmpeg_present = returncode == 0 and "FFmpeg" in output.decode() 30 - 31 - # use globals as in-memory cache 32 - @@ -789,7 +789,7 @@ async def get_silence( 23 + @@ -912,7 +912,7 @@ async def get_silence( 33 24 return 34 25 # use ffmpeg for all other encodings 35 26 args = [ ··· 39 30 "-loglevel", 40 31 "quiet", 41 32 diff --git a/music_assistant/helpers/ffmpeg.py b/music_assistant/helpers/ffmpeg.py 42 - index 0405fc27..570f9157 100644 33 + index 7c1c8d83..501a7370 100644 43 34 --- a/music_assistant/helpers/ffmpeg.py 44 35 +++ b/music_assistant/helpers/ffmpeg.py 45 - @@ -213,7 +213,7 @@ def get_ffmpeg_args( # noqa: PLR0915 46 - 36 + @@ -218,7 +218,7 @@ def get_ffmpeg_args( 37 + extra_args = [] 47 38 # generic args 48 39 generic_args = [ 49 40 - "ffmpeg", ··· 51 42 "-hide_banner", 52 43 "-loglevel", 53 44 loglevel, 45 + @@ -370,7 +370,7 @@ async def check_ffmpeg_version() -> None: 46 + """Check if ffmpeg is present (with libsoxr support).""" 47 + # check for FFmpeg presence 48 + try: 49 + - returncode, output = await check_output("ffmpeg", "-version") 50 + + returncode, output = await check_output("@ffmpeg@", "-version") 51 + except FileNotFoundError: 52 + raise AudioError( 53 + "FFmpeg binary is missing from system. " 54 54 diff --git a/music_assistant/helpers/tags.py b/music_assistant/helpers/tags.py 55 - index 55def74b..7c26e13d 100644 55 + index 06c8bcb5..a703aacd 100644 56 56 --- a/music_assistant/helpers/tags.py 57 57 +++ b/music_assistant/helpers/tags.py 58 - @@ -387,7 +387,7 @@ async def parse_tags(input_file: str, file_size: int | None = None) -> AudioTags 58 + @@ -438,7 +438,7 @@ def parse_tags(input_file: str, file_size: int | None = None) -> AudioTags: 59 59 Input_file may be a (local) filename or URL accessible by ffmpeg. 60 60 """ 61 61 args = ( ··· 64 64 "-hide_banner", 65 65 "-loglevel", 66 66 "fatal", 67 - @@ -448,7 +448,7 @@ async def get_embedded_image(input_file: str) -> bytes | None: 67 + @@ -553,7 +553,7 @@ async def get_embedded_image(input_file: str) -> bytes | None: 68 68 Input_file may be a (local) filename or URL accessible by ffmpeg. 69 69 """ 70 70 args = (
+2 -2
pkgs/by-name/mu/music-assistant/frontend.nix
··· 7 7 8 8 buildPythonPackage rec { 9 9 pname = "music-assistant-frontend"; 10 - version = "2.9.16"; 10 + version = "2.11.11"; 11 11 pyproject = true; 12 12 13 13 src = fetchPypi { 14 14 inherit pname version; 15 - hash = "sha256-bUtclj8GMq1JdC4tYNETl+l+TNF91y4yTANSpuOOm70="; 15 + hash = "sha256-fPFszZfJjdc2KTQipeb2KVbIwWwL56bqFGba1LSJXuQ="; 16 16 }; 17 17 18 18 postPatch = ''
+29
pkgs/by-name/mu/music-assistant/librespot.patch
··· 1 + diff --git a/music_assistant/providers/spotify/helpers.py b/music_assistant/providers/spotify/helpers.py 2 + index 8b6c4e78..20c2a269 100644 3 + --- a/music_assistant/providers/spotify/helpers.py 4 + +++ b/music_assistant/providers/spotify/helpers.py 5 + @@ -11,23 +11,4 @@ from music_assistant.helpers.process import check_output 6 + async def get_librespot_binary() -> str: 7 + """Find the correct librespot binary belonging to the platform.""" 8 + 9 + - # ruff: noqa: SIM102 10 + - async def check_librespot(librespot_path: str) -> str | None: 11 + - try: 12 + - returncode, output = await check_output(librespot_path, "--version") 13 + - if returncode == 0 and b"librespot" in output: 14 + - return librespot_path 15 + - except OSError: 16 + - return None 17 + - 18 + - base_path = os.path.join(os.path.dirname(__file__), "bin") 19 + - system = platform.system().lower().replace("darwin", "macos") 20 + - architecture = platform.machine().lower() 21 + - 22 + - if bridge_binary := await check_librespot( 23 + - os.path.join(base_path, f"librespot-{system}-{architecture}") 24 + - ): 25 + - return bridge_binary 26 + - 27 + - msg = f"Unable to locate Librespot for {system}/{architecture}" 28 + - raise RuntimeError(msg) 29 + + return "@librespot@"
+16 -17
pkgs/by-name/mu/music-assistant/package.nix
··· 3 3 python3, 4 4 fetchFromGitHub, 5 5 ffmpeg-headless, 6 + librespot, 6 7 nixosTests, 7 8 replaceVars, 8 9 providers ? [ ], ··· 12 13 python = python3.override { 13 14 self = python; 14 15 packageOverrides = self: super: { 15 - aiojellyfin = super.aiojellyfin.overridePythonAttrs (oldAttrs: rec { 16 - version = "0.10.1"; 17 - 18 - src = fetchFromGitHub { 19 - owner = "Jc2k"; 20 - repo = "aiojellyfin"; 21 - tag = "v${version}"; 22 - hash = "sha256-A+uvM1/7HntRMIdknfHr0TMGIjHk7BCwsZopXdVoEO8="; 23 - }; 24 - }); 25 - 26 16 music-assistant-frontend = self.callPackage ./frontend.nix { }; 27 17 28 18 music-assistant-models = super.music-assistant-models.overridePythonAttrs (oldAttrs: rec { 29 - version = "1.1.4"; 19 + version = "1.1.30"; 30 20 31 21 src = fetchFromGitHub { 32 22 owner = "music-assistant"; 33 23 repo = "models"; 34 24 tag = version; 35 - hash = "sha256-keig18o32X53q/QcoaPO0o9AT4XTEZ+dQ3L6u6BVkLU="; 25 + hash = "sha256-ZLTRHarjVFAk+tYPkgLm192rE+C82vNzqs8PmJhGSeg="; 36 26 }; 37 27 38 28 postPatch = '' ··· 54 44 55 45 python.pkgs.buildPythonApplication rec { 56 46 pname = "music-assistant"; 57 - version = "2.3.6"; 47 + version = "2.4.2"; 58 48 pyproject = true; 59 49 60 50 src = fetchFromGitHub { 61 51 owner = "music-assistant"; 62 52 repo = "server"; 63 53 tag = version; 64 - hash = "sha256-CSGpG1E4ou1TGz/S1mXFHyk49p7dStEwxUTB+xxfNEc="; 54 + hash = "sha256-5FIIXIn4tEz6w/uAh6PGkU4tU+mz7Jpb3+bq1mRNr2Y="; 65 55 }; 66 56 67 57 patches = [ ··· 69 59 ffmpeg = "${lib.getBin ffmpeg-headless}/bin/ffmpeg"; 70 60 ffprobe = "${lib.getBin ffmpeg-headless}/bin/ffprobe"; 71 61 }) 62 + (replaceVars ./librespot.patch { 63 + librespot = lib.getExe librespot; 64 + }) 72 65 73 66 # Disable interactive dependency resolution, which clashes with the immutable Python environment 74 67 ./dont-install-deps.patch ··· 77 70 postPatch = '' 78 71 substituteInPlace pyproject.toml \ 79 72 --replace-fail "0.0.0" "${version}" 73 + 74 + rm -rv music_assistant/providers/spotify/bin 80 75 ''; 81 76 82 77 build-system = with python.pkgs; [ ··· 85 80 86 81 pythonRelaxDeps = [ 87 82 "aiohttp" 83 + "aiosqlite" 88 84 "certifi" 89 85 "colorlog" 90 86 "cryptography" ··· 123 119 memory-tempfile 124 120 music-assistant-frontend 125 121 music-assistant-models 122 + mutagen 126 123 orjson 127 124 pillow 125 + podcastparser 128 126 python-slugify 129 127 shortuuid 130 128 unidecode ··· 136 134 nativeCheckInputs = 137 135 with python.pkgs; 138 136 [ 139 - aiojellyfin 140 137 pytest-aiohttp 141 138 pytest-cov-stub 142 139 pytest-timeout ··· 144 141 syrupy 145 142 pytest-timeout 146 143 ] 147 - ++ lib.flatten (lib.attrValues optional-dependencies); 144 + ++ lib.flatten (lib.attrValues optional-dependencies) 145 + ++ (providerPackages.jellyfin python.pkgs) 146 + ++ (providerPackages.opensubsonic python.pkgs); 148 147 149 148 pytestFlagsArray = [ 150 149 # blocks in poll()
+20 -2
pkgs/by-name/mu/music-assistant/providers.nix
··· 1 1 # Do not edit manually, run ./update-providers.py 2 2 3 3 { 4 - version = "2.3.6"; 4 + version = "2.4.2"; 5 5 providers = { 6 6 airplay = ps: [ 7 7 ]; 8 8 apple_music = ps: [ 9 9 ]; # missing pywidevine 10 + audible = 11 + ps: with ps; [ 12 + audible 13 + ]; 14 + audiobookshelf = 15 + ps: with ps; [ 16 + aioaudiobookshelf 17 + ]; 10 18 bluesound = 11 19 ps: with ps; [ 12 20 pyblu ··· 19 27 ]; 20 28 deezer = 21 29 ps: with ps; [ 30 + deezer-python-async 22 31 pycryptodome 23 - ]; # missing deezer-python-async 32 + ]; 24 33 dlna = 25 34 ps: with ps; [ 26 35 async-upnp-client ··· 41 50 ]; 42 51 hass_players = ps: [ 43 52 ]; 53 + ibroadcast = ps: [ 54 + ]; # missing ibroadcastaio 44 55 jellyfin = 45 56 ps: with ps; [ 46 57 aiojellyfin ··· 57 68 ps: with ps; [ 58 69 plexapi 59 70 ]; 71 + podcastfeed = 72 + ps: with ps; [ 73 + podcastparser 74 + ]; 60 75 qobuz = ps: [ 61 76 ]; 62 77 radiobrowser = ··· 87 102 ps: with ps; [ 88 103 pkce 89 104 ]; 105 + spotify_connect = ps: [ 106 + ]; 90 107 template_player_provider = ps: [ 91 108 ]; 92 109 test = ps: [ ··· 101 118 ]; 102 119 ytmusic = 103 120 ps: with ps; [ 121 + duration-parser 104 122 yt-dlp 105 123 ytmusicapi 106 124 ];
+43
pkgs/development/python-modules/aioaudiobookshelf/default.nix
··· 1 + { 2 + lib, 3 + buildPythonPackage, 4 + fetchFromGitHub, 5 + setuptools, 6 + aiohttp, 7 + mashumaro, 8 + python-socketio, 9 + }: 10 + 11 + buildPythonPackage rec { 12 + pname = "aioaudiobookshelf"; 13 + version = "0.1.4"; 14 + pyproject = true; 15 + 16 + src = fetchFromGitHub { 17 + owner = "music-assistant"; 18 + repo = "aioaudiobookshelf"; 19 + tag = version; 20 + hash = "sha256-rUd8TwmQDeMxXu7/UBnN426N+BMas2u6RNpTBXa3/5g="; 21 + }; 22 + 23 + build-system = [ 24 + setuptools 25 + ]; 26 + 27 + dependencies = [ 28 + aiohttp 29 + mashumaro 30 + python-socketio 31 + ]; 32 + 33 + pythonImportsCheck = [ 34 + "aioaudiobookshelf" 35 + ]; 36 + 37 + meta = { 38 + description = "Async python library to interact with Audiobookshelf"; 39 + homepage = "https://github.com/music-assistant/aioaudiobookshelf"; 40 + license = lib.licenses.asl20; 41 + maintainers = with lib.maintainers; [ hexa ]; 42 + }; 43 + }
+2 -2
pkgs/development/python-modules/aiorun/default.nix
··· 11 11 12 12 buildPythonPackage rec { 13 13 pname = "aiorun"; 14 - version = "2024.8.1"; 14 + version = "2025.1.1"; 15 15 pyproject = true; 16 16 17 17 disabled = pythonOlder "3.7"; ··· 20 20 owner = "cjrh"; 21 21 repo = "aiorun"; 22 22 tag = "v${version}"; 23 - hash = "sha256-D+4IceCdPg1Akq1YgPuSGF7yAOhDe8PmioNBE5X7yuQ="; 23 + hash = "sha256-YqUlWf79EbC47BETBDjo8hzg5jhL4LiWLKGr1Qy4AbM="; 24 24 }; 25 25 26 26 build-system = [ flit-core ];
+48
pkgs/development/python-modules/deezer-python-async/default.nix
··· 1 + { 2 + lib, 3 + buildPythonPackage, 4 + fetchFromGitHub, 5 + 6 + # build-system 7 + poetry-core, 8 + 9 + # dependencies 10 + aiohttp, 11 + asyncio-throttle, 12 + }: 13 + 14 + buildPythonPackage rec { 15 + pname = "deezer-python-async"; 16 + version = "0.3.0"; 17 + pyproject = true; 18 + 19 + src = fetchFromGitHub { 20 + owner = "music-assistant"; 21 + repo = "deezer-python-async"; 22 + tag = "v${version}"; 23 + hash = "sha256-uuAB+SC/ECG50ox/6Bi+94bAt+YZokeQChpDQUAK+zc="; 24 + }; 25 + 26 + build-system = [ 27 + poetry-core 28 + ]; 29 + 30 + dependencies = [ 31 + aiohttp 32 + asyncio-throttle 33 + ]; 34 + 35 + doCheck = false; # requires access to the deezer api 36 + 37 + pythonImportsCheck = [ 38 + "deezer" 39 + ]; 40 + 41 + meta = { 42 + description = "Deezer client for python *but async"; 43 + homepage = "https://github.com/music-assistant/deezer-python-async"; 44 + changelog = "https://github.com/music-assistant/deezer-python-async/blob/${src.tag}/CHANGELOG.md"; 45 + license = lib.licenses.mit; 46 + maintainers = with lib.maintainers; [ hexa ]; 47 + }; 48 + }
+39
pkgs/development/python-modules/duration-parser/default.nix
··· 1 + { 2 + lib, 3 + buildPythonPackage, 4 + fetchFromGitHub, 5 + setuptools, 6 + pytestCheckHook, 7 + }: 8 + 9 + buildPythonPackage rec { 10 + pname = "duration-parser"; 11 + version = "1.0.1"; 12 + pyproject = true; 13 + 14 + src = fetchFromGitHub { 15 + owner = "adriansahlman"; 16 + repo = "duration-parser"; 17 + tag = "v${version}"; 18 + hash = "sha256-Vn3H2JEMrJ6b/7eNG+h9tG5QzslGvaV3sunM7UO9Bok="; 19 + }; 20 + 21 + build-system = [ 22 + setuptools 23 + ]; 24 + 25 + nativeCheckInputs = [ 26 + pytestCheckHook 27 + ]; 28 + 29 + pythonImportsCheck = [ 30 + "duration_parser" 31 + ]; 32 + 33 + meta = { 34 + description = "A minimal duration parser written in python"; 35 + homepage = "https://github.com/adriansahlman/duration-parser"; 36 + license = lib.licenses.mit; 37 + maintainers = with lib.maintainers; [ hexa ]; 38 + }; 39 + }
+6
pkgs/top-level/python-packages.nix
··· 185 185 186 186 aioasuswrt = callPackage ../development/python-modules/aioasuswrt { }; 187 187 188 + aioaudiobookshelf = callPackage ../development/python-modules/aioaudiobookshelf { }; 189 + 188 190 aioautomower = callPackage ../development/python-modules/aioautomower { }; 189 191 190 192 aioazuredevops = callPackage ../development/python-modules/aioazuredevops { }; ··· 3194 3196 3195 3197 deezer-python = callPackage ../development/python-modules/deezer-python { }; 3196 3198 3199 + deezer-python-async = callPackage ../development/python-modules/deezer-python-async { }; 3200 + 3197 3201 defang = callPackage ../development/python-modules/defang { }; 3198 3202 3199 3203 defcon = callPackage ../development/python-modules/defcon { }; ··· 4035 4039 dungeon-eos = callPackage ../development/python-modules/dungeon-eos { }; 4036 4040 4037 4041 duo-client = callPackage ../development/python-modules/duo-client { }; 4042 + 4043 + duration-parser = callPackage ../development/python-modules/duration-parser { }; 4038 4044 4039 4045 durationpy = callPackage ../development/python-modules/durationpy { }; 4040 4046