Add add_uri_to_queue support to (sonos) media player (#1946)

Sonos (SoCo) supports add_uri_to_queue capability, making it possible
to stream media available via HTTP for example. This patch extends
media_player component and sonos platform to support this feature
This commit is contained in:
Alexander Fortin 2016-05-20 08:30:19 +02:00 committed by Paulus Schoutsen
parent 1eb3181c14
commit a4409da700
8 changed files with 36 additions and 14 deletions

View File

@ -63,6 +63,7 @@ ATTR_APP_NAME = 'app_name'
ATTR_SUPPORTED_MEDIA_COMMANDS = 'supported_media_commands' ATTR_SUPPORTED_MEDIA_COMMANDS = 'supported_media_commands'
ATTR_INPUT_SOURCE = 'source' ATTR_INPUT_SOURCE = 'source'
ATTR_INPUT_SOURCE_LIST = 'source_list' ATTR_INPUT_SOURCE_LIST = 'source_list'
ATTR_MEDIA_ENQUEUE = 'enqueue'
MEDIA_TYPE_MUSIC = 'music' MEDIA_TYPE_MUSIC = 'music'
MEDIA_TYPE_TVSHOW = 'tvshow' MEDIA_TYPE_TVSHOW = 'tvshow'
@ -145,6 +146,7 @@ MEDIA_PLAYER_MEDIA_SEEK_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
MEDIA_PLAYER_PLAY_MEDIA_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ MEDIA_PLAYER_PLAY_MEDIA_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
vol.Required(ATTR_MEDIA_CONTENT_TYPE): cv.string, vol.Required(ATTR_MEDIA_CONTENT_TYPE): cv.string,
vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string, vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string,
ATTR_MEDIA_ENQUEUE: cv.boolean,
}) })
MEDIA_PLAYER_SELECT_SOURCE_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ MEDIA_PLAYER_SELECT_SOURCE_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
@ -256,7 +258,7 @@ def media_seek(hass, position, entity_id=None):
hass.services.call(DOMAIN, SERVICE_MEDIA_SEEK, data) hass.services.call(DOMAIN, SERVICE_MEDIA_SEEK, data)
def play_media(hass, media_type, media_id, entity_id=None): def play_media(hass, media_type, media_id, entity_id=None, enqueue=None):
"""Send the media player the command for playing media.""" """Send the media player the command for playing media."""
data = {ATTR_MEDIA_CONTENT_TYPE: media_type, data = {ATTR_MEDIA_CONTENT_TYPE: media_type,
ATTR_MEDIA_CONTENT_ID: media_id} ATTR_MEDIA_CONTENT_ID: media_id}
@ -264,6 +266,9 @@ def play_media(hass, media_type, media_id, entity_id=None):
if entity_id: if entity_id:
data[ATTR_ENTITY_ID] = entity_id data[ATTR_ENTITY_ID] = entity_id
if enqueue:
data[ATTR_MEDIA_ENQUEUE] = enqueue
hass.services.call(DOMAIN, SERVICE_PLAY_MEDIA, data) hass.services.call(DOMAIN, SERVICE_PLAY_MEDIA, data)
@ -364,9 +369,14 @@ def setup(hass, config):
"""Play specified media_id on the media player.""" """Play specified media_id on the media player."""
media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE) media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE)
media_id = service.data.get(ATTR_MEDIA_CONTENT_ID) media_id = service.data.get(ATTR_MEDIA_CONTENT_ID)
enqueue = service.data.get(ATTR_MEDIA_ENQUEUE)
kwargs = {
ATTR_MEDIA_ENQUEUE: enqueue,
}
for player in component.extract_from_service(service): for player in component.extract_from_service(service):
player.play_media(media_type, media_id) player.play_media(media_type, media_id, **kwargs)
if player.should_poll: if player.should_poll:
player.update_ha_state(True) player.update_ha_state(True)

View File

@ -253,7 +253,7 @@ class CastDevice(MediaPlayerDevice):
"""Seek the media to a specific location.""" """Seek the media to a specific location."""
self.cast.media_controller.seek(position) self.cast.media_controller.seek(position)
def play_media(self, media_type, media_id): def play_media(self, media_type, media_id, **kwargs):
"""Play media from a URL.""" """Play media from a URL."""
self.cast.media_controller.play_media(media_id, media_type) self.cast.media_controller.play_media(media_id, media_type)

View File

@ -152,7 +152,7 @@ class DemoYoutubePlayer(AbstractDemoPlayer):
"""Flag of media commands that are supported.""" """Flag of media commands that are supported."""
return YOUTUBE_PLAYER_SUPPORT return YOUTUBE_PLAYER_SUPPORT
def play_media(self, media_type, media_id): def play_media(self, media_type, media_id, **kwargs):
"""Play a piece of media.""" """Play a piece of media."""
self.youtube_id = media_id self.youtube_id = media_id
self.update_ha_state() self.update_ha_state()

View File

@ -320,7 +320,7 @@ class ItunesDevice(MediaPlayerDevice):
response = self.client.previous() response = self.client.previous()
self.update_state(response) self.update_state(response)
def play_media(self, media_type, media_id): def play_media(self, media_type, media_id, **kwargs):
"""Send the play_media command to the media player.""" """Send the play_media command to the media player."""
if media_type == MEDIA_TYPE_PLAYLIST: if media_type == MEDIA_TYPE_PLAYLIST:
response = self.client.play_playlist(media_id) response = self.client.play_playlist(media_id)

View File

@ -278,6 +278,6 @@ class KodiDevice(MediaPlayerDevice):
self.update_ha_state() self.update_ha_state()
def play_media(self, media_type, media_id): def play_media(self, media_type, media_id, **kwargs):
"""Send the play_media command to the media player.""" """Send the play_media command to the media player."""
self._server.Player.Open({media_type: media_id}, {}) self._server.Player.Open({media_type: media_id}, {})

View File

@ -212,7 +212,7 @@ class MpdDevice(MediaPlayerDevice):
"""Service to send the MPD the command for previous track.""" """Service to send the MPD the command for previous track."""
self.client.previous() self.client.previous()
def play_media(self, media_type, media_id): def play_media(self, media_type, media_id, **kwargs):
"""Send the media player the command for playing a playlist.""" """Send the media player the command for playing a playlist."""
_LOGGER.info(str.format("Playing playlist: {0}", media_id)) _LOGGER.info(str.format("Playing playlist: {0}", media_id))
if media_type == MEDIA_TYPE_PLAYLIST: if media_type == MEDIA_TYPE_PLAYLIST:

View File

@ -9,10 +9,9 @@ import logging
import socket import socket
from homeassistant.components.media_player import ( from homeassistant.components.media_player import (
MEDIA_TYPE_MUSIC, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, ATTR_MEDIA_ENQUEUE, MEDIA_TYPE_MUSIC, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE,
SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK,
SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, MediaPlayerDevice)
MediaPlayerDevice)
from homeassistant.const import ( from homeassistant.const import (
STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, STATE_OFF) STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, STATE_OFF)
@ -268,9 +267,22 @@ class SonosDevice(MediaPlayerDevice):
self._player.play() self._player.play()
@only_if_coordinator @only_if_coordinator
def play_media(self, media_type, media_id): def play_media(self, media_type, media_id, **kwargs):
"""Send the play_media command to the media player.""" """
self._player.play_uri(media_id) Send the play_media command to the media player.
If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the queue.
"""
if kwargs.get(ATTR_MEDIA_ENQUEUE):
from soco.exceptions import SoCoUPnPException
try:
self._player.add_uri_to_queue(media_id)
except SoCoUPnPException:
_LOGGER.error('Error parsing media uri "%s", '
"please check it's a valid media resource "
'supported by Sonos', media_id)
else:
self._player.play_uri(media_id)
@property @property
def available(self): def available(self):

View File

@ -402,7 +402,7 @@ class UniversalMediaPlayer(MediaPlayerDevice):
data = {ATTR_MEDIA_SEEK_POSITION: position} data = {ATTR_MEDIA_SEEK_POSITION: position}
self._call_service(SERVICE_MEDIA_SEEK, data) self._call_service(SERVICE_MEDIA_SEEK, data)
def play_media(self, media_type, media_id): def play_media(self, media_type, media_id, **kwargs):
"""Play a piece of media.""" """Play a piece of media."""
data = {ATTR_MEDIA_CONTENT_TYPE: media_type, data = {ATTR_MEDIA_CONTENT_TYPE: media_type,
ATTR_MEDIA_CONTENT_ID: media_id} ATTR_MEDIA_CONTENT_ID: media_id}