Martin Weinelt 2025-03-05 20:48:09 +01:00
parent fed188c351
commit 2127c8d779
No known key found for this signature in database
GPG Key ID: 87C1E9888F856759
6 changed files with 91 additions and 44 deletions

View File

@ -1,8 +1,8 @@
diff --git a/music_assistant/helpers/util.py b/music_assistant/helpers/util.py
index b6e5f2b4..0edead16 100644
index 8daf159d..af5a6f38 100644
--- a/music_assistant/helpers/util.py
+++ b/music_assistant/helpers/util.py
@@ -424,29 +424,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider
@@ -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")
@ -29,7 +29,8 @@ index b6e5f2b4..0edead16 100644
- # try loading the provider again to be safe
- # 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"Missing dependencies for provider {domain}.")
def create_tempfile():
"""Return a (named) temporary file."""

View File

@ -1,8 +1,8 @@
diff --git a/music_assistant/helpers/audio.py b/music_assistant/helpers/audio.py
index dad3c5db..d1398d66 100644
index 482ab8e8..a02fc435 100644
--- a/music_assistant/helpers/audio.py
+++ b/music_assistant/helpers/audio.py
@@ -74,7 +74,7 @@ async def crossfade_pcm_parts(
@@ -80,7 +80,7 @@ async def crossfade_pcm_parts(
await outfile.write(fade_out_part)
args = [
# generic args
@ -11,7 +11,7 @@ index dad3c5db..d1398d66 100644
"-hide_banner",
"-loglevel",
"quiet",
@@ -135,7 +135,7 @@ async def strip_silence(
@@ -141,7 +141,7 @@ async def strip_silence(
reverse: bool = False,
) -> bytes:
"""Strip silence from begin or end of pcm audio using ffmpeg."""
@ -20,16 +20,7 @@ index dad3c5db..d1398d66 100644
args += [
"-acodec",
pcm_format.content_type.name.lower(),
@@ -734,7 +734,7 @@ async def get_file_stream(
async def check_audio_support() -> tuple[bool, bool, str]:
"""Check if ffmpeg is present (with/without libsoxr support)."""
# check for FFmpeg presence
- returncode, output = await check_output("ffmpeg", "-version")
+ returncode, output = await check_output("@ffmpeg@", "-version")
ffmpeg_present = returncode == 0 and "FFmpeg" in output.decode()
# use globals as in-memory cache
@@ -789,7 +789,7 @@ async def get_silence(
@@ -912,7 +912,7 @@ async def get_silence(
return
# use ffmpeg for all other encodings
args = [
@ -39,11 +30,11 @@ index dad3c5db..d1398d66 100644
"-loglevel",
"quiet",
diff --git a/music_assistant/helpers/ffmpeg.py b/music_assistant/helpers/ffmpeg.py
index 0405fc27..570f9157 100644
index 7c1c8d83..501a7370 100644
--- a/music_assistant/helpers/ffmpeg.py
+++ b/music_assistant/helpers/ffmpeg.py
@@ -213,7 +213,7 @@ def get_ffmpeg_args( # noqa: PLR0915
@@ -218,7 +218,7 @@ def get_ffmpeg_args(
extra_args = []
# generic args
generic_args = [
- "ffmpeg",
@ -51,11 +42,20 @@ index 0405fc27..570f9157 100644
"-hide_banner",
"-loglevel",
loglevel,
@@ -370,7 +370,7 @@ async def check_ffmpeg_version() -> None:
"""Check if ffmpeg is present (with libsoxr support)."""
# check for FFmpeg presence
try:
- returncode, output = await check_output("ffmpeg", "-version")
+ returncode, output = await check_output("@ffmpeg@", "-version")
except FileNotFoundError:
raise AudioError(
"FFmpeg binary is missing from system. "
diff --git a/music_assistant/helpers/tags.py b/music_assistant/helpers/tags.py
index 55def74b..7c26e13d 100644
index 06c8bcb5..a703aacd 100644
--- a/music_assistant/helpers/tags.py
+++ b/music_assistant/helpers/tags.py
@@ -387,7 +387,7 @@ async def parse_tags(input_file: str, file_size: int | None = None) -> AudioTags
@@ -438,7 +438,7 @@ def parse_tags(input_file: str, file_size: int | None = None) -> AudioTags:
Input_file may be a (local) filename or URL accessible by ffmpeg.
"""
args = (
@ -64,7 +64,7 @@ index 55def74b..7c26e13d 100644
"-hide_banner",
"-loglevel",
"fatal",
@@ -448,7 +448,7 @@ async def get_embedded_image(input_file: str) -> bytes | None:
@@ -553,7 +553,7 @@ async def get_embedded_image(input_file: str) -> bytes | None:
Input_file may be a (local) filename or URL accessible by ffmpeg.
"""
args = (

View File

@ -7,12 +7,12 @@
buildPythonPackage rec {
pname = "music-assistant-frontend";
version = "2.9.16";
version = "2.11.11";
pyproject = true;
src = fetchPypi {
inherit pname version;
hash = "sha256-bUtclj8GMq1JdC4tYNETl+l+TNF91y4yTANSpuOOm70=";
hash = "sha256-fPFszZfJjdc2KTQipeb2KVbIwWwL56bqFGba1LSJXuQ=";
};
postPatch = ''

View File

@ -0,0 +1,29 @@
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@"

View File

@ -3,6 +3,7 @@
python3,
fetchFromGitHub,
ffmpeg-headless,
librespot,
nixosTests,
replaceVars,
providers ? [ ],
@ -12,27 +13,16 @@ let
python = python3.override {
self = python;
packageOverrides = self: super: {
aiojellyfin = super.aiojellyfin.overridePythonAttrs (oldAttrs: rec {
version = "0.10.1";
src = fetchFromGitHub {
owner = "Jc2k";
repo = "aiojellyfin";
tag = "v${version}";
hash = "sha256-A+uvM1/7HntRMIdknfHr0TMGIjHk7BCwsZopXdVoEO8=";
};
});
music-assistant-frontend = self.callPackage ./frontend.nix { };
music-assistant-models = super.music-assistant-models.overridePythonAttrs (oldAttrs: rec {
version = "1.1.4";
version = "1.1.30";
src = fetchFromGitHub {
owner = "music-assistant";
repo = "models";
tag = version;
hash = "sha256-keig18o32X53q/QcoaPO0o9AT4XTEZ+dQ3L6u6BVkLU=";
hash = "sha256-ZLTRHarjVFAk+tYPkgLm192rE+C82vNzqs8PmJhGSeg=";
};
postPatch = ''
@ -54,14 +44,14 @@ in
python.pkgs.buildPythonApplication rec {
pname = "music-assistant";
version = "2.3.6";
version = "2.4.2";
pyproject = true;
src = fetchFromGitHub {
owner = "music-assistant";
repo = "server";
tag = version;
hash = "sha256-CSGpG1E4ou1TGz/S1mXFHyk49p7dStEwxUTB+xxfNEc=";
hash = "sha256-5FIIXIn4tEz6w/uAh6PGkU4tU+mz7Jpb3+bq1mRNr2Y=";
};
patches = [
@ -69,6 +59,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;
})
# Disable interactive dependency resolution, which clashes with the immutable Python environment
./dont-install-deps.patch
@ -77,6 +70,8 @@ python.pkgs.buildPythonApplication rec {
postPatch = ''
substituteInPlace pyproject.toml \
--replace-fail "0.0.0" "${version}"
rm -rv music_assistant/providers/spotify/bin
'';
build-system = with python.pkgs; [
@ -85,6 +80,7 @@ python.pkgs.buildPythonApplication rec {
pythonRelaxDeps = [
"aiohttp"
"aiosqlite"
"certifi"
"colorlog"
"cryptography"
@ -123,8 +119,10 @@ python.pkgs.buildPythonApplication rec {
memory-tempfile
music-assistant-frontend
music-assistant-models
mutagen
orjson
pillow
podcastparser
python-slugify
shortuuid
unidecode
@ -136,7 +134,6 @@ python.pkgs.buildPythonApplication rec {
nativeCheckInputs =
with python.pkgs;
[
aiojellyfin
pytest-aiohttp
pytest-cov-stub
pytest-timeout
@ -144,7 +141,9 @@ python.pkgs.buildPythonApplication rec {
syrupy
pytest-timeout
]
++ lib.flatten (lib.attrValues optional-dependencies);
++ lib.flatten (lib.attrValues optional-dependencies)
++ (providerPackages.jellyfin python.pkgs)
++ (providerPackages.opensubsonic python.pkgs);
pytestFlagsArray = [
# blocks in poll()

View File

@ -1,12 +1,20 @@
# Do not edit manually, run ./update-providers.py
{
version = "2.3.6";
version = "2.4.2";
providers = {
airplay = ps: [
];
apple_music = ps: [
]; # missing pywidevine
audible =
ps: with ps; [
audible
];
audiobookshelf =
ps: with ps; [
aioaudiobookshelf
];
bluesound =
ps: with ps; [
pyblu
@ -19,8 +27,9 @@
];
deezer =
ps: with ps; [
deezer-python-async
pycryptodome
]; # missing deezer-python-async
];
dlna =
ps: with ps; [
async-upnp-client
@ -41,6 +50,8 @@
];
hass_players = ps: [
];
ibroadcast = ps: [
]; # missing ibroadcastaio
jellyfin =
ps: with ps; [
aiojellyfin
@ -57,6 +68,10 @@
ps: with ps; [
plexapi
];
podcastfeed =
ps: with ps; [
podcastparser
];
qobuz = ps: [
];
radiobrowser =
@ -87,6 +102,8 @@
ps: with ps; [
pkce
];
spotify_connect = ps: [
];
template_player_provider = ps: [
];
test = ps: [
@ -101,6 +118,7 @@
];
ytmusic =
ps: with ps; [
duration-parser
yt-dlp
ytmusicapi
];