diff --git a/src/linkplay/bridge.py b/src/linkplay/bridge.py index 860bae0..7c18d51 100644 --- a/src/linkplay/bridge.py +++ b/src/linkplay/bridge.py @@ -153,9 +153,15 @@ async def update_status(self) -> None: self.properties = fixup_player_properties(properties) if self.bridge.device.manufacturer == MANUFACTURER_WIIM: - self.metainfo: dict[ - MetaInfo, dict[MetaInfoMetaData, str] - ] = await self.bridge.json_request(LinkPlayCommand.META_INFO) # type: ignore[assignment] + try: + self.metainfo: dict[ + MetaInfo, dict[MetaInfoMetaData, str] + ] = await self.bridge.json_request(LinkPlayCommand.META_INFO) # type: ignore[assignment] + except LinkPlayInvalidDataException as exc: + if getattr(exc, "data", None) == "Failed": + self.metainfo = {} + else: + raise else: self.metainfo = {} diff --git a/src/linkplay/consts.py b/src/linkplay/consts.py index 74f651b..681d1d6 100644 --- a/src/linkplay/consts.py +++ b/src/linkplay/consts.py @@ -473,18 +473,18 @@ def __str__(self): def __repr__(self): return self.value - -class MetaInfo(StrEnum): +class MetaInfo(StrEnum): METADATA = "metaData" - + def __str__(self): return self.value def __repr__(self): - return self.value - + return self.value + + class MetaInfoMetaData(StrEnum): """Defines the metadata within the metainfo.""" @@ -496,25 +496,27 @@ class MetaInfoMetaData(StrEnum): BIT_DEPTH = "bitDepth" BIT_RATE = "bitRate" TRACK_ID = "trackId" - + def __str__(self): return self.value def __repr__(self): - return self.value - + return self.value + class AudioOutputHwMode(StrEnum): """Defines a output mode for the hardware.""" + OPTICAL = "1" LINE_OUT = "2" COAXIAL = "3" HEADPHONES = "4" + # Map between a play mode and how to activate the play mode AUDIO_OUTPUT_HW_MODE_MAP: dict[AudioOutputHwMode, str] = { # case sensitive! AudioOutputHwMode.OPTICAL: "optical", AudioOutputHwMode.LINE_OUT: "line-out", AudioOutputHwMode.COAXIAL: "co-axial", AudioOutputHwMode.HEADPHONES: "headphones", -} \ No newline at end of file +} diff --git a/src/linkplay/exceptions.py b/src/linkplay/exceptions.py index 3c50c86..db29433 100644 --- a/src/linkplay/exceptions.py +++ b/src/linkplay/exceptions.py @@ -7,4 +7,6 @@ class LinkPlayRequestException(LinkPlayException): class LinkPlayInvalidDataException(LinkPlayException): - pass + def __init__(self, message: str = "Invalid data received", data: str | None = None): + super().__init__(message) + self.data = data diff --git a/src/linkplay/utils.py b/src/linkplay/utils.py index cf16bcf..bb45573 100644 --- a/src/linkplay/utils.py +++ b/src/linkplay/utils.py @@ -82,7 +82,7 @@ async def session_call_api_json( except json.JSONDecodeError as jsonexc: url = API_ENDPOINT.format(endpoint, command) raise LinkPlayInvalidDataException( - f"Unexpected JSON ({result}) received from '{url}'" + message=f"Unexpected JSON ({result}) received from '{url}'", data=result ) from jsonexc diff --git a/tests/linkplay/test_bridge.py b/tests/linkplay/test_bridge.py index 03ebcde..7c3529c 100644 --- a/tests/linkplay/test_bridge.py +++ b/tests/linkplay/test_bridge.py @@ -1,7 +1,7 @@ """Test bridge functionality.""" from typing import Any -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import AsyncMock, MagicMock, Mock, patch import pytest from linkplay.bridge import ( @@ -22,6 +22,7 @@ PlayingStatus, ) from linkplay.endpoint import LinkPlayApiEndpoint +from linkplay.manufacturers import MANUFACTURER_WIIM def test_device_name(): @@ -561,3 +562,40 @@ async def test_update_status_does_not_trigger_controller_on_no_mode_change(mock_ await player.update_status() mock_bridge.device.controller.assert_not_called() + + +async def test_meta_info_failed_handling(): + """Test that the player handles a failed META_INFO request correctly.""" + + async def mock_session_call_api_json_side_effect(endpoint, session, command): + if command == LinkPlayCommand.META_INFO: + return "Failed" + return "{}" + + # Mock the session_call_api function + with patch( + "linkplay.utils.session_call_api", + new=AsyncMock(side_effect=mock_session_call_api_json_side_effect), + ) as mock_api: + # Mock the bridge and its device + mock_bridge = LinkPlayBridge( + endpoint=LinkPlayApiEndpoint( + protocol="http", port=80, endpoint="1.2.3.4", session=None + ) + ) + mock_bridge.device = MagicMock() + mock_bridge.device.manufacturer = ( + MANUFACTURER_WIIM # Set the manufacturer to WiiM + ) + + # Create a LinkPlayPlayer instance with the mocked bridge + player = LinkPlayPlayer(mock_bridge) + + # Simulate the META_INFO request and exception handling + await player.update_status() + + # Verify that metainfo is set to an empty dictionary after the exception + assert player.metainfo == {} + + # Verify that the mocked function was called with the correct command + mock_api.assert_called_with("http://1.2.3.4", None, LinkPlayCommand.META_INFO)