diff --git a/pyheos/const.py b/pyheos/const.py index 79d70e6..04ff0a0 100644 --- a/pyheos/const.py +++ b/pyheos/const.py @@ -40,6 +40,9 @@ SYSTEM_ERROR_CONTENT_AUTHORIZATION_ERROR: Final = -1232 SYSTEM_ERROR_ACCOUNT_PARAMETERS_INVALID: Final = -1239 +# Search Crtieria Container IDs (keep discrete values as we do not control the list) +SEARCHED_TRACKS: Final = "SEARCHED_TRACKS-" + # Music Sources (keep discrete values as we do not control the list) MUSIC_SOURCE_CONNECT: Final = 0 # TIDAL Connect // possibly Spotify Connect as well (?) MUSIC_SOURCE_PANDORA: Final = 1 diff --git a/pyheos/heos.py b/pyheos/heos.py index 334444b..1500175 100644 --- a/pyheos/heos.py +++ b/pyheos/heos.py @@ -498,6 +498,33 @@ async def add_to_queue( ) ) + async def add_search_to_queue( + self, + player_id: int, + source_id: int, + search: str, + criteria_container_id: str = const.SEARCHED_TRACKS, + add_criteria: AddCriteriaType = AddCriteriaType.PLAY_NOW, + ) -> None: + """Add searched tracks to the queue of the specified player. + + References: + 4.4.11 Add Container to Queue with Options + + Args: + player_id: The identifier of the player to add the search results. + source_id: The identifier of the source to search. + search: The search string. + criteria_container_id: the criteria container id prefix. + add_criteria: Determines how tracks are added to the queue. The default is AddCriteriaType.PLAY_NOW. + """ + await self.add_to_queue( + player_id=player_id, + source_id=source_id, + container_id=f"{criteria_container_id}{search}", + add_criteria=add_criteria, + ) + async def rename_playlist( self, source_id: int, container_id: str, new_name: str ) -> None: diff --git a/pyheos/player.py b/pyheos/player.py index ac061ff..a3a7a7c 100644 --- a/pyheos/player.py +++ b/pyheos/player.py @@ -463,6 +463,33 @@ async def add_to_queue( self.player_id, source_id, container_id, media_id, add_criteria ) + async def add_search_to_queue( + self, + source_id: int, + search: str, + criteria_container_id: str = const.SEARCHED_TRACKS, + add_criteria: AddCriteriaType = AddCriteriaType.PLAY_NOW, + ) -> None: + """Add searched tracks to the queue of the specified player. + + References: + 4.4.11 Add Container to Queue with Options + + Args: + source_id: The identifier of the source to search. + search: The search string. + criteria_container_id: the criteria container id prefix. + add_criteria: Determines how tracks are added to the queue. The default is AddCriteriaType.PLAY_NOW. + """ + assert self.heos, "Heos instance not set" + await self.heos.add_search_to_queue( + player_id=self.player_id, + source_id=source_id, + search=search, + criteria_container_id=criteria_container_id, + add_criteria=add_criteria, + ) + async def play_media( self, media: MediaItem, diff --git a/tests/fixtures/browse.add_to_queue_search.json b/tests/fixtures/browse.add_to_queue_search.json new file mode 100644 index 0000000..cd6e32e --- /dev/null +++ b/tests/fixtures/browse.add_to_queue_search.json @@ -0,0 +1 @@ +{"heos": {"command": "browse/add_to_queue", "result": "success", "message": "pid={player_id}&sid=10&cid=SEARCHED_TRACKS-Tangerine Rays&aid=3"}} \ No newline at end of file diff --git a/tests/test_player.py b/tests/test_player.py index cf5a420..fdd0000 100644 --- a/tests/test_player.py +++ b/tests/test_player.py @@ -5,7 +5,13 @@ import pytest from pyheos import command as c -from pyheos.const import INPUT_AUX_IN_1, MUSIC_SOURCE_DEEZER, MUSIC_SOURCE_PLAYLISTS +from pyheos.const import ( + INPUT_AUX_IN_1, + MUSIC_SOURCE_DEEZER, + MUSIC_SOURCE_PLAYLISTS, + MUSIC_SOURCE_TIDAL, + SEARCHED_TRACKS, +) from pyheos.media import MediaItem from pyheos.player import HeosPlayer from pyheos.types import ( @@ -441,6 +447,21 @@ async def test_add_to_queue(player: HeosPlayer) -> None: ) +@calls_command( + "browse.add_to_queue_search", + { + c.ATTR_PLAYER_ID: 1, + c.ATTR_SOURCE_ID: MUSIC_SOURCE_TIDAL, + c.ATTR_CONTAINER_ID: SEARCHED_TRACKS + "Tangerine Rays", + c.ATTR_ADD_CRITERIA_ID: AddCriteriaType.PLAY_NOW, + }, + add_command_under_process=True, +) +async def test_add_search_to_queue(player: HeosPlayer) -> None: + """Test adding a track to the queue.""" + await player.add_search_to_queue(MUSIC_SOURCE_TIDAL, "Tangerine Rays") + + @calls_command("player.get_now_playing_media_blank", {c.ATTR_PLAYER_ID: 1}) async def test_now_playing_media_unavailable(player: HeosPlayer) -> None: """Test edge case where now_playing_media returns an empty payload."""