diff --git a/README.md b/README.md
index 1546b08..a4a7a97 100644
--- a/README.md
+++ b/README.md
@@ -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)
+
---
+
+
+Queue Actions
+
`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. |
@@ -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 |
+
+
+
+
+Group Actions
+
+`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 |
+
+
+
+
+Collection Actions
+
+`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. |
+
+
+
+## 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
@@ -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.
diff --git a/custom_components/mass_queue/__init__.py b/custom_components/mass_queue/__init__.py
index fd929ec..1546f8c 100644
--- a/custom_components/mass_queue/__init__.py
+++ b/custom_components/mass_queue/__init__.py
@@ -43,6 +43,7 @@
api_download_and_encode_image,
api_download_images,
api_get_entity_info,
+ api_get_user_info,
)
if TYPE_CHECKING:
@@ -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:
diff --git a/custom_components/mass_queue/manifest.json b/custom_components/mass_queue/manifest.json
index facb84e..591fa8c 100644
--- a/custom_components/mass_queue/manifest.json
+++ b/custom_components/mass_queue/manifest.json
@@ -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."]
}
diff --git a/custom_components/mass_queue/translations/en.json b/custom_components/mass_queue/translations/en.json
index 1e04102..952238a 100644
--- a/custom_components/mass_queue/translations/en.json
+++ b/custom_components/mass_queue/translations/en.json
@@ -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"
}
},
@@ -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%]"
}
@@ -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": {
diff --git a/custom_components/mass_queue/utils.py b/custom_components/mass_queue/utils.py
index eda3601..7f1c2d8 100644
--- a/custom_components/mass_queue/utils.py
+++ b/custom_components/mass_queue/utils.py
@@ -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)
@@ -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)
diff --git a/custom_components/mass_queue/websocket_commands.py b/custom_components/mass_queue/websocket_commands.py
index 5402b83..2f5236e 100644
--- a/custom_components/mass_queue/websocket_commands.py
+++ b/custom_components/mass_queue/websocket_commands.py
@@ -16,6 +16,7 @@
download_and_encode_image,
download_single_image_from_image_data,
get_entity_info,
+ get_user_info,
)
@@ -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)
diff --git a/docs/response_schemas.md b/docs/response_schemas.md
new file mode 100644
index 0000000..a2eb90c
--- /dev/null
+++ b/docs/response_schemas.md
@@ -0,0 +1,168 @@
+# Schemas
+
+## Service Schemas
+
+### GetQueueItemsResponseSchema
+
+```yaml
+[player_name: str]: QueueItemSchema[]
+```
+
+### GetGroupVolumeResponseSchema
+
+```yaml
+volume_level: int
+```
+
+
+### SendCommandResponseSchema
+
+```yaml
+response: any
+```
+
+### GetRecommendationsResponseSchema
+
+```yaml
+response: RecommendationFolder[]
+```
+
+### GetAlbumResponseSchema
+
+*See [music_assistant_models.media_items.Album](https://github.com/music-assistant/models/blob/0f2ad708ab26d2cc2ae008872afc00cd4a795380/music_assistant_models/media_items/media_item.py#L208)*
+
+
+### GetArtistResponseSchema
+
+*See [music_assistant_models.media_items.Artist](https://github.com/music-assistant/models/blob/0f2ad708ab26d2cc2ae008872afc00cd4a795380/music_assistant_models/media_items/media_item.py#L198)*
+
+### GetPlaylistResponseSchema
+
+*See [music_assistant_models.media_items.Playlist](https://github.com/music-assistant/models/blob/0f2ad708ab26d2cc2ae008872afc00cd4a795380/music_assistant_models/media_items/media_item.py#L254)*
+
+### GetPodcastResponseSchema
+
+*See [music_assistant_models.media_items.Podcast](https://github.com/music-assistant/models/blob/0f2ad708ab26d2cc2ae008872afc00cd4a795380/music_assistant_models/media_items/media_item.py#L323)*
+
+### GetAlbumTracksResponseSchema
+
+```yaml
+tracks: TrackSchema[]
+```
+
+### GetArtistTracksResponseSchema
+
+```yaml
+tracks: TrackSchema[]
+```
+
+### GetPlaylistTracksResponseSchema
+
+```yaml
+tracks: PlaylistTrackSchema[]
+```
+
+### GetPodcastEpisodesResponseSchema
+
+```yaml
+episodes: PodcastEpisodeSchema[]
+```
+
+## WebSocket Schemas
+
+### GetInfoResponseSchema
+
+```yaml
+available: bool
+can_group_with: str[] # List of player IDs that can be natively synced using `media_player.join`
+connection:
+ configuration_url: str # URL to configure the player from Music Assistant
+ url: str # IP Address for player
+entries: # Config Entry IDs for the player's HA integrations
+ music_assistant: str
+ mass_queue: str
+features: str[] # List of features which the player supports
+manufacturer: str
+model: str
+name: str
+player_id: str # ID of player in Music Assistant
+provider: str
+queue_id: str # ID for queue currently playing on player
+server:
+ connection:
+ url: str # URL to access Music Assistant integration
+ websocket: str # WebSocket address to interact with player
+synced_to: str| None # Player(s) which are currently synced/grouped/joined with the player
+type: str
+```
+
+### GetUser
+*See [music_assistant_models.auth.User](https://github.com/music-assistant/models/blob/0f2ad708ab26d2cc2ae008872afc00cd4a795380/music_assistant_models/auth.py#L29)*
+
+
+### DownloadAndEncodeImageResponseSchema
+
+```yaml
+
+```
+
+## Sub-schemas
+
+### QueueItemSchema
+
+```yaml
+queue_item_id: str
+media_title: str
+media_album_name: str
+media_artist: str
+media_content_id: str
+media_image: str
+favorite: bool
+```
+
+### TrackSchema
+
+```yaml
+media_title: str
+media_content_id: str
+duration?: int
+media_image: str
+local_image_encoded?: str
+favorite: bool
+media_album_name: str
+media_artist: str
+```
+
+### PlaylistTrackSchema
+
+```yaml
+media_title: str
+media_content_id: str
+duration?: int
+media_image: str
+local_image_encoded?: str
+favorite: bool
+media_album_name: str
+media_artist: str
+position: int
+```
+
+### PodcastEpisodeSchema
+
+```yaml
+media_title: str
+media_content_id: str
+duration?: int
+media_image: str
+local_image_encoded?: str
+favorite: bool
+media_album_name: str
+media_artist: str
+release_date: str
+```
+
+*Note: release date is a string representation of a date, formatted as `YYYY-MM-DDTHH:MM:SS`.*
+
+### RecommendationFolder
+
+*See [music_assistant_models.media_items.RecommendationFolder](https://github.com/music-assistant/models/blob/0f2ad708ab26d2cc2ae008872afc00cd4a795380/music_assistant_models/media_items/media_item.py#L389)*