Add new mediatypes to Music Assistant integration (#139338)

* Bump Music Assistant client to 1.1.0

* Add some casts to help mypy

* Add handling of the new media types in Music Assistant

* mypy cleanup

* lint

* update snapshot

* Adjust tests

---------

Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Marcel van der Veldt 2025-02-28 14:17:02 +01:00 committed by GitHub
parent d6f9040baf
commit b79c6e772a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 1087 additions and 5 deletions

View File

@ -23,6 +23,7 @@ from .const import (
ATTR_ALBUM_TYPE,
ATTR_ALBUMS,
ATTR_ARTISTS,
ATTR_AUDIOBOOKS,
ATTR_CONFIG_ENTRY_ID,
ATTR_FAVORITE,
ATTR_ITEMS,
@ -32,6 +33,7 @@ from .const import (
ATTR_OFFSET,
ATTR_ORDER_BY,
ATTR_PLAYLISTS,
ATTR_PODCASTS,
ATTR_RADIO,
ATTR_SEARCH,
ATTR_SEARCH_ALBUM,
@ -48,7 +50,15 @@ from .schemas import (
if TYPE_CHECKING:
from music_assistant_client import MusicAssistantClient
from music_assistant_models.media_items import Album, Artist, Playlist, Radio, Track
from music_assistant_models.media_items import (
Album,
Artist,
Audiobook,
Playlist,
Podcast,
Radio,
Track,
)
from . import MusicAssistantConfigEntry
@ -155,6 +165,14 @@ async def handle_search(call: ServiceCall) -> ServiceResponse:
media_item_dict_from_mass_item(mass, item)
for item in search_results.radio
],
ATTR_AUDIOBOOKS: [
media_item_dict_from_mass_item(mass, item)
for item in search_results.audiobooks
],
ATTR_PODCASTS: [
media_item_dict_from_mass_item(mass, item)
for item in search_results.podcasts
],
}
)
return response
@ -175,7 +193,13 @@ async def handle_get_library(call: ServiceCall) -> ServiceResponse:
"order_by": order_by,
}
library_result: (
list[Album] | list[Artist] | list[Track] | list[Radio] | list[Playlist]
list[Album]
| list[Artist]
| list[Track]
| list[Radio]
| list[Playlist]
| list[Audiobook]
| list[Podcast]
)
if media_type == MediaType.ALBUM:
library_result = await mass.music.get_library_albums(
@ -199,6 +223,14 @@ async def handle_get_library(call: ServiceCall) -> ServiceResponse:
library_result = await mass.music.get_library_playlists(
**base_params,
)
elif media_type == MediaType.AUDIOBOOK:
library_result = await mass.music.get_library_audiobooks(
**base_params,
)
elif media_type == MediaType.PODCAST:
library_result = await mass.music.get_library_podcasts(
**base_params,
)
else:
raise ServiceValidationError(f"Unsupported media type {media_type}")

View File

@ -34,6 +34,8 @@ ATTR_ARTISTS = "artists"
ATTR_ALBUMS = "albums"
ATTR_TRACKS = "tracks"
ATTR_PLAYLISTS = "playlists"
ATTR_AUDIOBOOKS = "audiobooks"
ATTR_PODCASTS = "podcasts"
ATTR_RADIO = "radio"
ATTR_ITEMS = "items"
ATTR_RADIO_MODE = "radio_mode"

View File

@ -15,6 +15,7 @@ from .const import (
ATTR_ALBUM,
ATTR_ALBUMS,
ATTR_ARTISTS,
ATTR_AUDIOBOOKS,
ATTR_BIT_DEPTH,
ATTR_CONTENT_TYPE,
ATTR_CURRENT_INDEX,
@ -31,6 +32,7 @@ from .const import (
ATTR_OFFSET,
ATTR_ORDER_BY,
ATTR_PLAYLISTS,
ATTR_PODCASTS,
ATTR_PROVIDER,
ATTR_QUEUE_ID,
ATTR_QUEUE_ITEM_ID,
@ -101,6 +103,12 @@ SEARCH_RESULT_SCHEMA = vol.Schema(
vol.Required(ATTR_RADIO): vol.All(
cv.ensure_list, [vol.Schema(MEDIA_ITEM_SCHEMA)]
),
vol.Required(ATTR_AUDIOBOOKS): vol.All(
cv.ensure_list, [vol.Schema(MEDIA_ITEM_SCHEMA)]
),
vol.Required(ATTR_PODCASTS): vol.All(
cv.ensure_list, [vol.Schema(MEDIA_ITEM_SCHEMA)]
),
},
)

View File

@ -21,7 +21,10 @@ play_media:
options:
- artist
- album
- audiobook
- folder
- playlist
- podcast
- track
- radio
artist:
@ -118,7 +121,9 @@ search:
options:
- artist
- album
- audiobook
- playlist
- podcast
- track
- radio
artist:
@ -160,7 +165,9 @@ get_library:
options:
- artist
- album
- audiobook
- playlist
- podcast
- track
- radio
favorite:

View File

@ -195,8 +195,11 @@
"options": {
"artist": "Artist",
"album": "Album",
"audiobook": "Audiobook",
"folder": "Folder",
"track": "Track",
"playlist": "Playlist",
"podcast": "Podcast",
"radio": "Radio"
}
},

View File

@ -8,7 +8,15 @@ from unittest.mock import AsyncMock, MagicMock
from music_assistant_models.api import MassEvent
from music_assistant_models.enums import EventType
from music_assistant_models.media_items import Album, Artist, Playlist, Radio, Track
from music_assistant_models.media_items import (
Album,
Artist,
Audiobook,
Playlist,
Podcast,
Radio,
Track,
)
from music_assistant_models.player import Player
from music_assistant_models.player_queue import PlayerQueue
from syrupy import SnapshotAssertion
@ -62,6 +70,10 @@ async def setup_integration_from_fixtures(
music.get_playlist_tracks = AsyncMock(return_value=library_playlist_tracks)
library_radios = create_library_radios_from_fixture()
music.get_library_radios = AsyncMock(return_value=library_radios)
library_audiobooks = create_library_audiobooks_from_fixture()
music.get_library_audiobooks = AsyncMock(return_value=library_audiobooks)
library_podcasts = create_library_podcasts_from_fixture()
music.get_library_podcasts = AsyncMock(return_value=library_podcasts)
music.get_item_by_uri = AsyncMock()
config_entry.add_to_hass(hass)
@ -132,6 +144,18 @@ def create_library_radios_from_fixture() -> list[Radio]:
return [Radio.from_dict(radio_data) for radio_data in fixture_data]
def create_library_audiobooks_from_fixture() -> list[Audiobook]:
"""Create MA Audiobooks from fixture."""
fixture_data = load_and_parse_fixture("library_audiobooks")
return [Audiobook.from_dict(radio_data) for radio_data in fixture_data]
def create_library_podcasts_from_fixture() -> list[Podcast]:
"""Create MA Podcasts from fixture."""
fixture_data = load_and_parse_fixture("library_podcasts")
return [Podcast.from_dict(radio_data) for radio_data in fixture_data]
async def trigger_subscription_callback(
hass: HomeAssistant,
client: MagicMock,

View File

@ -0,0 +1,489 @@
{
"library_audiobooks": [
{
"item_id": "1",
"provider": "library",
"name": "Test Audiobook",
"version": "",
"sort_name": "test audiobook",
"uri": "library://audiobook/1",
"external_ids": [],
"is_playable": true,
"media_type": "audiobook",
"provider_mappings": [
{
"item_id": "test-audiobook.mp3",
"provider_domain": "filesystem_smb",
"provider_instance": "filesystem_smb--7Kf8QySu",
"available": true,
"audio_format": {
"content_type": "mp3",
"codec_type": "?",
"sample_rate": 48000,
"bit_depth": 16,
"channels": 1,
"output_format_str": "mp3",
"bit_rate": 90304
},
"url": null,
"details": "1738502411"
}
],
"metadata": {
"description": "Cover (front)",
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "test-audiobook.mp3",
"provider": "filesystem_smb--7Kf8QySu",
"remotely_accessible": false
}
],
"genres": [],
"mood": null,
"style": null,
"copyright": null,
"lyrics": "",
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": [],
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": null,
"authors": ["TestWriter"],
"narrators": [],
"duration": 9,
"fully_played": true,
"resume_position_ms": 9000
},
{
"item_id": "11",
"provider": "library",
"name": "Test Audiobook 0",
"version": "",
"sort_name": "test audiobook 0",
"uri": "library://audiobook/11",
"external_ids": [],
"is_playable": true,
"media_type": "audiobook",
"provider_mappings": [
{
"item_id": "0",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": "This is a description for Test Audiobook",
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": [
{
"position": 1,
"name": "Chapter 1",
"start": 10.0,
"end": 20.0
},
{
"position": 2,
"name": "Chapter 2",
"start": 20.0,
"end": 40.0
},
{
"position": 2,
"name": "Chapter 3",
"start": 40.0,
"end": null
}
],
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"authors": ["AudioBook Author"],
"narrators": ["AudioBook Narrator"],
"duration": 60,
"fully_played": null,
"resume_position_ms": null
},
{
"item_id": "12",
"provider": "library",
"name": "Test Audiobook 1",
"version": "",
"sort_name": "test audiobook 1",
"uri": "library://audiobook/12",
"external_ids": [],
"is_playable": true,
"media_type": "audiobook",
"provider_mappings": [
{
"item_id": "1",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": "This is a description for Test Audiobook",
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": [
{
"position": 1,
"name": "Chapter 1",
"start": 10.0,
"end": 20.0
},
{
"position": 2,
"name": "Chapter 2",
"start": 20.0,
"end": 40.0
},
{
"position": 2,
"name": "Chapter 3",
"start": 40.0,
"end": null
}
],
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"authors": ["AudioBook Author"],
"narrators": ["AudioBook Narrator"],
"duration": 60,
"fully_played": null,
"resume_position_ms": null
},
{
"item_id": "13",
"provider": "library",
"name": "Test Audiobook 2",
"version": "",
"sort_name": "test audiobook 2",
"uri": "library://audiobook/13",
"external_ids": [],
"is_playable": true,
"media_type": "audiobook",
"provider_mappings": [
{
"item_id": "2",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": "This is a description for Test Audiobook",
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": [
{
"position": 1,
"name": "Chapter 1",
"start": 10.0,
"end": 20.0
},
{
"position": 2,
"name": "Chapter 2",
"start": 20.0,
"end": 40.0
},
{
"position": 2,
"name": "Chapter 3",
"start": 40.0,
"end": null
}
],
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"authors": ["AudioBook Author"],
"narrators": ["AudioBook Narrator"],
"duration": 60,
"fully_played": null,
"resume_position_ms": null
},
{
"item_id": "14",
"provider": "library",
"name": "Test Audiobook 3",
"version": "",
"sort_name": "test audiobook 3",
"uri": "library://audiobook/14",
"external_ids": [],
"is_playable": true,
"media_type": "audiobook",
"provider_mappings": [
{
"item_id": "3",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": "This is a description for Test Audiobook",
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": [
{
"position": 1,
"name": "Chapter 1",
"start": 10.0,
"end": 20.0
},
{
"position": 2,
"name": "Chapter 2",
"start": 20.0,
"end": 40.0
},
{
"position": 2,
"name": "Chapter 3",
"start": 40.0,
"end": null
}
],
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"authors": ["AudioBook Author"],
"narrators": ["AudioBook Narrator"],
"duration": 60,
"fully_played": null,
"resume_position_ms": null
},
{
"item_id": "15",
"provider": "library",
"name": "Test Audiobook 4",
"version": "",
"sort_name": "test audiobook 4",
"uri": "library://audiobook/15",
"external_ids": [],
"is_playable": true,
"media_type": "audiobook",
"provider_mappings": [
{
"item_id": "4",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": "This is a description for Test Audiobook",
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": [
{
"position": 1,
"name": "Chapter 1",
"start": 10.0,
"end": 20.0
},
{
"position": 2,
"name": "Chapter 2",
"start": 20.0,
"end": 40.0
},
{
"position": 2,
"name": "Chapter 3",
"start": 40.0,
"end": null
}
],
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"authors": ["AudioBook Author"],
"narrators": ["AudioBook Narrator"],
"duration": 60,
"fully_played": null,
"resume_position_ms": null
}
]
}

View File

@ -0,0 +1,309 @@
{
"library_podcasts": [
{
"item_id": "6",
"provider": "library",
"name": "Test Podcast 0",
"version": "",
"sort_name": "test podcast 0",
"uri": "library://podcast/6",
"external_ids": [],
"is_playable": true,
"media_type": "podcast",
"provider_mappings": [
{
"item_id": "0",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": null,
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": null,
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"total_episodes": null
},
{
"item_id": "7",
"provider": "library",
"name": "Test Podcast 1",
"version": "",
"sort_name": "test podcast 1",
"uri": "library://podcast/7",
"external_ids": [],
"is_playable": true,
"media_type": "podcast",
"provider_mappings": [
{
"item_id": "1",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": null,
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": null,
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"total_episodes": null
},
{
"item_id": "8",
"provider": "library",
"name": "Test Podcast 2",
"version": "",
"sort_name": "test podcast 2",
"uri": "library://podcast/8",
"external_ids": [],
"is_playable": true,
"media_type": "podcast",
"provider_mappings": [
{
"item_id": "2",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": null,
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": null,
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"total_episodes": null
},
{
"item_id": "9",
"provider": "library",
"name": "Test Podcast 3",
"version": "",
"sort_name": "test podcast 3",
"uri": "library://podcast/9",
"external_ids": [],
"is_playable": true,
"media_type": "podcast",
"provider_mappings": [
{
"item_id": "3",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": null,
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": null,
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"total_episodes": null
},
{
"item_id": "10",
"provider": "library",
"name": "Test Podcast 4",
"version": "",
"sort_name": "test podcast 4",
"uri": "library://podcast/10",
"external_ids": [],
"is_playable": true,
"media_type": "podcast",
"provider_mappings": [
{
"item_id": "4",
"provider_domain": "test",
"provider_instance": "test",
"available": true,
"audio_format": {
"content_type": "?",
"codec_type": "?",
"sample_rate": 44100,
"bit_depth": 16,
"channels": 2,
"output_format_str": "?",
"bit_rate": 0
},
"url": null,
"details": null
}
],
"metadata": {
"description": null,
"review": null,
"explicit": null,
"images": [
{
"type": "thumb",
"path": "logo.png",
"provider": "builtin",
"remotely_accessible": false
}
],
"genres": null,
"mood": null,
"style": null,
"copyright": null,
"lyrics": null,
"label": null,
"links": null,
"performers": null,
"preview": null,
"popularity": null,
"release_date": null,
"languages": null,
"chapters": null,
"last_refresh": null
},
"favorite": false,
"position": null,
"publisher": "Test Publisher",
"total_episodes": null
}
]
}

View File

@ -1,5 +1,195 @@
# serializer version: 1
# name: test_get_library_action
# name: test_get_library_action[album]
dict({
'items': list([
dict({
'artists': list([
dict({
'image': None,
'media_type': <MediaType.ARTIST: 'artist'>,
'name': 'A Space Love Adventure',
'uri': 'library://artist/289',
'version': '',
}),
]),
'image': None,
'media_type': <MediaType.ALBUM: 'album'>,
'name': 'Synth Punk EP',
'uri': 'library://album/396',
'version': '',
}),
dict({
'artists': list([
dict({
'image': None,
'media_type': <MediaType.ARTIST: 'artist'>,
'name': 'Various Artists',
'uri': 'library://artist/96',
'version': '',
}),
]),
'image': None,
'media_type': <MediaType.ALBUM: 'album'>,
'name': 'Synthwave (The 80S Revival)',
'uri': 'library://album/95',
'version': 'The 80S Revival',
}),
]),
'limit': 25,
'media_type': <MediaType.ALBUM: 'album'>,
'offset': 0,
'order_by': 'name',
})
# ---
# name: test_get_library_action[artist]
dict({
'items': list([
dict({
'image': None,
'media_type': <MediaType.ARTIST: 'artist'>,
'name': 'W O L F C L U B',
'uri': 'library://artist/127',
'version': '',
}),
]),
'limit': 25,
'media_type': <MediaType.ARTIST: 'artist'>,
'offset': 0,
'order_by': 'name',
})
# ---
# name: test_get_library_action[audiobook]
dict({
'items': list([
dict({
'image': None,
'media_type': <MediaType.AUDIOBOOK: 'audiobook'>,
'name': 'Test Audiobook',
'uri': 'library://audiobook/1',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.AUDIOBOOK: 'audiobook'>,
'name': 'Test Audiobook 0',
'uri': 'library://audiobook/11',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.AUDIOBOOK: 'audiobook'>,
'name': 'Test Audiobook 1',
'uri': 'library://audiobook/12',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.AUDIOBOOK: 'audiobook'>,
'name': 'Test Audiobook 2',
'uri': 'library://audiobook/13',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.AUDIOBOOK: 'audiobook'>,
'name': 'Test Audiobook 3',
'uri': 'library://audiobook/14',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.AUDIOBOOK: 'audiobook'>,
'name': 'Test Audiobook 4',
'uri': 'library://audiobook/15',
'version': '',
}),
]),
'limit': 25,
'media_type': <MediaType.AUDIOBOOK: 'audiobook'>,
'offset': 0,
'order_by': 'name',
})
# ---
# name: test_get_library_action[playlist]
dict({
'items': list([
dict({
'image': None,
'media_type': <MediaType.PLAYLIST: 'playlist'>,
'name': '1970s Rock Hits',
'uri': 'library://playlist/40',
'version': '',
}),
]),
'limit': 25,
'media_type': <MediaType.PLAYLIST: 'playlist'>,
'offset': 0,
'order_by': 'name',
})
# ---
# name: test_get_library_action[podcast]
dict({
'items': list([
dict({
'image': None,
'media_type': <MediaType.PODCAST: 'podcast'>,
'name': 'Test Podcast 0',
'uri': 'library://podcast/6',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.PODCAST: 'podcast'>,
'name': 'Test Podcast 1',
'uri': 'library://podcast/7',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.PODCAST: 'podcast'>,
'name': 'Test Podcast 2',
'uri': 'library://podcast/8',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.PODCAST: 'podcast'>,
'name': 'Test Podcast 3',
'uri': 'library://podcast/9',
'version': '',
}),
dict({
'image': None,
'media_type': <MediaType.PODCAST: 'podcast'>,
'name': 'Test Podcast 4',
'uri': 'library://podcast/10',
'version': '',
}),
]),
'limit': 25,
'media_type': <MediaType.PODCAST: 'podcast'>,
'offset': 0,
'order_by': 'name',
})
# ---
# name: test_get_library_action[radio]
dict({
'items': list([
dict({
'image': None,
'media_type': <MediaType.RADIO: 'radio'>,
'name': 'fm4 | ORF | HQ',
'uri': 'library://radio/1',
'version': '',
}),
]),
'limit': 25,
'media_type': <MediaType.RADIO: 'radio'>,
'offset': 0,
'order_by': 'name',
})
# ---
# name: test_get_library_action[track]
dict({
'items': list([
dict({
@ -192,8 +382,12 @@
]),
'artists': list([
]),
'audiobooks': list([
]),
'playlists': list([
]),
'podcasts': list([
]),
'radio': list([
]),
'tracks': list([

View File

@ -3,6 +3,7 @@
from unittest.mock import AsyncMock, MagicMock
from music_assistant_models.media_items import SearchResults
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.music_assistant.actions import (
@ -47,9 +48,22 @@ async def test_search_action(
assert response == snapshot
@pytest.mark.parametrize(
"media_type",
[
"artist",
"album",
"track",
"playlist",
"audiobook",
"podcast",
"radio",
],
)
async def test_get_library_action(
hass: HomeAssistant,
music_assistant_client: MagicMock,
media_type: str,
snapshot: SnapshotAssertion,
) -> None:
"""Test music assistant get_library action."""
@ -60,7 +74,7 @@ async def test_get_library_action(
{
ATTR_CONFIG_ENTRY_ID: entry.entry_id,
ATTR_FAVORITE: False,
ATTR_MEDIA_TYPE: "track",
ATTR_MEDIA_TYPE: media_type,
},
blocking=True,
return_response=True,