Skip to content

Commit

Permalink
Bump Music Assistant client to 2.2.4 + add new transfer queue service (
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelveldt authored Sep 14, 2024
1 parent d79038e commit 665c740
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 24 deletions.
21 changes: 5 additions & 16 deletions custom_components/mass/manifest.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
{
"domain": "mass",
"name": "Music Assistant",
"after_dependencies": [
"media_source",
"media_player"
],
"codeowners": [
"@music-assistant"
],
"after_dependencies": ["media_source", "media_player"],
"codeowners": ["@music-assistant"],
"config_flow": true,
"documentation": "https://music-assistant.io",
"iot_class": "local_push",
"issue_tracker": "https://github.com/music-assistant/hass-music-assistant/issues",
"loggers": [
"music_assistant"
],
"requirements": [
"music-assistant==2.1.3"
],
"loggers": ["music_assistant"],
"requirements": ["music-assistant==2.2.4"],
"version": "0.0.0",
"zeroconf": [
"_mass._tcp.local."
]
"zeroconf": ["_mass._tcp.local."]
}
57 changes: 49 additions & 8 deletions custom_components/mass/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
ATTR_ACTIVE_GROUP,
ATTR_ACTIVE_QUEUE,
ATTR_GROUP_LEADER,
ATTR_GROUP_MEMBERS,
ATTR_MASS_PLAYER_ID,
ATTR_MASS_PLAYER_TYPE,
ATTR_QUEUE_INDEX,
Expand Down Expand Up @@ -117,6 +116,7 @@

SERVICE_PLAY_MEDIA_ADVANCED = "play_media"
SERVICE_PLAY_ANNOUNCEMEMT = "play_announcement"
SERVICE_TRANSFER_QUEUE = "transfer_queue"
ATTR_RADIO_MODE = "radio_mode"
ATTR_MEDIA_ID = "media_id"
ATTR_MEDIA_TYPE = "media_type"
Expand All @@ -125,6 +125,8 @@
ATTR_URL = "url"
ATTR_USE_PRE_ANNOUNCE = "use_pre_announce"
ATTR_ANNOUNCE_VOLUME = "announce_volume"
ATTR_SOURCE_PLAYER = "source_player"
ATTR_AUTO_PLAY = "auto_play"

# pylint: disable=too-many-public-methods

Expand Down Expand Up @@ -204,6 +206,14 @@ async def handle_player_added(event: MassEvent) -> None:
},
"_async_play_announcement",
)
platform.async_register_entity_service(
SERVICE_TRANSFER_QUEUE,
{
vol.Required(ATTR_SOURCE_PLAYER): cv.entity_id,
vol.Optional(ATTR_AUTO_PLAY): vol.Coerce(bool),
},
"_async_transfer_queue",
)


class MassPlayer(MassBaseEntity, MediaPlayerEntity):
Expand Down Expand Up @@ -247,7 +257,7 @@ async def async_added_to_hass(self) -> None:
async def queue_time_updated(event: MassEvent) -> None:
if event.object_id != self.player.active_source:
return
if abs(self._prev_time - event.data) > 5:
if abs((self._prev_time or 0) - event.data) > 5:
await self.async_on_update()
self.async_write_ha_state()
self._prev_time = event.data
Expand All @@ -267,7 +277,6 @@ def extra_state_attributes(self) -> Mapping[str, Any]:
attrs = {
ATTR_MASS_PLAYER_ID: self.player_id,
ATTR_MASS_PLAYER_TYPE: player.type.value,
ATTR_GROUP_MEMBERS: player.group_childs,
ATTR_GROUP_LEADER: player.synced_to,
ATTR_ACTIVE_QUEUE: player.active_source,
ATTR_ACTIVE_GROUP: player.active_group,
Expand Down Expand Up @@ -304,11 +313,26 @@ async def async_on_update(self) -> None:
queue = self.mass.player_queues.get(player.active_source)
# update generic attributes
if player.powered:
self._attr_state = STATE_MAPPING[self.player.state]
self._attr_state = STATE_MAPPING.get(self.player.state)
else:
self._attr_state = STATE_OFF
self._attr_group_members = player.group_childs
self._attr_volume_level = player.volume_level / 100

# translate MA group_childs to HA group_members as entity id's
# TODO: find a way to optimize this a tiny bit more
# e.g. by holding a lookup dict in memory on integration level
group_members_entity_ids: list[str] = []
if player.group_childs:
for state in self.hass.states.async_all("media_player"):
if not (mass_player_id := state.attributes.get("mass_player_id")):
continue
if mass_player_id not in player.group_childs:
continue
group_members_entity_ids.append(state.entity_id)
self._attr_group_members = group_members_entity_ids

self._attr_volume_level = (
player.volume_level / 100 if player.volume_level is not None else None
)
self._attr_is_volume_muted = player.volume_muted
self._update_media_attributes(player, queue)
self._update_media_image_url(player, queue)
Expand Down Expand Up @@ -523,6 +547,21 @@ async def _async_play_announcement(
self.player_id, url, use_pre_announce, announce_volume
)

@catch_musicassistant_error
async def _async_transfer_queue(
self, source_player: str, auto_play: bool | None = None
) -> None:
"""Transfer the current queue to another player."""
# resolve HA entity_id to MA player_id
if (hass_state := self.hass.states.get(source_player)) is None:
return # guard
if (mass_player_id := hass_state.attributes.get("mass_player_id")) is None:
return # guard
if queue := self.mass.player_queues.get(self.player.active_source):
await self.mass.player_queues.transfer_queue(
mass_player_id, queue.queue_id, auto_play
)

async def async_browse_media(
self, media_content_type=None, media_content_id=None
) -> BrowseMedia:
Expand Down Expand Up @@ -638,8 +677,10 @@ def _update_media_attributes(
self._attr_shuffle = None
self._attr_repeat = None
self._attr_media_position = player.elapsed_time
self._attr_media_position_updated_at = from_utc_timestamp(
player.elapsed_time_last_updated
self._attr_media_position_updated_at = (
from_utc_timestamp(player.elapsed_time_last_updated)
if player.elapsed_time_last_updated
else None
)
self._prev_time = player.elapsed_time
return
Expand Down
3 changes: 3 additions & 0 deletions custom_components/mass/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
ATTR_SEARCH_ARTIST = "artist"
ATTR_SEARCH_ALBUM = "album"
ATTR_LIMIT = "limit"
ATTR_LIBRARY_ONLY = "library_only"


@callback
Expand All @@ -46,6 +47,7 @@ async def handle_search(call: ServiceCall) -> ServiceResponse:
search_query=search_name,
media_types=call.data.get(ATTR_MEDIA_TYPE, MediaType.ALL),
limit=call.data[ATTR_LIMIT],
library_only=call.data[ATTR_LIBRARY_ONLY],
)

# return limited result to prevent it being too verbose
Expand Down Expand Up @@ -92,6 +94,7 @@ def compact_item(item: dict[str, Any]) -> dict[str, Any]:
vol.Optional(ATTR_SEARCH_ARTIST): cv.string,
vol.Optional(ATTR_SEARCH_ALBUM): cv.string,
vol.Optional(ATTR_LIMIT, default=5): vol.Coerce(int),
vol.Optional(ATTR_LIBRARY_ONLY, default=False): cv.boolean,
}
),
supports_response=SupportsResponse.ONLY,
Expand Down
24 changes: 24 additions & 0 deletions custom_components/mass/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,24 @@ play_announcement:
max: 100
step: 1

transfer_queue:
target:
entity:
domain: media_player
integration: mass
fields:
source_entity:
required: true
selector:
entity:
domain: media_player
integration: mass
auto_play:
required: false
example: "true"
selector:
boolean:

search:
fields:
name:
Expand Down Expand Up @@ -121,3 +139,9 @@ search:
min: 1
max: 100
step: 1
library_only:
required: false
example: "true"
default: false
selector:
boolean:
18 changes: 18 additions & 0 deletions custom_components/mass/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@
}
}
},
"transfer_queue": {
"name": "Transfer Queue",
"description": "Transfer the player's queue to another player.",
"fields": {
"source_entity": {
"name": "Source media player",
"description": "The source media player which queue you want to transfer."
},
"auto_play": {
"name": "Auto play",
"description": "Start playing the queue on the target player. Omit to use the default behavior."
}
}
},
"search": {
"name": "Search Music Assistant",
"description": "Perform a global search on the Music Assistant library and all providers.",
Expand All @@ -102,6 +116,10 @@
"limit": {
"name": "Limit",
"description": "Maximum number of items to return (per media type)."
},
"library_only": {
"name": "Only library items",
"description": "Only include results that are in the library."
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions custom_components/mass/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@
}
}
},
"transfer_queue": {
"name": "Transfer Queue",
"description": "Transfer the player's queue to another player.",
"fields": {
"source_entity": {
"name": "Source media player",
"description": "The source media player which queue you want to transfer."
},
"auto_play": {
"name": "Auto play",
"description": "Start playing the queue on the target player. Omit to use the default behavior."
}
}
},
"search": {
"name": "Search Music Assistant",
"description": "Perform a global search on the Music Assistant library and all providers.",
Expand All @@ -103,6 +117,10 @@
"limit": {
"name": "Limit",
"description": "Maximum number of items to return (per media type)."
},
"library_only": {
"name": "Only library items",
"description": "Only include results that are in the library."
}
}
}
Expand Down

0 comments on commit 665c740

Please sign in to comment.