<s> """<STR_LIT>""" <EOL> import logging <EOL> from copy import copy <EOL> from homeassistant . components . media_player import ( <EOL> ATTR_APP_ID , ATTR_APP_NAME , ATTR_MEDIA_ALBUM_ARTIST , ATTR_MEDIA_ALBUM_NAME , <EOL> ATTR_MEDIA_ARTIST , ATTR_MEDIA_CHANNEL , ATTR_MEDIA_CONTENT_ID , <EOL> ATTR_MEDIA_CONTENT_TYPE , ATTR_MEDIA_DURATION , ATTR_MEDIA_EPISODE , <EOL> ATTR_MEDIA_PLAYLIST , ATTR_MEDIA_SEASON , ATTR_MEDIA_SEEK_POSITION , <EOL> ATTR_MEDIA_SERIES_TITLE , ATTR_MEDIA_TITLE , ATTR_MEDIA_TRACK , <EOL> ATTR_MEDIA_VOLUME_LEVEL , ATTR_MEDIA_VOLUME_MUTED , <EOL> ATTR_SUPPORTED_MEDIA_COMMANDS , DOMAIN , SERVICE_PLAY_MEDIA , <EOL> SUPPORT_TURN_OFF , SUPPORT_TURN_ON , SUPPORT_VOLUME_MUTE , SUPPORT_VOLUME_SET , <EOL> SUPPORT_VOLUME_STEP , SUPPORT_SELECT_SOURCE , ATTR_INPUT_SOURCE , <EOL> SERVICE_SELECT_SOURCE , MediaPlayerDevice ) <EOL> from homeassistant . const import ( <EOL> ATTR_ENTITY_ID , ATTR_ENTITY_PICTURE , CONF_NAME , SERVICE_MEDIA_NEXT_TRACK , <EOL> SERVICE_MEDIA_PAUSE , SERVICE_MEDIA_PLAY , SERVICE_MEDIA_PLAY_PAUSE , <EOL> SERVICE_MEDIA_PREVIOUS_TRACK , SERVICE_MEDIA_SEEK , SERVICE_TURN_OFF , <EOL> SERVICE_TURN_ON , SERVICE_VOLUME_DOWN , SERVICE_VOLUME_MUTE , <EOL> SERVICE_VOLUME_SET , SERVICE_VOLUME_UP , STATE_IDLE , STATE_OFF , STATE_ON ) <EOL> from homeassistant . helpers . event import track_state_change <EOL> from homeassistant . helpers . service import call_from_config <EOL> ATTR_ACTIVE_CHILD = '<STR_LIT>' <EOL> CONF_ATTRS = '<STR_LIT>' <EOL> CONF_CHILDREN = '<STR_LIT>' <EOL> CONF_COMMANDS = '<STR_LIT>' <EOL> CONF_PLATFORM = '<STR_LIT>' <EOL> CONF_SERVICE = '<STR_LIT>' <EOL> CONF_SERVICE_DATA = '<STR_LIT>' <EOL> CONF_STATE = '<STR_LIT:state>' <EOL> OFF_STATES = [ STATE_IDLE , STATE_OFF ] <EOL> REQUIREMENTS = [ ] <EOL> _LOGGER = logging . getLogger ( __name__ ) <EOL> def setup_platform ( hass , config , add_devices , discovery_info = None ) : <EOL> """<STR_LIT>""" <EOL> if not validate_config ( config ) : <EOL> return <EOL> player = UniversalMediaPlayer ( hass , <EOL> config [ CONF_NAME ] , <EOL> config [ CONF_CHILDREN ] , <EOL> config [ CONF_COMMANDS ] , <EOL> config [ CONF_ATTRS ] ) <EOL> add_devices ( [ player ] ) <EOL> def validate_config ( config ) : <EOL> """<STR_LIT>""" <EOL> del config [ CONF_PLATFORM ] <EOL> if CONF_NAME not in config : <EOL> _LOGGER . error ( '<STR_LIT>' ) <EOL> return False <EOL> validate_children ( config ) <EOL> validate_commands ( config ) <EOL> validate_attributes ( config ) <EOL> del_keys = [ ] <EOL> for key in config : <EOL> if key not in [ CONF_NAME , CONF_CHILDREN , CONF_COMMANDS , CONF_ATTRS ] : <EOL> _LOGGER . warning ( <EOL> '<STR_LIT>' , <EOL> config [ CONF_NAME ] , key ) <EOL> del_keys . append ( key ) <EOL> for key in del_keys : <EOL> del config [ key ] <EOL> return True <EOL> def validate_children ( config ) : <EOL> """<STR_LIT>""" <EOL> if CONF_CHILDREN not in config : <EOL> _LOGGER . info ( <EOL> '<STR_LIT>' , config [ CONF_NAME ] ) <EOL> config [ CONF_CHILDREN ] = [ ] <EOL> elif not isinstance ( config [ CONF_CHILDREN ] , list ) : <EOL> _LOGGER . warning ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' , <EOL> config [ CONF_NAME ] ) <EOL> config [ CONF_CHILDREN ] = [ ] <EOL> def validate_commands ( config ) : <EOL> """<STR_LIT>""" <EOL> if CONF_COMMANDS not in config : <EOL> config [ CONF_COMMANDS ] = { } <EOL> elif not isinstance ( config [ CONF_COMMANDS ] , dict ) : <EOL> _LOGGER . warning ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' , <EOL> config [ CONF_NAME ] ) <EOL> config [ CONF_COMMANDS ] = { } <EOL> def validate_attributes ( config ) : <EOL> """<STR_LIT>""" <EOL> if CONF_ATTRS not in config : <EOL> config [ CONF_ATTRS ] = { } <EOL> elif not isinstance ( config [ CONF_ATTRS ] , dict ) : <EOL> _LOGGER . warning ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' , <EOL> config [ CONF_NAME ] ) <EOL> config [ CONF_ATTRS ] = { } <EOL> for key , val in config [ CONF_ATTRS ] . items ( ) : <EOL> attr = val . split ( '<STR_LIT:|>' , <NUM_LIT:1> ) <EOL> if len ( attr ) == <NUM_LIT:1> : <EOL> attr . append ( None ) <EOL> config [ CONF_ATTRS ] [ key ] = attr <EOL> class UniversalMediaPlayer ( MediaPlayerDevice ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , hass , name , children , commands , attributes ) : <EOL> """<STR_LIT>""" <EOL> self . hass = hass <EOL> self . _name = name <EOL> self . _children = children <EOL> self . _cmds = commands <EOL> self . _attrs = attributes <EOL> self . _child_state = None <EOL> def on_dependency_update ( * _ ) : <EOL> """<STR_LIT>""" <EOL> self . update_ha_state ( True ) <EOL> depend = copy ( children ) <EOL> for entity in attributes . values ( ) : <EOL> depend . append ( entity [ <NUM_LIT:0> ] ) <EOL> track_state_change ( hass , depend , on_dependency_update ) <EOL> def _entity_lkp ( self , entity_id , state_attr = None ) : <EOL> """<STR_LIT>""" <EOL> state_obj = self . hass . states . get ( entity_id ) <EOL> if state_obj is None : <EOL> return <EOL> if state_attr : <EOL> return state_obj . attributes . get ( state_attr ) <EOL> return state_obj . state <EOL> def _override_or_child_attr ( self , attr_name ) : <EOL> """<STR_LIT>""" <EOL> if attr_name in self . _attrs : <EOL> return self . _entity_lkp ( self . _attrs [ attr_name ] [ <NUM_LIT:0> ] , <EOL> self . _attrs [ attr_name ] [ <NUM_LIT:1> ] ) <EOL> return self . _child_attr ( attr_name ) <EOL> def _child_attr ( self , attr_name ) : <EOL> """<STR_LIT>""" <EOL> active_child = self . _child_state <EOL> return active_child . attributes . get ( attr_name ) if active_child else None <EOL> def _call_service ( self , service_name , service_data = None , <EOL> allow_override = False ) : <EOL> """<STR_LIT>""" <EOL> if allow_override and service_name in self . _cmds : <EOL> call_from_config ( <EOL> self . hass , self . _cmds [ service_name ] , blocking = True ) <EOL> return <EOL> if service_data is None : <EOL> service_data = { } <EOL> active_child = self . _child_state <EOL> service_data [ ATTR_ENTITY_ID ] = active_child . entity_id <EOL> self . hass . services . call ( DOMAIN , service_name , service_data , <EOL> blocking = True ) <EOL> @ property <EOL> def should_poll ( self ) : <EOL> """<STR_LIT>""" <EOL> return False <EOL> @ property <EOL> def master_state ( self ) : <EOL> """<STR_LIT>""" <EOL> if CONF_STATE in self . _attrs : <EOL> master_state = self . _entity_lkp ( self . _attrs [ CONF_STATE ] [ <NUM_LIT:0> ] , <EOL> self . _attrs [ CONF_STATE ] [ <NUM_LIT:1> ] ) <EOL> return master_state if master_state else STATE_OFF <EOL> else : <EOL> return None <EOL> @ property <EOL> def name ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _name <EOL> @ property <EOL> def state ( self ) : <EOL> """<STR_LIT>""" <EOL> master_state = self . master_state <EOL> if master_state == STATE_OFF : <EOL> return STATE_OFF <EOL> active_child = self . _child_state <EOL> if active_child : <EOL> return active_child . state <EOL> return master_state if master_state else STATE_OFF <EOL> @ property <EOL> def volume_level ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_VOLUME_LEVEL ) <EOL> @ property <EOL> def is_volume_muted ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _override_or_child_attr ( ATTR_MEDIA_VOLUME_MUTED ) in [ True , STATE_ON ] <EOL> @ property <EOL> def media_content_id ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_CONTENT_ID ) <EOL> @ property <EOL> def media_content_type ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_CONTENT_TYPE ) <EOL> @ property <EOL> def media_duration ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_DURATION ) <EOL> @ property <EOL> def media_image_url ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_ENTITY_PICTURE ) <EOL> @ property <EOL> def media_title ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_TITLE ) <EOL> @ property <EOL> def media_artist ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_ARTIST ) <EOL> @ property <EOL> def media_album_name ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_ALBUM_NAME ) <EOL> @ property <EOL> def media_album_artist ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_ALBUM_ARTIST ) <EOL> @ property <EOL> def media_track ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_TRACK ) <EOL> @ property <EOL> def media_series_title ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_SERIES_TITLE ) <EOL> @ property <EOL> def media_season ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_SEASON ) <EOL> @ property <EOL> def media_episode ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_EPISODE ) <EOL> @ property <EOL> def media_channel ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_CHANNEL ) <EOL> @ property <EOL> def media_playlist ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_MEDIA_PLAYLIST ) <EOL> @ property <EOL> def app_id ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_APP_ID ) <EOL> @ property <EOL> def app_name ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_APP_NAME ) <EOL> @ property <EOL> def current_source ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _child_attr ( ATTR_INPUT_SOURCE ) <EOL> @ property <EOL> def supported_media_commands ( self ) : <EOL> """<STR_LIT>""" <EOL> flags = self . _child_attr ( ATTR_SUPPORTED_MEDIA_COMMANDS ) or <NUM_LIT:0> <EOL> if SERVICE_TURN_ON in self . _cmds : <EOL> flags |= SUPPORT_TURN_ON <EOL> if SERVICE_TURN_OFF in self . _cmds : <EOL> flags |= SUPPORT_TURN_OFF <EOL> if any ( [ cmd in self . _cmds for cmd in [ SERVICE_VOLUME_UP , <EOL> SERVICE_VOLUME_DOWN ] ] ) : <EOL> flags |= SUPPORT_VOLUME_STEP <EOL> flags &= ~ SUPPORT_VOLUME_SET <EOL> if SERVICE_VOLUME_MUTE in self . _cmds and ATTR_MEDIA_VOLUME_MUTED in self . _attrs : <EOL> flags |= SUPPORT_VOLUME_MUTE <EOL> if SUPPORT_SELECT_SOURCE in self . _cmds : <EOL> flags |= SUPPORT_SELECT_SOURCE <EOL> return flags <EOL> @ property <EOL> def device_state_attributes ( self ) : <EOL> """<STR_LIT>""" <EOL> active_child = self . _child_state <EOL> return { ATTR_ACTIVE_CHILD : active_child . entity_id } if active_child else { } <EOL> def turn_on ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_TURN_ON , allow_override = True ) <EOL> def turn_off ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_TURN_OFF , allow_override = True ) <EOL> def mute_volume ( self , is_volume_muted ) : <EOL> """<STR_LIT>""" <EOL> data = { ATTR_MEDIA_VOLUME_MUTED : is_volume_muted } <EOL> self . _call_service ( SERVICE_VOLUME_MUTE , data , allow_override = True ) <EOL> def set_volume_level ( self , volume_level ) : <EOL> """<STR_LIT>""" <EOL> data = { ATTR_MEDIA_VOLUME_LEVEL : volume_level } <EOL> self . _call_service ( SERVICE_VOLUME_SET , data ) <EOL> def media_play ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_MEDIA_PLAY ) <EOL> def media_pause ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_MEDIA_PAUSE ) <EOL> def media_previous_track ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_MEDIA_PREVIOUS_TRACK ) <EOL> def media_next_track ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_MEDIA_NEXT_TRACK ) <EOL> def media_seek ( self , position ) : <EOL> """<STR_LIT>""" <EOL> data = { ATTR_MEDIA_SEEK_POSITION : position } <EOL> self . _call_service ( SERVICE_MEDIA_SEEK , data ) <EOL> def play_media ( self , media_type , media_id ) : <EOL> """<STR_LIT>""" <EOL> data = { ATTR_MEDIA_CONTENT_TYPE : media_type , <EOL> ATTR_MEDIA_CONTENT_ID : media_id } <EOL> self . _call_service ( SERVICE_PLAY_MEDIA , data ) <EOL> def volume_up ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_VOLUME_UP , allow_override = True ) <EOL> def volume_down ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_VOLUME_DOWN , allow_override = True ) <EOL> def media_play_pause ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _call_service ( SERVICE_MEDIA_PLAY_PAUSE ) <EOL> def select_source ( self , source ) : <EOL> """<STR_LIT>""" <EOL> data = { ATTR_INPUT_SOURCE : source } <EOL> self . _call_service ( SERVICE_SELECT_SOURCE , data ) <EOL> def update ( self ) : <EOL> """<STR_LIT>""" <EOL> for child_name in self . _children : <EOL> child_state = self . hass . states . get ( child_name ) <EOL> if child_state and child_state . state not in OFF_STATES : <EOL> self . _child_state = child_state <EOL> return <EOL> self . _child_state = None </s>
