From cfd22d685159430e70c83a699842732848a1fe76 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 8 Jul 2023 14:44:03 +0200 Subject: [PATCH] A few small bugfixes (#753) * Fix typo in ProviderMappings resulting in wrong contenttype * move preview stream into webserver * Fix detection check of homeassistant addon --- .../server/controllers/media/base.py | 2 +- music_assistant/server/controllers/streams.py | 13 ----------- .../server/controllers/webserver.py | 23 +++++++++++++++---- music_assistant/server/helpers/util.py | 17 +++++++++----- music_assistant/server/server.py | 4 ++-- 5 files changed, 33 insertions(+), 26 deletions(-) diff --git a/music_assistant/server/controllers/media/base.py b/music_assistant/server/controllers/media/base.py index ad0cbcc8e..e29bb3d0e 100644 --- a/music_assistant/server/controllers/media/base.py +++ b/music_assistant/server/controllers/media/base.py @@ -573,7 +573,7 @@ def _get_provider_mappings( return org_item.provider_mappings if overwrite and update_item.provider_mappings: return update_item.provider_mappings - return {*org_item.provider_mappings, *update_item.provider_mappings} + return {*update_item.provider_mappings, *org_item.provider_mappings} async def _get_artist_mappings( self, diff --git a/music_assistant/server/controllers/streams.py b/music_assistant/server/controllers/streams.py index 91442b217..ce301b0d7 100644 --- a/music_assistant/server/controllers/streams.py +++ b/music_assistant/server/controllers/streams.py @@ -38,7 +38,6 @@ check_audio_support, crossfade_pcm_parts, get_media_stream, - get_preview_stream, get_stream_details, ) from music_assistant.server.helpers.process import AsyncProcess @@ -330,7 +329,6 @@ async def setup(self, config: CoreConfig) -> None: bind_port=self.publish_port, base_url=f"http://{self.publish_ip}:{self.publish_port}", static_routes=[ - ("GET", "/preview", self.serve_preview_stream), ( "GET", "/{queue_id}/multi/{job_id}/{player_id}/{queue_item_id}.{fmt}", @@ -729,17 +727,6 @@ async def read_audio(): return resp - async def serve_preview_stream(self, request: web.Request): - """Serve short preview sample.""" - self._log_request(request) - provider_instance_id_or_domain = request.query["provider"] - item_id = urllib.parse.unquote(request.query["item_id"]) - resp = web.StreamResponse(status=200, reason="OK", headers={"Content-Type": "audio/mp3"}) - await resp.prepare(request) - async for chunk in get_preview_stream(self.mass, provider_instance_id_or_domain, item_id): - await resp.write(chunk) - return resp - async def get_flow_stream( self, queue: PlayerQueue, diff --git a/music_assistant/server/controllers/webserver.py b/music_assistant/server/controllers/webserver.py index b9d08dc66..a7c2a1e33 100644 --- a/music_assistant/server/controllers/webserver.py +++ b/music_assistant/server/controllers/webserver.py @@ -10,6 +10,7 @@ import inspect import logging import os +import urllib.parse from collections.abc import Awaitable from concurrent import futures from contextlib import suppress @@ -33,6 +34,7 @@ from music_assistant.common.models.event import MassEvent from music_assistant.constants import CONF_BIND_IP, CONF_BIND_PORT from music_assistant.server.helpers.api import APICommandHandler, parse_arguments +from music_assistant.server.helpers.audio import get_preview_stream from music_assistant.server.helpers.util import get_ips from music_assistant.server.helpers.webserver import Webserver from music_assistant.server.models.core_controller import CoreController @@ -81,7 +83,7 @@ async def get_config_entries( # if a user also wants to expose a the webserver non securely on his internal # network he/she should open the port in the add-on config. internal_ip = next((x for x in await get_ips() if x.startswith("172")), await get_ip()) - base_url = f"http://{internal_ip:8095}" + base_url = f"http://{internal_ip}:8095" return ( ConfigEntry( key=CONF_BIND_PORT, @@ -174,11 +176,13 @@ async def setup(self, config: CoreConfig) -> None: # also host the image proxy on the webserver routes.append(("GET", "/imageproxy", self.mass.metadata.handle_imageproxy)) # also host the audio preview service - routes.append(("GET", "/preview", self.mass.streams.serve_preview_stream)) + routes.append(("GET", "/preview", self.serve_preview_stream)) # start the webserver + self.publish_port = config.get_value(CONF_BIND_PORT) + self.publish_ip = config.get_value(CONF_BIND_IP) await self._server.setup( - bind_ip=config.get_value(CONF_BIND_IP), - bind_port=config.get_value(CONF_BIND_PORT), + bind_ip=self.publish_ip, + bind_port=self.publish_port, base_url=config.get_value(CONF_BASE_URL), static_routes=routes, # add assets subdir as static_content @@ -191,6 +195,17 @@ async def close(self) -> None: await client.disconnect() await self._server.close() + async def serve_preview_stream(self, request: web.Request): + """Serve short preview sample.""" + self._log_request(request) + provider_instance_id_or_domain = request.query["provider"] + item_id = urllib.parse.unquote(request.query["item_id"]) + resp = web.StreamResponse(status=200, reason="OK", headers={"Content-Type": "audio/mp3"}) + await resp.prepare(request) + async for chunk in get_preview_stream(self.mass, provider_instance_id_or_domain, item_id): + await resp.write(chunk) + return resp + async def _handle_server_info(self, request: web.Request) -> web.Response: # noqa: ARG002 """Handle request for server info.""" return web.json_response(self.mass.get_server_info().to_dict()) diff --git a/music_assistant/server/helpers/util.py b/music_assistant/server/helpers/util.py index 504e74b17..c4299544d 100644 --- a/music_assistant/server/helpers/util.py +++ b/music_assistant/server/helpers/util.py @@ -10,7 +10,6 @@ import urllib.error import urllib.parse import urllib.request -from contextlib import suppress from functools import lru_cache from importlib.metadata import PackageNotFoundError from importlib.metadata import version as pkg_version @@ -73,11 +72,17 @@ def call() -> set[str]: async def is_hass_supervisor() -> bool: """Return if we're running inside the HA Supervisor (e.g. HAOS).""" - with suppress(urllib.error.URLError): - res = await asyncio.to_thread(urllib.request.urlopen, "http://supervisor/core") - # this should return a 401 unauthorized if it exists - return res.code == 401 - return False + + def _check(): + try: + urllib.request.urlopen("http://supervisor/core") + except urllib.error.URLError as err: + # this should return a 401 unauthorized if it exists + return getattr(err, "code", 999) == 401 + except Exception: + return False + + return await asyncio.to_thread(_check) async def get_provider_module(domain: str) -> ProviderModuleType: diff --git a/music_assistant/server/server.py b/music_assistant/server/server.py index 24a505cd3..55c886906 100644 --- a/music_assistant/server/server.py +++ b/music_assistant/server/server.py @@ -517,8 +517,8 @@ async def _setup_discovery(self) -> None: info = ServiceInfo( zeroconf_type, name=f"{server_id}.{zeroconf_type}", - addresses=[await get_ip_pton(self.streams.publish_ip)], - port=self.streams.publish_port, + addresses=[await get_ip_pton(self.webserver.publish_ip)], + port=self.webserver.publish_port, properties=self.get_server_info().to_dict(), server="mass.local.", )