From 73752560ac001055800d4aad38142ef856c201f2 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Mon, 11 Aug 2025 01:40:44 +0200 Subject: [PATCH] Fix issues with dynamically installing packages into the running server (#2318) * Always ensure uv is present for installing packages dynamically * Add extra check for YTM to see if yt_dlp is useable --- .github/workflows/release.yml | 4 ++-- Dockerfile | 2 -- Dockerfile.base | 3 +++ music_assistant/helpers/util.py | 24 ++----------------- music_assistant/providers/ytmusic/__init__.py | 6 +++++ pyproject.toml | 1 + requirements_all.txt | 1 + 7 files changed, 15 insertions(+), 26 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index abdad286..a8c9ca1a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,8 +6,8 @@ on: env: PYTHON_VERSION: "3.12" - BASE_IMAGE_VERSION_STABLE: "1.2.3" - BASE_IMAGE_VERSION_BETA: "1.3.0" + BASE_IMAGE_VERSION_STABLE: "1.3.1" + BASE_IMAGE_VERSION_BETA: "1.3.1" jobs: build-artifact: diff --git a/Dockerfile b/Dockerfile index e3e3c91d..de069a04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,8 +8,6 @@ FROM ghcr.io/music-assistant/base:$BASE_IMAGE_VERSION AS builder ADD dist dist COPY requirements_all.txt . -# ensure UV is installed -COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ # create venv which will be copied to the final image ENV VIRTUAL_ENV=/app/venv RUN uv venv $VIRTUAL_ENV diff --git a/Dockerfile.base b/Dockerfile.base index 0a64ba9c..d3ab4d4e 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -24,6 +24,9 @@ RUN set -x \ COPY --from=mwader/static-ffmpeg:7.1.1 /ffmpeg /usr/local/bin/ COPY --from=mwader/static-ffmpeg:7.1.1 /ffprobe /usr/local/bin/ +# ensure UV is installed into the base image +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + # Copy widevine client files to container RUN mkdir -p /usr/local/bin/widevine_cdm COPY widevine_cdm/* /usr/local/bin/widevine_cdm/ diff --git a/music_assistant/helpers/util.py b/music_assistant/helpers/util.py index f24d6051..a244e958 100644 --- a/music_assistant/helpers/util.py +++ b/music_assistant/helpers/util.py @@ -424,32 +424,12 @@ def empty_queue[T](q: asyncio.Queue[T]) -> None: pass -async def install_package(package: str, prefer_uv: bool = True) -> None: +async def install_package(package: str) -> None: """Install package with pip, raise when install failed.""" LOGGER.debug("Installing python package %s", package) - if await get_package_version("uv") is None: - # uv is not present on this system - prefer_uv = False - # determine args (either uv pip or regular pip) - if prefer_uv: - args = ["uv", "pip", "install", "--no-cache", "--find-links", HA_WHEELS, package] - else: - args = [ - "pip", - "install", - "--no-cache-dir", - "--no-input", - "--find-links", - HA_WHEELS, - package, - ] + args = ["uv", "pip", "install", "--no-cache", "--find-links", HA_WHEELS, package] return_code, output = await check_output(*args) if return_code != 0: - if "Permission denied" in output.decode() and prefer_uv: - # try again with regular pip - # uv pip seems to have issues with permissions on docker installs - await install_package(package, prefer_uv=False) - return msg = f"Failed to install package {package}\n{output.decode()}" raise RuntimeError(msg) diff --git a/music_assistant/providers/ytmusic/__init__.py b/music_assistant/providers/ytmusic/__init__.py index 0b021633..52a7544a 100644 --- a/music_assistant/providers/ytmusic/__init__.py +++ b/music_assistant/providers/ytmusic/__init__.py @@ -27,6 +27,7 @@ from music_assistant_models.errors import ( InvalidDataError, LoginFailed, MediaNotFoundError, + SetupFailedError, UnplayableMediaError, ) from music_assistant_models.media_items import ( @@ -1025,3 +1026,8 @@ class YoutubeMusicProvider(MusicProvider): # us from having to update MA to ensure this provider works. for package_name in PACKAGES_TO_INSTALL: await install_package(package_name) + # verify if the yt_dlp package is usable + try: + await asyncio.to_thread(importlib.import_module, "yt_dlp") + except ImportError: + raise SetupFailedError("Package yt_dlp failed to install") diff --git a/pyproject.toml b/pyproject.toml index e22e2a65..cd5237bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,7 @@ dependencies = [ "xmltodict==0.14.2", "shortuuid==1.0.13", "zeroconf==0.147.0", + "uv>=0.8.0", ] description = "Music Assistant" license = {text = "Apache-2.0"} diff --git a/requirements_all.txt b/requirements_all.txt index cfb2c3ca..940c612f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -54,6 +54,7 @@ soco==0.30.10 soundcloudpy==0.1.4 sxm==0.2.8 unidecode==1.4.0 +uv>=0.8.0 websocket-client==1.8.0 xmltodict==0.14.2 ytmusicapi==1.10.3 -- 2.34.1