Skip to content

Commit

Permalink
Implement fixup_player_properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Philip Vanloo committed Aug 22, 2024
1 parent dad53e2 commit 3d6857c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 16 deletions.
9 changes: 4 additions & 5 deletions src/linkplay/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
SpeakerType,
)
from linkplay.endpoint import LinkPlayEndpoint
from linkplay.utils import decode_hexstr
from linkplay.utils import fixup_player_properties


class LinkPlayDevice:
Expand Down Expand Up @@ -83,10 +83,9 @@ def __init__(self, bridge: LinkPlayBridge):

async def update_status(self) -> None:
"""Update the player status."""
self.properties = await self.bridge.json_request(LinkPlayCommand.PLAYER_STATUS) # type: ignore[assignment]
self.properties[PlayerAttribute.TITLE] = decode_hexstr(self.title)
self.properties[PlayerAttribute.ARTIST] = decode_hexstr(self.artist)
self.properties[PlayerAttribute.ALBUM] = decode_hexstr(self.album)
self.properties = fixup_player_properties(
await self.bridge.json_request(LinkPlayCommand.PLAYER_STATUS)
)

async def next(self) -> None:
"""Play the next song in the playlist."""
Expand Down
35 changes: 32 additions & 3 deletions src/linkplay/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@
import socket
import ssl
from http import HTTPStatus
from typing import Dict

import aiofiles
import async_timeout
from aiohttp import ClientError, ClientSession, TCPConnector
from appdirs import AppDirs

from linkplay.consts import API_ENDPOINT, API_TIMEOUT, MTLS_CERTIFICATE_CONTENTS
from linkplay.consts import (
API_ENDPOINT,
API_TIMEOUT,
MTLS_CERTIFICATE_CONTENTS,
PlayerAttribute,
PlayingStatus,
)
from linkplay.exceptions import LinkPlayRequestException


Expand Down Expand Up @@ -51,7 +56,7 @@ async def session_call_api(endpoint: str, session: ClientSession, command: str)

async def session_call_api_json(
endpoint: str, session: ClientSession, command: str
) -> Dict[str, str]:
) -> dict[str, str]:
"""Calls the LinkPlay API and returns the result as a JSON object."""
result = await session_call_api(endpoint, session, command)
return json.loads(result) # type: ignore
Expand Down Expand Up @@ -125,3 +130,27 @@ async def async_create_unverified_client_session() -> ClientSession:
context: ssl.SSLContext = await async_create_unverified_context()
connector: TCPConnector = TCPConnector(family=socket.AF_UNSPEC, ssl=context)
return ClientSession(connector=connector)


def fixup_player_properties(
properties: dict[PlayerAttribute, str],
) -> dict[PlayerAttribute, str]:
"""Fixes up PlayerAttribute in a dict."""
properties[PlayerAttribute.TITLE] = decode_hexstr(
properties.get(PlayerAttribute.TITLE, "")
)
properties[PlayerAttribute.ARTIST] = decode_hexstr(
properties.get(PlayerAttribute.ARTIST, "")
)
properties[PlayerAttribute.ALBUM] = decode_hexstr(
properties.get(PlayerAttribute.ALBUM, "")
)

# Fixup playing status "none" by setting it to "stopped"
if (
properties.get(PlayerAttribute.PLAYING_STATUS, "")
not in PlayingStatus.__members__.values()
):
properties[PlayerAttribute.PLAYING_STATUS] = PlayingStatus.STOPPED

return properties
21 changes: 14 additions & 7 deletions tests/linkplay/test_bridge.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Test bridge functionality."""

from unittest.mock import AsyncMock
from unittest.mock import AsyncMock, patch

from linkplay.bridge import (
LinkPlayBridge,
Expand Down Expand Up @@ -59,17 +59,24 @@ async def test_device_reboot():
async def test_player_update_status():
"""Tests if the player update status is correctly called."""
bridge = AsyncMock()
bridge.json_request.return_value = {
PlayerAttribute.TITLE: "556E6B6E6F776E",
PlayerAttribute.ARTIST: "556E6B6E6F776E",
PlayerAttribute.ALBUM: "556E6B6E6F776E",
}
bridge.json_request.return_value = {}
player = LinkPlayPlayer(bridge)

await player.update_status()

bridge.json_request.assert_called_once_with(LinkPlayCommand.PLAYER_STATUS)
assert player.title == "Unknown"


async def test_player_update_status_calls_fixup_player_properties():
"""Tests if the player update status is correctly called."""

with patch("linkplay.bridge.fixup_player_properties") as fixup_mock:
bridge = AsyncMock()
player = LinkPlayPlayer(bridge)

await player.update_status()

fixup_mock.assert_called_once()


async def test_player_next():
Expand Down
29 changes: 28 additions & 1 deletion tests/linkplay/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Test utility functions."""

from linkplay.utils import decode_hexstr
from linkplay.consts import PlayerAttribute, PlayingStatus
from linkplay.utils import decode_hexstr, fixup_player_properties


def test_decode_hexstr():
Expand All @@ -11,3 +12,29 @@ def test_decode_hexstr():
def test_decode_hexstr_invalid():
"""Tests the decode_hexstr function upon invalid input."""
assert "ABCDEFGHIJKLMNOPQRSTUVWXYZ" == decode_hexstr("ABCDEFGHIJKLMNOPQRSTUVWXYZ")


def test_fixup_player_properties_decodes_hexstr():
"""Tests if the fixup_player_properties function properly fixes the dict."""
test_dict: dict[PlayerAttribute, str] = {
PlayerAttribute.ARTIST: "556E6B6E6F776E",
PlayerAttribute.TITLE: "556E6B6E6F776E",
PlayerAttribute.ALBUM: "556E6B6E6F776E",
}

fixed_dict: dict[PlayerAttribute, str] = fixup_player_properties(test_dict)

assert fixed_dict[PlayerAttribute.ARTIST] == "Unknown"
assert fixed_dict[PlayerAttribute.TITLE] == "Unknown"
assert fixed_dict[PlayerAttribute.ALBUM] == "Unknown"


def test_fixup_player_properties_fixes_playing_status():
"""Tests if the fixup_player_properties function properly fixes the dict."""
test_dict: dict[PlayerAttribute, str] = {
PlayerAttribute.PLAYING_STATUS: "none",
}

fixed_dict: dict[PlayerAttribute, str] = fixup_player_properties(test_dict)

assert fixed_dict[PlayerAttribute.PLAYING_STATUS] == PlayingStatus.STOPPED

0 comments on commit 3d6857c

Please sign in to comment.