mirror of
https://github.com/home-assistant/core.git
synced 2026-10-11 00:41:55 -04:00
Match track titles in a Squeezebox search inside a genre (#183423)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
75cc467a6a
commit
460d0e7f50
@@ -47,6 +47,7 @@ MEDIA_TYPE_TO_SQUEEZEBOX: dict[str | MediaType, str] = {
|
||||
"new music": "new music",
|
||||
"album artists": "album artists",
|
||||
"artist tracks": "titles",
|
||||
"genre tracks": "titles",
|
||||
MediaType.ALBUM: "album",
|
||||
MediaType.ARTIST: "artist",
|
||||
MediaType.TRACK: "title",
|
||||
@@ -63,6 +64,7 @@ SQUEEZEBOX_ID_BY_TYPE: dict[str | MediaType, str] = {
|
||||
MediaType.ARTIST: "artist_id",
|
||||
"artists": "artist_id",
|
||||
"artist tracks": "artist_id",
|
||||
"genre tracks": "genre_id",
|
||||
MediaType.TRACK: "track_id",
|
||||
"tracks": "track_id",
|
||||
MediaType.PLAYLIST: "playlist_id",
|
||||
@@ -90,6 +92,7 @@ CONTENT_TYPE_MEDIA_CLASS: dict[str | MediaType, dict[str, MediaClass | str]] = {
|
||||
"new music": {"item": MediaClass.DIRECTORY, "children": MediaClass.ALBUM},
|
||||
"album artists": {"item": MediaClass.DIRECTORY, "children": MediaClass.ARTIST},
|
||||
"artist tracks": {"item": MediaClass.DIRECTORY, "children": MediaClass.TRACK},
|
||||
"genre tracks": {"item": MediaClass.DIRECTORY, "children": MediaClass.TRACK},
|
||||
MediaType.ALBUM: {"item": MediaClass.ALBUM, "children": MediaClass.TRACK},
|
||||
MediaType.ARTIST: {"item": MediaClass.ARTIST, "children": MediaClass.ALBUM},
|
||||
MediaType.TRACK: {"item": MediaClass.TRACK, "children": ""},
|
||||
@@ -117,6 +120,7 @@ CONTENT_TYPE_TO_CHILD_TYPE: dict[
|
||||
"new music": MediaType.ALBUM,
|
||||
"album artists": MediaType.ARTIST,
|
||||
"artist tracks": MediaType.TRACK,
|
||||
"genre tracks": MediaType.TRACK,
|
||||
MediaType.APPS: MediaType.APP,
|
||||
MediaType.APP: MediaType.TRACK,
|
||||
"favorite": None,
|
||||
|
||||
@@ -665,7 +665,8 @@ class SqueezeBoxMediaPlayerEntity(SqueezeboxEntity, MediaPlayerEntity):
|
||||
_valid_type_list = [
|
||||
key
|
||||
for key in self._browse_data.content_type_media_class
|
||||
if key not in ["apps", "app", "radios", "radio", "artist tracks"]
|
||||
if key
|
||||
not in ["apps", "app", "radios", "radio", "artist tracks", "genre tracks"]
|
||||
]
|
||||
|
||||
_media_content_type_list = (
|
||||
@@ -687,9 +688,13 @@ class SqueezeBoxMediaPlayerEntity(SqueezeboxEntity, MediaPlayerEntity):
|
||||
},
|
||||
)
|
||||
|
||||
if query.media_content_id and MediaType.ARTIST in _media_content_type_list:
|
||||
# LMS matches the albums of an artist by album title only
|
||||
_media_content_type_list.append("artist tracks")
|
||||
if query.media_content_id:
|
||||
# Without full text search, LMS matches only album titles inside an
|
||||
# artist and only artist names inside a genre
|
||||
if MediaType.ARTIST in _media_content_type_list:
|
||||
_media_content_type_list.append("artist tracks")
|
||||
if MediaType.GENRE in _media_content_type_list:
|
||||
_media_content_type_list.append("genre tracks")
|
||||
|
||||
search_response_list: list[BrowseMedia] = []
|
||||
|
||||
|
||||
@@ -260,12 +260,35 @@ async def test_async_search_media(
|
||||
assert category_level[0]["title"] == "Fake Item 1"
|
||||
|
||||
|
||||
async def test_async_search_media_in_artist(
|
||||
@pytest.mark.parametrize(
|
||||
("media_content_type", "category", "id_key", "first_item"),
|
||||
[
|
||||
pytest.param(
|
||||
MediaType.ARTIST,
|
||||
"artist",
|
||||
"artist_id",
|
||||
("Love Album", MediaClass.ALBUM, MediaType.ALBUM, "1", True),
|
||||
id="artist",
|
||||
),
|
||||
pytest.param(
|
||||
MediaType.GENRE,
|
||||
"genre",
|
||||
"genre_id",
|
||||
("Love Band", MediaClass.ARTIST, MediaType.ARTIST, "1", True),
|
||||
id="genre",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_async_search_media_in_container(
|
||||
hass: HomeAssistant,
|
||||
lms: MagicMock,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
media_content_type: MediaType,
|
||||
category: str,
|
||||
id_key: str,
|
||||
first_item: tuple[str, MediaClass, MediaType, str, bool],
|
||||
) -> None:
|
||||
"""Test a search inside an artist returns matching albums and tracks."""
|
||||
"""Test a search inside an artist or genre also matches track titles."""
|
||||
|
||||
async def mock_browse(
|
||||
category: str,
|
||||
@@ -274,10 +297,9 @@ async def test_async_search_media_in_artist(
|
||||
search_query: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
items = {
|
||||
"artist": [{"id": "1", "title": "Love Album"}],
|
||||
"titles": [{"id": "2", "title": "Love Song"}],
|
||||
}
|
||||
return {"title": category, "items": items[category]}
|
||||
}.get(category, [{"id": "1", "title": first_item[0]}])
|
||||
return {"title": category, "items": items}
|
||||
|
||||
player = (await lms.async_get_players())[0]
|
||||
player.async_browse.side_effect = mock_browse
|
||||
@@ -289,7 +311,7 @@ async def test_async_search_media_in_artist(
|
||||
"type": "media_player/search_media",
|
||||
"entity_id": "media_player.test_player",
|
||||
"media_content_id": "42",
|
||||
"media_content_type": MediaType.ARTIST,
|
||||
"media_content_type": media_content_type,
|
||||
"search_query": "love",
|
||||
}
|
||||
)
|
||||
@@ -305,12 +327,12 @@ async def test_async_search_media_in_artist(
|
||||
)
|
||||
for item in response["result"]["result"]
|
||||
] == [
|
||||
("Love Album", MediaClass.ALBUM, MediaType.ALBUM, "1", True),
|
||||
first_item,
|
||||
("Love Song", MediaClass.TRACK, MediaType.TRACK, "2", False),
|
||||
]
|
||||
assert player.async_browse.call_args_list == [
|
||||
call("artist", limit=ANY, browse_id=("artist_id", "42"), search_query="love"),
|
||||
call("titles", limit=ANY, browse_id=("artist_id", "42"), search_query="love"),
|
||||
call(category, limit=ANY, browse_id=(id_key, "42"), search_query="love"),
|
||||
call("titles", limit=ANY, browse_id=(id_key, "42"), search_query="love"),
|
||||
]
|
||||
|
||||
|
||||
@@ -345,7 +367,8 @@ async def test_async_search_media_invalid_filter(
|
||||
"media_content_type",
|
||||
[
|
||||
pytest.param("Fake Type", id="unknown"),
|
||||
pytest.param("artist tracks", id="internal"),
|
||||
pytest.param("artist tracks", id="internal_artist"),
|
||||
pytest.param("genre tracks", id="internal_genre"),
|
||||
],
|
||||
)
|
||||
async def test_async_search_media_invalid_type(
|
||||
@@ -375,6 +398,7 @@ async def test_async_search_media_invalid_type(
|
||||
err_message = "If specified, Media content type must be one of"
|
||||
assert err_message in response["error"]["message"]
|
||||
assert "artist tracks" not in response["error"]["message"]
|
||||
assert "genre tracks" not in response["error"]["message"]
|
||||
|
||||
|
||||
async def test_async_search_media_not_found(
|
||||
|
||||
Reference in New Issue
Block a user