Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 175 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,17 @@ Designed to work with [Music Assistant Player Card](https://github.com/droans/ma

## New actions:

The response schemas for all new actions and WebSocket commands can be found at [docs/response_schemas.md](docs/response_schemas.md)

---

<details>
<summary>Queue Actions</summary>

`mass_queue.get_queue_items`: Returns the items (songs, podcast episods, etc.) within a queue

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Parameter | Type | Required | Default | Description |
|-----------------|------|----------|-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `entity` | str | Yes | n/a | Music assistant player entity |
| `limit` | int | No | 500 | Number of items in queue to return |
| `offset` | int | No | n/a | Location in queue to start where zero equals the first item in queue, not the current item. By default, will start with five items before actively playing item. |
Expand Down Expand Up @@ -103,7 +109,161 @@ media_player.music_assistant_speaker:
|-------------------|------|----------|---------|---------------------------------------------|
| `command` | str | Yes | n/a | The command to send to Music Assistant |
| `data` | dict | No | None | Any data to send with the command |
| `config_entry_id` | dict | No | None | The ID of the used `mass_queue` integration |
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |

`mass_queue.clear_queue_from_here`: Clear the items in a queue after the currently playing item.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------------------------|
| `entity` | str | Yes | n/a | Music assistant player entity |

`mass_queue.unfavorite_current_item`: Unfavorite the currently playing item

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------------------------|
| `entity` | str | Yes | n/a | Music assistant player entity |

</details>

<details>
<summary>Group Actions</summary>

`mass_queue.set_group_volume`: Sets the volume for the group which the provided player belongs to.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------------------------|
| `entity` | str | Yes | n/a | Music assistant player entity |

`mass_queue.get_group_volume`: Returns the volume for a player group.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------------------------|
| `entity` | str | Yes | n/a | Music assistant player entity |

</details>

<details>
<summary>Collection Actions</summary>

`mass_queue.get_recommendations`: Get recommendations from your music providers.

| Parameter | Type | Required | Default | Description |
|--------------|-------------|----------|---------|----------------------------------------------------|
| `entity` | str | Yes | n/a | Music assistant player entity |
| `providers` | list of str | No | n/a | Limit recommendations to the specified provider(s) |

---
### Albums
`mass_queue.get_album`: Returns information about an album from the MA server.

| Parameter | Type | Required | Default | Description |
|-------------------|------|----------|---------|---------------------------------------------|
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |
| `uri` | str | Yes | n/a | The URI for the playlist |

`mass_queue.get_album_tracks`: Returns some or all tracks for the album given by the URI.

| Parameter | Type | Required | Default | Description |
|-------------------|------|----------|---------|----------------------------------------------------------|
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |
| `uri` | str | Yes | n/a | The URI for the album |
| `page` | int | No | None | Page of results to return. If not provided, returns all. |

---
### Artists
`mass_queue.get_artist`: Returns information about an artist from the MA server.

| Parameter | Type | Required | Default | Description |
|-------------------|------|----------|---------|---------------------------------------------|
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |
| `uri` | str | Yes | n/a | The URI for the playlist |

`mass_queue.get_artist_tracks`: Returns the top tracks for the artist given by the URI.

| Parameter | Type | Required | Default | Description |
|-------------------|------|----------|---------|----------------------------------------------------------|
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |
| `uri` | str | Yes | n/a | The URI for the artist |
| `page` | int | No | None | Page of results to return. If not provided, returns all. |

---
### Playlists
`mass_queue.get_playlist`: Returns information about a playlist from the MA server.

| Parameter | Type | Required | Default | Description |
|-------------------|------|----------|---------|---------------------------------------------|
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |
| `uri` | str | Yes | n/a | The URI for the playlist |

`mass_queue.get_playlist_tracks`: Returns some or all tracks for the playlist given by the URI.

| Parameter | Type | Required | Default | Description |
|-------------------|------|----------|---------|----------------------------------------------------------|
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |
| `uri` | str | Yes | n/a | The URI for the playlist |
| `page` | int | No | None | Page of results to return. If not provided, returns all. |

`mass_queue.remove_playlist_tracks`: Removes one or more tracks from a playlist based on their position. **IMPORTANT: SEE WARNING BELOW**

| Parameter | Type | Required | Default | Description |
|-----------------------|-------------|----------|---------|---------------------------------------------------|
| `config_entry_id` | str | Yes | n/a | The ID of the used `mass_queue` integration |
| `playlist_id` | str | Yes | n/a | The ID of the playlist |
| `positions_to_remove` | list of str | Yes | n/a | Position(s) of items to remove from the playlist. |

### ⚠️WARNING: mass_queue.remove_playlist_tracks is bad for your health.⚠️

`mass_queue.remove_playlist_tracks` is **dangerous**.

Music Assistant will use the positions in a playlist to determine which tracks to remove. However, it does not provide an updated playlist immediately, instead waiting for the next refresh.

You must be **VERY** careful if you are using this action. You should **NOT** rely on proper feedback from Music Assistant. If you plan on using this, you MUST plan to work around this.

---

### Podcasts
`mass_queue.get_podcast`: Returns information about a podcast from the MA server.

| Parameter | Type | Required | Default | Description |
|-------------------|------|----------|---------|---------------------------------------------|
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |
| `uri` | str | Yes | n/a | The URI for the playlist |

`mass_queue.get_podcast_episodes`: Returns some or all episodes for the podcast given by the URI.

| Parameter | Type | Required | Default | Description |
|-------------------|------|----------|---------|----------------------------------------------------------|
| `config_entry_id` | str | No | None | The ID of the used `mass_queue` integration |
| `uri` | str | Yes | n/a | The URI for the podcast |
| `page` | int | No | None | Page of results to return. If not provided, returns all. |

</details>

## New Websocket Commands:

The WebSocket commands below can be used by custom cards/integrations along with whatever personal use you may discern.

`mass_queue/get_info`: Returns basic information about a Music Assistant player.

| Parameter | Type | Required | Description |
|-------------------|------|----------|--------------------------------|
| `type` | str | Yes | Must be `mass_queue/get_info` |
| `entity_id` | str | Yes | Music assistant player entity |

`mass_queue/download_and_encode_image`: Returns a single image for a media item as a Base64 encoded string. Useful when avoiding mixed-content or when accessing local media outside of your network

| Parameter | Type | Required | Description |
|-------------------|------|----------|-------------------------------------------------|
| `type` | str | Yes | Must be `mass_queue/download_and_encode_image` |
| `url` | str | Yes | URL of media to download. |

`mass_queue/get_user_info`: Returns a single image for a media item as a Base64 encoded string. Useful when avoiding mixed-content or when accessing local media outside of your network

| Parameter | Type | Required | Description |
|-------------------|------|----------|---------------------------------------|
| `type` | str | Yes | Must be `mass_queue/get_user_info` |
| `entity_id` | str | Yes | URL of media to download. |
| `username` | str | Yes | Username of user to return info for. |

## Installation

Expand Down Expand Up @@ -133,6 +293,18 @@ This option will then return a new attribute for these queue items labeled `loca
* Loading the integration and updating the queue WILL take much longer. Each item must be downloaded and converted. This is NOT a quick process. Depending on your server, this may take between 2-20 seconds per item.
* This requires that Home Assistant can directly access the Music Assistant server along with the local provider.

## I'm having issues trying to authenticate!

The OAuth flow for Music Assistant and Home Assistant can sometimes be finicky. In most instances, the issue is due to the differences in the expected and the used address for either Music Assistant or Home Assistant. However, there is fortunately a simple fix.

First, complete the process as much as you can. When you receive an error, go to the navigation bar on your browser. Take a note at the address you currently are at and whether it is the address for Music Assistant or for Home Assistant.

Then, simply change the base URL from whatever is displayed to the actual IP and port for MA or HA.

## Where are the entities at?

This integration does not create any new entities. It only provides new actions and WebSocket commands which can be used in scripts, automations, and custom cards.

## I am the creator of a custom card. Can I use these actions in my own card, too?

Of course - this is open-source! The only requirement is that you give credit.
Expand Down
2 changes: 2 additions & 0 deletions custom_components/mass_queue/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
api_download_and_encode_image,
api_download_images,
api_get_entity_info,
api_get_user_info,
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -146,6 +147,7 @@ async def on_hass_stop(event: Event) -> None: # noqa: ARG001
websocket_api.async_register_command(hass, api_download_images)
websocket_api.async_register_command(hass, api_download_and_encode_image)
websocket_api.async_register_command(hass, api_get_entity_info)
websocket_api.async_register_command(hass, api_get_user_info)

# If the listen task is already failed, we need to raise ConfigEntryNotReady
if listen_task.done() and (listen_error := listen_task.exception()) is not None:
Expand Down
2 changes: 1 addition & 1 deletion custom_components/mass_queue/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
"issue_tracker": "https://github.com/droans/mass_queue/issues",
"requirements": ["music-assistant-client"],
"ssdp": [],
"version": "0.10.0",
"version": "0.10.1",
"zeroconf": ["_mass._tcp.local."]
}
8 changes: 4 additions & 4 deletions custom_components/mass_queue/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
},
"manual": {
"title": "Manually add Music Assistant server",
"description": "Enter the URL to your already running Music Assistant server. If you do not have the Music Assistant server running, you should install it first.",
"description": "Enter the URL to your already running Music Assistant server for Music Assistant Queue Actions to use. If you do not have the Music Assistant server running, you should install it first.",
"data": {
"url": "URL of the Music Assistant server"
}
},
"discovery_confirm": {
"description": "Do you want to add the Music Assistant server `{url}` to Home Assistant?",
"description": "Do you want to add Music Assistant Queue Actions (via the Music Assistant server `{url}`) to Home Assistant?",
"title": "Discovered Music Assistant server"
}
},
Expand All @@ -26,7 +26,7 @@
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
"reconfiguration_successful": "Successfully reconfigured the Music Assistant integration.",
"reconfiguration_successful": "Successfully reconfigured the Music Assistant Queue Action integration.",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]"
}
Expand All @@ -43,7 +43,7 @@
"issues": {
"invalid_server_version": {
"title": "The Music Assistant server is not the correct version",
"description": "Check if there are updates available for the Music Assistant server and/or integration."
"description": "Check if there are updates available for the Music Assistant server and/or MA Queue Actions integration."
}
},
"services": {
Expand Down
11 changes: 10 additions & 1 deletion custom_components/mass_queue/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def find_mass_queue_entry_from_unique_id(hass: HomeAssistant, unique_id: str):
for entry in entries:
if entry.unique_id == unique_id:
return entry
msg = f"Cannot find entry for Music Assistant with unique ID {unique_id}"
msg = f"Cannot find entry for Music Assistant Queue Actions with unique ID {unique_id}. Are the integrations for Music Assistant and Music Assistant Queue Actions configured?"
raise ServiceValidationError(msg)


Expand Down Expand Up @@ -295,6 +295,15 @@ async def download_and_encode_image(url: str, hass: HomeAssistant):
return f"data:image;base64,{base64.b64encode(read).decode('utf-8')}"


async def get_user_info(hass: HomeAssistant, entity_id: str, username: str):
"""Returns the user information for the given username."""
client = get_mass_client(hass, entity_id)
users = await client.auth.list_users()
LOGGER.debug(f"Client: {client}")
LOGGER.debug(f"Users: {users}")
return [user.to_dict() for user in users if user.username == username][0]


def get_entity_info(hass: HomeAssistant, entity_id: str):
"""Gets the server and client info for a given player."""
client = get_mass_client(hass, entity_id)
Expand Down
23 changes: 23 additions & 0 deletions custom_components/mass_queue/websocket_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
download_and_encode_image,
download_single_image_from_image_data,
get_entity_info,
get_user_info,
)


Expand Down Expand Up @@ -101,3 +102,25 @@ async def get_playlist_items(
msg: dict,
) -> None:
"""Retrieves all playlist items."""


@websocket_api.websocket_command(
{
vol.Required("type"): "mass_queue/get_user_info",
vol.Required("entity_id"): str,
vol.Required("username"): str,
},
)
@websocket_api.async_response
async def api_get_user_info(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict,
) -> None:
"""Returns the information for a given user."""
entity_id = msg["entity_id"]
username = msg["username"]
LOGGER.debug(f"Received message {msg}")
result = await get_user_info(hass, entity_id, username)
LOGGER.debug(f"Sending result {result}")
connection.send_result(msg["id"], result)
Loading
Loading