Fix Sonos album artwork performance (#116391)

This commit is contained in:
Pete Sage 2024-05-24 04:42:45 -04:00 committed by GitHub
parent 5c263b039e
commit 1ad2e4951d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 344 additions and 9 deletions

View File

@ -53,14 +53,16 @@ def get_thumbnail_url_full(
media_content_type: str,
media_content_id: str,
media_image_id: str | None = None,
item: MusicServiceItem | None = None,
) -> str | None:
"""Get thumbnail URL."""
if is_internal:
item = get_media(
media.library,
media_content_id,
media_content_type,
)
if not item:
item = get_media(
media.library,
media_content_id,
media_content_type,
)
return urllib.parse.unquote(getattr(item, "album_art_uri", ""))
return urllib.parse.unquote(
@ -255,7 +257,7 @@ def item_payload(item: DidlObject, get_thumbnail_url=None) -> BrowseMedia:
content_id = get_content_id(item)
thumbnail = None
if getattr(item, "album_art_uri", None):
thumbnail = get_thumbnail_url(media_class, content_id)
thumbnail = get_thumbnail_url(media_class, content_id, item=item)
return BrowseMedia(
title=item.title,

View File

@ -316,12 +316,35 @@ def sonos_favorites_fixture() -> SearchResult:
class MockMusicServiceItem:
"""Mocks a Soco MusicServiceItem."""
def __init__(self, title: str, item_id: str, parent_id: str, item_class: str):
def __init__(
self,
title: str,
item_id: str,
parent_id: str,
item_class: str,
album_art_uri: None | str = None,
):
"""Initialize the mock item."""
self.title = title
self.item_id = item_id
self.item_class = item_class
self.parent_id = parent_id
self.album_art_uri: None | str = album_art_uri
def list_from_json_fixture(file_name: str) -> list[MockMusicServiceItem]:
"""Create a list of music service items from a json fixture file."""
item_list = load_json_value_fixture(file_name, "sonos")
return [
MockMusicServiceItem(
item.get("title"),
item.get("item_id"),
item.get("parent_id"),
item.get("item_class"),
item.get("album_art_uri"),
)
for item in item_list
]
def mock_browse_by_idstring(
@ -398,6 +421,10 @@ def mock_browse_by_idstring(
"object.container.album.musicAlbum",
),
]
if search_type == "tracks":
return list_from_json_fixture("music_library_tracks.json")
if search_type == "albums" and idstring == "A:ALBUM":
return list_from_json_fixture("music_library_albums.json")
return []
@ -416,13 +443,23 @@ def mock_get_music_library_information(
]
@pytest.fixture(name="music_library_browse_categories")
def music_library_browse_categories() -> list[MockMusicServiceItem]:
"""Create fixture for top-level music library categories."""
return list_from_json_fixture("music_library_categories.json")
@pytest.fixture(name="music_library")
def music_library_fixture(sonos_favorites: SearchResult) -> Mock:
def music_library_fixture(
sonos_favorites: SearchResult,
music_library_browse_categories: list[MockMusicServiceItem],
) -> Mock:
"""Create music_library fixture."""
music_library = MagicMock()
music_library.get_sonos_favorites.return_value = sonos_favorites
music_library.browse_by_idstring = mock_browse_by_idstring
music_library.browse_by_idstring = Mock(side_effect=mock_browse_by_idstring)
music_library.get_music_library_information = mock_get_music_library_information
music_library.browse = Mock(return_value=music_library_browse_categories)
return music_library

View File

@ -0,0 +1,23 @@
[
{
"title": "A Hard Day's Night",
"item_id": "A:ALBUM/A%20Hard%20Day's%20Night",
"parent_id": "A:ALBUM",
"item_class": "object.container.album.musicAlbum",
"album_art_uri": "http://192.168.42.2:1400/getaa?u=x-file-cifs%3a%2f%2f192.168.42.100%2fmusic%2fThe%2520Beatles%2fA%2520Hard%2520Day's%2520Night%2f01%2520A%2520Hard%2520Day's%2520Night%25201.m4a&v=53"
},
{
"title": "Abbey Road",
"item_id": "A:ALBUM/Abbey%20Road",
"parent_id": "A:ALBUM",
"item_class": "object.container.album.musicAlbum",
"album_art_uri": "http://192.168.42.2:1400/getaa?u=x-file-cifs%3a%2f%2f192.168.42.100%2fmusic%2fThe%2520Beatles%2fAbbeyA%2520Road%2f01%2520Come%2520Together.m4a&v=53"
},
{
"title": "Between Good And Evil",
"item_id": "A:ALBUM/Between%20Good%20And%20Evil",
"parent_id": "A:ALBUM",
"item_class": "object.container.album.musicAlbum",
"album_art_uri": "http://192.168.42.2:1400/getaa?u=x-file-cifs%3a%2f%2f192.168.42.100%2fmusic%2fSantana%2fA%2520Between%2520Good%2520And%2520Evil%2f02%2520A%2520Persuasion.m4a&v=53"
}
]

View File

@ -0,0 +1,44 @@
[
{
"title": "Contributing Artists",
"item_id": "A:ARTIST",
"parent_id": "A:",
"item_class": "object.container"
},
{
"title": "Artists",
"item_id": "A:ALBUMARTIST",
"parent_id": "A:",
"item_class": "object.container"
},
{
"title": "Albums",
"item_id": "A:ALBUM",
"parent_id": "A:",
"item_class": "object.container"
},
{
"title": "Genres",
"item_id": "A:GENRE",
"parent_id": "A:",
"item_class": "object.container"
},
{
"title": "Composers",
"item_id": "A:COMPOSER",
"parent_id": "A:",
"item_class": "object.container"
},
{
"title": "Tracks",
"item_id": "A:TRACKS",
"parent_id": "A:",
"item_class": "object.container.playlistContainer"
},
{
"title": "Playlists",
"item_id": "A:PLAYLISTS",
"parent_id": "A:",
"item_class": "object.container"
}
]

View File

@ -0,0 +1,14 @@
[
{
"title": "A Hard Day's Night",
"item_id": "S://192.168.42.100/music/iTunes/The%20Beatles/A%20Hard%20Day%2fs%20Night/A%20Hard%20Day%2fs%20Night.mp3",
"parent_id": "A:ALBUMARTIST/Beatles/A%20Hard%20Day's%20Night",
"item_class": "object.container.album.musicTrack"
},
{
"title": "I Should Have Known Better",
"item_id": "S://192.168.42.100/music/iTunes/The%20Beatles/A%20Hard%20Day%2fs%I%20Should%20Have%20Known%20Better.mp3",
"parent_id": "A:ALBUMARTIST/Beatles/A%20Hard%20Day's%20Night",
"item_class": "object.container.album.musicTrack"
}
]

View File

@ -0,0 +1,133 @@
# serializer version: 1
# name: test_browse_media_library
list([
dict({
'can_expand': True,
'can_play': False,
'children_media_class': None,
'media_class': 'contributing_artist',
'media_content_id': 'A:ARTIST',
'media_content_type': 'contributing_artist',
'thumbnail': None,
'title': 'Contributing Artists',
}),
dict({
'can_expand': True,
'can_play': False,
'children_media_class': None,
'media_class': 'artist',
'media_content_id': 'A:ALBUMARTIST',
'media_content_type': 'artist',
'thumbnail': None,
'title': 'Artists',
}),
dict({
'can_expand': True,
'can_play': False,
'children_media_class': None,
'media_class': 'album',
'media_content_id': 'A:ALBUM',
'media_content_type': 'album',
'thumbnail': None,
'title': 'Albums',
}),
dict({
'can_expand': True,
'can_play': False,
'children_media_class': None,
'media_class': 'genre',
'media_content_id': 'A:GENRE',
'media_content_type': 'genre',
'thumbnail': None,
'title': 'Genres',
}),
dict({
'can_expand': True,
'can_play': False,
'children_media_class': None,
'media_class': 'composer',
'media_content_id': 'A:COMPOSER',
'media_content_type': 'composer',
'thumbnail': None,
'title': 'Composers',
}),
dict({
'can_expand': True,
'can_play': True,
'children_media_class': None,
'media_class': 'track',
'media_content_id': 'A:TRACKS',
'media_content_type': 'track',
'thumbnail': None,
'title': 'Tracks',
}),
dict({
'can_expand': True,
'can_play': False,
'children_media_class': None,
'media_class': 'playlist',
'media_content_id': 'A:PLAYLISTS',
'media_content_type': 'playlist',
'thumbnail': None,
'title': 'Playlists',
}),
])
# ---
# name: test_browse_media_library_albums
list([
dict({
'can_expand': True,
'can_play': True,
'children_media_class': None,
'media_class': 'album',
'media_content_id': "A:ALBUM/A%20Hard%20Day's%20Night",
'media_content_type': 'album',
'thumbnail': "http://192.168.42.2:1400/getaa?u=x-file-cifs://192.168.42.100/music/The%20Beatles/A%20Hard%20Day's%20Night/01%20A%20Hard%20Day's%20Night%201.m4a&v=53",
'title': "A Hard Day's Night",
}),
dict({
'can_expand': True,
'can_play': True,
'children_media_class': None,
'media_class': 'album',
'media_content_id': 'A:ALBUM/Abbey%20Road',
'media_content_type': 'album',
'thumbnail': 'http://192.168.42.2:1400/getaa?u=x-file-cifs://192.168.42.100/music/The%20Beatles/AbbeyA%20Road/01%20Come%20Together.m4a&v=53',
'title': 'Abbey Road',
}),
dict({
'can_expand': True,
'can_play': True,
'children_media_class': None,
'media_class': 'album',
'media_content_id': 'A:ALBUM/Between%20Good%20And%20Evil',
'media_content_type': 'album',
'thumbnail': 'http://192.168.42.2:1400/getaa?u=x-file-cifs://192.168.42.100/music/Santana/A%20Between%20Good%20And%20Evil/02%20A%20Persuasion.m4a&v=53',
'title': 'Between Good And Evil',
}),
])
# ---
# name: test_browse_media_root
list([
dict({
'can_expand': True,
'can_play': False,
'children_media_class': None,
'media_class': 'directory',
'media_content_id': '',
'media_content_type': 'favorites',
'thumbnail': 'https://brands.home-assistant.io/_/sonos/logo.png',
'title': 'Favorites',
}),
dict({
'can_expand': True,
'can_play': False,
'children_media_class': None,
'media_class': 'directory',
'media_content_id': '',
'media_content_type': 'library',
'thumbnail': 'https://brands.home-assistant.io/_/sonos/logo.png',
'title': 'Music Library',
}),
])
# ---

View File

@ -2,6 +2,8 @@
from functools import partial
from syrupy import SnapshotAssertion
from homeassistant.components.media_player.browse_media import BrowseMedia
from homeassistant.components.media_player.const import MediaClass, MediaType
from homeassistant.components.sonos.media_browser import (
@ -12,6 +14,8 @@ from homeassistant.core import HomeAssistant
from .conftest import SoCoMockFactory
from tests.typing import WebSocketGenerator
class MockMusicServiceItem:
"""Mocks a Soco MusicServiceItem."""
@ -95,3 +99,81 @@ async def test_build_item_response(
browse_item.children[1].media_content_id
== "x-file-cifs://192.168.42.10/music/The%20Beatles/Abbey%20Road/03%20Something.mp3"
)
async def test_browse_media_root(
hass: HomeAssistant,
soco_factory: SoCoMockFactory,
async_autosetup_sonos,
soco,
discover,
hass_ws_client: WebSocketGenerator,
snapshot: SnapshotAssertion,
) -> None:
"""Test the async_browse_media method."""
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "media_player/browse_media",
"entity_id": "media_player.zone_a",
}
)
response = await client.receive_json()
assert response["success"]
assert response["result"]["children"] == snapshot
async def test_browse_media_library(
hass: HomeAssistant,
soco_factory: SoCoMockFactory,
async_autosetup_sonos,
soco,
discover,
hass_ws_client: WebSocketGenerator,
snapshot: SnapshotAssertion,
) -> None:
"""Test the async_browse_media method."""
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "media_player/browse_media",
"entity_id": "media_player.zone_a",
"media_content_id": "",
"media_content_type": "library",
}
)
response = await client.receive_json()
assert response["success"]
assert response["result"]["children"] == snapshot
async def test_browse_media_library_albums(
hass: HomeAssistant,
soco_factory: SoCoMockFactory,
async_autosetup_sonos,
soco,
discover,
hass_ws_client: WebSocketGenerator,
snapshot: SnapshotAssertion,
) -> None:
"""Test the async_browse_media method."""
soco_mock = soco_factory.mock_list.get("192.168.42.2")
client = await hass_ws_client()
await client.send_json(
{
"id": 1,
"type": "media_player/browse_media",
"entity_id": "media_player.zone_a",
"media_content_id": "A:ALBUM",
"media_content_type": "album",
}
)
response = await client.receive_json()
assert response["success"]
assert response["result"]["children"] == snapshot
assert soco_mock.music_library.browse_by_idstring.call_count == 1