Convert media player enqueue to an enum (#72406)
This commit is contained in:
parent
f33517ef2c
commit
6bf6a0f7bc
9 changed files with 119 additions and 36 deletions
|
@ -24,10 +24,7 @@ from homeassistant.components.media_player import (
|
|||
from homeassistant.components.media_player.browse_media import (
|
||||
async_process_play_media_url,
|
||||
)
|
||||
from homeassistant.components.media_player.const import (
|
||||
ATTR_MEDIA_ENQUEUE,
|
||||
MEDIA_TYPE_MUSIC,
|
||||
)
|
||||
from homeassistant.components.media_player.const import MEDIA_TYPE_MUSIC
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
CONF_HOST,
|
||||
|
@ -1023,11 +1020,7 @@ class BluesoundPlayer(MediaPlayerEntity):
|
|||
return await self.send_bluesound_command(f"Play?seek={float(position)}")
|
||||
|
||||
async def async_play_media(self, media_type, media_id, **kwargs):
|
||||
"""
|
||||
Send the play_media command to the media player.
|
||||
|
||||
If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the queue.
|
||||
"""
|
||||
"""Send the play_media command to the media player."""
|
||||
if self.is_grouped and not self.is_master:
|
||||
return
|
||||
|
||||
|
@ -1041,9 +1034,6 @@ class BluesoundPlayer(MediaPlayerEntity):
|
|||
|
||||
url = f"Play?url={media_id}"
|
||||
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE):
|
||||
return await self.send_bluesound_command(url)
|
||||
|
||||
return await self.send_bluesound_command(url)
|
||||
|
||||
async def async_volume_up(self):
|
||||
|
|
|
@ -12,6 +12,7 @@ from typing_extensions import ParamSpec
|
|||
|
||||
from homeassistant.components import media_source
|
||||
from homeassistant.components.media_player import (
|
||||
MediaPlayerEnqueue,
|
||||
MediaPlayerEntity,
|
||||
MediaPlayerEntityFeature,
|
||||
)
|
||||
|
@ -73,6 +74,14 @@ CONTROL_TO_SUPPORT = {
|
|||
heos_const.CONTROL_PLAY_NEXT: MediaPlayerEntityFeature.NEXT_TRACK,
|
||||
}
|
||||
|
||||
HA_HEOS_ENQUEUE_MAP = {
|
||||
None: heos_const.ADD_QUEUE_REPLACE_AND_PLAY,
|
||||
MediaPlayerEnqueue.ADD: heos_const.ADD_QUEUE_ADD_TO_END,
|
||||
MediaPlayerEnqueue.REPLACE: heos_const.ADD_QUEUE_REPLACE_AND_PLAY,
|
||||
MediaPlayerEnqueue.NEXT: heos_const.ADD_QUEUE_PLAY_NEXT,
|
||||
MediaPlayerEnqueue.PLAY: heos_const.ADD_QUEUE_PLAY_NOW,
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -224,11 +233,8 @@ class HeosMediaPlayer(MediaPlayerEntity):
|
|||
playlist = next((p for p in playlists if p.name == media_id), None)
|
||||
if not playlist:
|
||||
raise ValueError(f"Invalid playlist '{media_id}'")
|
||||
add_queue_option = (
|
||||
heos_const.ADD_QUEUE_ADD_TO_END
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE)
|
||||
else heos_const.ADD_QUEUE_REPLACE_AND_PLAY
|
||||
)
|
||||
add_queue_option = HA_HEOS_ENQUEUE_MAP.get(kwargs.get(ATTR_MEDIA_ENQUEUE))
|
||||
|
||||
await self._player.add_to_queue(playlist, add_queue_option)
|
||||
return
|
||||
|
||||
|
|
|
@ -147,6 +147,19 @@ ENTITY_IMAGE_CACHE = {CACHE_IMAGES: collections.OrderedDict(), CACHE_MAXSIZE: 16
|
|||
SCAN_INTERVAL = dt.timedelta(seconds=10)
|
||||
|
||||
|
||||
class MediaPlayerEnqueue(StrEnum):
|
||||
"""Enqueue types for playing media."""
|
||||
|
||||
# add given media item to end of the queue
|
||||
ADD = "add"
|
||||
# play the given media item next, keep queue
|
||||
NEXT = "next"
|
||||
# play the given media item now, keep queue
|
||||
PLAY = "play"
|
||||
# play the given media item now, clear queue
|
||||
REPLACE = "replace"
|
||||
|
||||
|
||||
class MediaPlayerDeviceClass(StrEnum):
|
||||
"""Device class for media players."""
|
||||
|
||||
|
@ -169,7 +182,9 @@ DEVICE_CLASS_RECEIVER = MediaPlayerDeviceClass.RECEIVER.value
|
|||
MEDIA_PLAYER_PLAY_MEDIA_SCHEMA = {
|
||||
vol.Required(ATTR_MEDIA_CONTENT_TYPE): cv.string,
|
||||
vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string,
|
||||
vol.Optional(ATTR_MEDIA_ENQUEUE): cv.boolean,
|
||||
vol.Optional(ATTR_MEDIA_ENQUEUE): vol.Any(
|
||||
cv.boolean, vol.Coerce(MediaPlayerEnqueue)
|
||||
),
|
||||
vol.Optional(ATTR_MEDIA_EXTRA, default={}): dict,
|
||||
}
|
||||
|
||||
|
@ -350,10 +365,30 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
"async_select_sound_mode",
|
||||
[MediaPlayerEntityFeature.SELECT_SOUND_MODE],
|
||||
)
|
||||
|
||||
# Remove in Home Assistant 2022.9
|
||||
def _rewrite_enqueue(value):
|
||||
"""Rewrite the enqueue value."""
|
||||
if ATTR_MEDIA_ENQUEUE not in value:
|
||||
pass
|
||||
elif value[ATTR_MEDIA_ENQUEUE] is True:
|
||||
value[ATTR_MEDIA_ENQUEUE] = MediaPlayerEnqueue.ADD
|
||||
_LOGGER.warning(
|
||||
"Playing media with enqueue set to True is deprecated. Use 'add' instead"
|
||||
)
|
||||
elif value[ATTR_MEDIA_ENQUEUE] is False:
|
||||
value[ATTR_MEDIA_ENQUEUE] = MediaPlayerEnqueue.PLAY
|
||||
_LOGGER.warning(
|
||||
"Playing media with enqueue set to False is deprecated. Use 'play' instead"
|
||||
)
|
||||
|
||||
return value
|
||||
|
||||
component.async_register_entity_service(
|
||||
SERVICE_PLAY_MEDIA,
|
||||
vol.All(
|
||||
cv.make_entity_service_schema(MEDIA_PLAYER_PLAY_MEDIA_SCHEMA),
|
||||
_rewrite_enqueue,
|
||||
_rename_keys(
|
||||
media_type=ATTR_MEDIA_CONTENT_TYPE,
|
||||
media_id=ATTR_MEDIA_CONTENT_ID,
|
||||
|
|
|
@ -27,7 +27,6 @@ from .const import (
|
|||
ATTR_INPUT_SOURCE,
|
||||
ATTR_MEDIA_CONTENT_ID,
|
||||
ATTR_MEDIA_CONTENT_TYPE,
|
||||
ATTR_MEDIA_ENQUEUE,
|
||||
ATTR_MEDIA_VOLUME_LEVEL,
|
||||
ATTR_MEDIA_VOLUME_MUTED,
|
||||
ATTR_SOUND_MODE,
|
||||
|
@ -118,7 +117,7 @@ async def _async_reproduce_states(
|
|||
if features & MediaPlayerEntityFeature.PLAY_MEDIA:
|
||||
await call_service(
|
||||
SERVICE_PLAY_MEDIA,
|
||||
[ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_CONTENT_ID, ATTR_MEDIA_ENQUEUE],
|
||||
[ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_CONTENT_ID],
|
||||
)
|
||||
already_playing = True
|
||||
|
||||
|
|
|
@ -151,6 +151,22 @@ play_media:
|
|||
selector:
|
||||
text:
|
||||
|
||||
enqueue:
|
||||
name: Enqueue
|
||||
description: If the content should be played now or be added to the queue.
|
||||
required: false
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- label: "Play now"
|
||||
value: "play"
|
||||
- label: "Play next"
|
||||
value: "next"
|
||||
- label: "Add to queue"
|
||||
value: "add"
|
||||
- label: "Play now and clear queue"
|
||||
value: "replace"
|
||||
|
||||
select_source:
|
||||
name: Select source
|
||||
description: Send the media player the command to change input source.
|
||||
|
|
|
@ -18,6 +18,7 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.components import media_source, spotify
|
||||
from homeassistant.components.media_player import (
|
||||
MediaPlayerEnqueue,
|
||||
MediaPlayerEntity,
|
||||
MediaPlayerEntityFeature,
|
||||
async_process_play_media_url,
|
||||
|
@ -537,8 +538,6 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
|||
|
||||
If media_type is "playlist", media_id should be a Sonos
|
||||
Playlist name. Otherwise, media_id should be a URI.
|
||||
|
||||
If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the queue.
|
||||
"""
|
||||
if spotify.is_spotify_media_type(media_type):
|
||||
media_type = spotify.resolve_spotify_media_type(media_type)
|
||||
|
@ -575,7 +574,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
|||
)
|
||||
if result.shuffle:
|
||||
self.set_shuffle(True)
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE):
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE) == MediaPlayerEnqueue.ADD:
|
||||
plex_plugin.add_to_queue(result.media)
|
||||
else:
|
||||
soco.clear_queue()
|
||||
|
@ -585,7 +584,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
|||
|
||||
share_link = self.coordinator.share_link
|
||||
if share_link.is_share_link(media_id):
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE):
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE) == MediaPlayerEnqueue.ADD:
|
||||
share_link.add_share_link_to_queue(media_id)
|
||||
else:
|
||||
soco.clear_queue()
|
||||
|
@ -595,7 +594,7 @@ class SonosMediaPlayerEntity(SonosEntity, MediaPlayerEntity):
|
|||
# If media ID is a relative URL, we serve it from HA.
|
||||
media_id = async_process_play_media_url(self.hass, media_id)
|
||||
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE):
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE) == MediaPlayerEnqueue.ADD:
|
||||
soco.add_uri_to_queue(media_id)
|
||||
else:
|
||||
soco.play_uri(media_id, force_radio=is_radio)
|
||||
|
|
|
@ -10,6 +10,7 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.components import media_source
|
||||
from homeassistant.components.media_player import (
|
||||
MediaPlayerEnqueue,
|
||||
MediaPlayerEntity,
|
||||
MediaPlayerEntityFeature,
|
||||
)
|
||||
|
@ -469,16 +470,17 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||
await self._player.async_set_power(True)
|
||||
|
||||
async def async_play_media(self, media_type, media_id, **kwargs):
|
||||
"""
|
||||
Send the play_media command to the media player.
|
||||
|
||||
If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the current playlist.
|
||||
"""
|
||||
cmd = "play"
|
||||
"""Send the play_media command to the media player."""
|
||||
index = None
|
||||
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE):
|
||||
enqueue: MediaPlayerEnqueue | None = kwargs.get(ATTR_MEDIA_ENQUEUE)
|
||||
|
||||
if enqueue == MediaPlayerEnqueue.ADD:
|
||||
cmd = "add"
|
||||
elif enqueue == MediaPlayerEnqueue.NEXT:
|
||||
cmd = "insert"
|
||||
else:
|
||||
cmd = "play"
|
||||
|
||||
if media_source.is_media_source_id(media_id):
|
||||
media_type = MEDIA_TYPE_MUSIC
|
||||
|
|
|
@ -4,6 +4,8 @@ import base64
|
|||
from http import HTTPStatus
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import media_player
|
||||
from homeassistant.components.media_player.browse_media import BrowseMedia
|
||||
from homeassistant.components.websocket_api.const import TYPE_RESULT
|
||||
|
@ -251,3 +253,41 @@ async def test_group_members_available_when_off(hass):
|
|||
state = hass.states.get("media_player.bedroom")
|
||||
assert state.state == STATE_OFF
|
||||
assert "group_members" in state.attributes
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input,expected",
|
||||
(
|
||||
(True, media_player.MediaPlayerEnqueue.ADD),
|
||||
(False, media_player.MediaPlayerEnqueue.PLAY),
|
||||
("play", media_player.MediaPlayerEnqueue.PLAY),
|
||||
("next", media_player.MediaPlayerEnqueue.NEXT),
|
||||
("add", media_player.MediaPlayerEnqueue.ADD),
|
||||
("replace", media_player.MediaPlayerEnqueue.REPLACE),
|
||||
),
|
||||
)
|
||||
async def test_enqueue_rewrite(hass, input, expected):
|
||||
"""Test that group_members are still available when media_player is off."""
|
||||
await async_setup_component(
|
||||
hass, "media_player", {"media_player": {"platform": "demo"}}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Fake group support for DemoYoutubePlayer
|
||||
with patch(
|
||||
"homeassistant.components.demo.media_player.DemoYoutubePlayer.play_media",
|
||||
) as mock_play_media:
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
"play_media",
|
||||
{
|
||||
"entity_id": "media_player.bedroom",
|
||||
"media_content_type": "music",
|
||||
"media_content_id": "1234",
|
||||
"enqueue": input,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert len(mock_play_media.mock_calls) == 1
|
||||
assert mock_play_media.mock_calls[0][2]["enqueue"] == expected
|
||||
|
|
|
@ -6,7 +6,6 @@ from homeassistant.components.media_player.const import (
|
|||
ATTR_INPUT_SOURCE,
|
||||
ATTR_MEDIA_CONTENT_ID,
|
||||
ATTR_MEDIA_CONTENT_TYPE,
|
||||
ATTR_MEDIA_ENQUEUE,
|
||||
ATTR_MEDIA_VOLUME_LEVEL,
|
||||
ATTR_MEDIA_VOLUME_MUTED,
|
||||
ATTR_SOUND_MODE,
|
||||
|
@ -253,7 +252,6 @@ async def test_play_media(hass):
|
|||
|
||||
value_1 = "dummy_1"
|
||||
value_2 = "dummy_2"
|
||||
value_3 = "dummy_3"
|
||||
|
||||
await async_reproduce_states(
|
||||
hass,
|
||||
|
@ -275,7 +273,6 @@ async def test_play_media(hass):
|
|||
{
|
||||
ATTR_MEDIA_CONTENT_TYPE: value_1,
|
||||
ATTR_MEDIA_CONTENT_ID: value_2,
|
||||
ATTR_MEDIA_ENQUEUE: value_3,
|
||||
},
|
||||
)
|
||||
],
|
||||
|
@ -294,5 +291,4 @@ async def test_play_media(hass):
|
|||
"entity_id": ENTITY_1,
|
||||
ATTR_MEDIA_CONTENT_TYPE: value_1,
|
||||
ATTR_MEDIA_CONTENT_ID: value_2,
|
||||
ATTR_MEDIA_ENQUEUE: value_3,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue