diff --git a/custom_components/alexa_media/media_player.py b/custom_components/alexa_media/media_player.py index 427a5159..d08d02bf 100644 --- a/custom_components/alexa_media/media_player.py +++ b/custom_components/alexa_media/media_player.py @@ -7,6 +7,7 @@ For more details about this platform, please refer to the documentation at https://community.home-assistant.io/t/echo-devices-alexa-as-media-player-testers-needed/58639 """ +import asyncio import logging from typing import List # noqa pylint: disable=unused-import @@ -136,6 +137,7 @@ def __init__(self, device, login): self._source_list = [] self._shuffle = None self._repeat = None + self._playing_parent = None # Last Device self._last_called = None # Do not Disturb state @@ -204,8 +206,9 @@ async def _refresh_if_no_audiopush(already_refreshed=False): event_serial = (event.data['last_called_change']['serialNumber'] if event.data['last_called_change'] else None) elif 'bluetooth_change' in event.data: - event_serial = (event.data['bluetooth_change']['deviceSerialNumber'] - if event.data['bluetooth_change'] else None) + event_serial = ( + event.data['bluetooth_change']['deviceSerialNumber'] + if event.data['bluetooth_change'] else None) elif 'player_state' in event.data: event_serial = (event.data['player_state']['dopplerId'] ['deviceSerialNumber'] @@ -346,6 +349,7 @@ async def refresh(self, device=None): self._available = device['online'] self._capabilities = device['capabilities'] self._cluster_members = device['clusterMembers'] + self._parent_clusters = device['parentClusters'] self._bluetooth_state = device['bluetooth_state'] self._locale = device['locale'] if 'locale' in device else 'en-US' self._timezone = (device['timeZoneId'] @@ -355,20 +359,67 @@ async def refresh(self, device=None): session = None if self._available: _LOGGER.debug("%s: Refreshing %s", self.account, self.name) + if self._parent_clusters and self.hass: + playing_parents = list(filter( + lambda x: ( + self.hass.data[DATA_ALEXAMEDIA] + ['accounts'] + [self._login.email] + ['entities'] + ['media_player'][x].state == STATE_PLAYING), + self._parent_clusters)) + else: + playing_parents = [] if "PAIR_BT_SOURCE" in self._capabilities: self._source = await self._get_source() self._source_list = await self._get_source_list() self._last_called = await self._get_last_called() if "MUSIC_SKILL" in self._capabilities: - session = await self.alexa_api.get_state() + parent_session = {} + if playing_parents: + if len(playing_parents) > 1: + _LOGGER.warning( + "Found multiple playing parents " + "please file an issue") + parent = ( + self.hass.data[DATA_ALEXAMEDIA] + ['accounts'] + [self._login.email] + ['entities'] + ['media_player'][playing_parents[0]] + ) + self._playing_parent = parent + parent_session = parent.session + if parent_session: + session = parent_session.copy() + session["isPlayingInLemur"] = False + session["lemurVolume"] = None + session["volume"] = ( + parent_session["lemurVolume"]["memberVolume"] + [self.device_serial_number]) + session = {"playerInfo": session} + else: + self._playing_parent = None + session = await self.alexa_api.get_state() await self._clear_media_details() # update the session if it exists; not doing relogin here - if session is not None: + if session: self._session = session - if self._session is None: - return - if 'playerInfo' in self._session: + if self._session and 'playerInfo' in self._session: self._session = self._session['playerInfo'] + if self._session['transport'] is not None: + self._shuffle = (self._session['transport'] + ['shuffle'] == "SELECTED" + if ('shuffle' in self._session['transport'] + and self._session['transport']['shuffle'] + != 'DISABLED') + else None) + self._repeat = (self._session['transport'] + ['repeat'] == "SELECTED" + if ('repeat' in self._session['transport'] + and self._session['transport']['repeat'] + != 'DISABLED') + else None) if self._session['state'] is not None: self._media_player_state = self._session['state'] self._media_pos = (self._session['progress']['mediaProgress'] @@ -376,17 +427,6 @@ async def refresh(self, device=None): and 'mediaProgress' in self._session['progress']) else None) - self._media_is_muted = (self._session['volume']['muted'] - if (self._session['volume'] is not None - and 'muted' in - self._session['volume']) - else None) - self._media_vol_level = (self._session['volume'] - ['volume'] / 100 - if(self._session['volume'] is not None - and 'volume' in - self._session['volume']) - else None) self._media_title = (self._session['infoText']['title'] if (self._session['infoText'] is not None and 'title' in @@ -413,19 +453,56 @@ async def refresh(self, device=None): None and 'mediaLength' in self._session['progress']) else None) - if self._session['transport'] is not None: - self._shuffle = (self._session['transport'] - ['shuffle'] == "SELECTED" - if ('shuffle' in self._session['transport'] - and self._session['transport']['shuffle'] - != 'DISABLED') - else None) - self._repeat = (self._session['transport'] - ['repeat'] == "SELECTED" - if ('repeat' in self._session['transport'] - and self._session['transport']['repeat'] - != 'DISABLED') - else None) + if not self._session["lemurVolume"]: + self._media_is_muted = ( + self._session['volume']['muted'] + if (self._session['volume'] is not None + and 'muted' in + self._session['volume']) + else None) + self._media_vol_level = ( + self._session['volume'] + ['volume'] / 100 + if(self._session['volume'] is not None + and 'volume' in + self._session['volume']) + else None) + else: + self._media_is_muted = ( + self._session['lemurVolume']['compositeVolume']['muted'] + if (self._session['lemurVolume']['compositeVolume'] is not None + and 'muted' in + self._session['lemurVolume']['compositeVolume']) + else None) + self._media_vol_level = ( + self._session['lemurVolume']['compositeVolume'] + ['volume'] / 100 + if (self._session['lemurVolume']['compositeVolume']['volume'] is not None + and 'volume' in + self._session['lemurVolume']['compositeVolume']) + else None) + if not self.hass: + return + asyncio.gather( + *map( + lambda x: ( + self.hass.data[DATA_ALEXAMEDIA] + ['accounts'] + [self._login.email] + ['entities'] + ['media_player'][x].async_update()), + filter( + lambda x: ( + x in self._cluster_members and x in ( + self.hass.data[DATA_ALEXAMEDIA] + ['accounts'] + [self._login.email] + ['entities'] + ['media_player'])), + self._session['lemurVolume']['memberVolume'].keys() + ) + ) + ) @property def source(self): @@ -745,7 +822,10 @@ async def async_media_play(self): if not (self.state in [STATE_PLAYING, STATE_PAUSED] and self.available): return - await self.alexa_api.play() + if self._playing_parent: + await self._playing_parent.async_media_play() + else: + await self.alexa_api.play() if not (self.hass.data[DATA_ALEXAMEDIA] ['accounts'][self._login.email]['websocket']): await self.async_update() @@ -756,7 +836,10 @@ async def async_media_pause(self): if not (self.state in [STATE_PLAYING, STATE_PAUSED] and self.available): return - await self.alexa_api.pause() + if self._playing_parent: + await self._playing_parent.async_media_pause() + else: + await self.alexa_api.pause() if not (self.hass.data[DATA_ALEXAMEDIA] ['accounts'][self._login.email]['websocket']): await self.async_update() @@ -788,7 +871,10 @@ async def async_media_next_track(self): if not (self.state in [STATE_PLAYING, STATE_PAUSED] and self.available): return - await self.alexa_api.next() + if self._playing_parent: + await self._playing_parent.async_media_next_track() + else: + await self.alexa_api.next() if not (self.hass.data[DATA_ALEXAMEDIA] ['accounts'][self._login.email]['websocket']): await self.async_update() @@ -799,7 +885,10 @@ async def async_media_previous_track(self): if not (self.state in [STATE_PLAYING, STATE_PAUSED] and self.available): return - await self.alexa_api.previous() + if self._playing_parent: + await self._playing_parent.async_media_previous_track() + else: + await self.alexa_api.previous() if not (self.hass.data[DATA_ALEXAMEDIA] ['accounts'][self._login.email]['websocket']): await self.async_update()