diff --git a/libsoundtouch/device.py b/libsoundtouch/device.py index 87ead61..f41a335 100644 --- a/libsoundtouch/device.py +++ b/libsoundtouch/device.py @@ -34,8 +34,7 @@ def _get_dom_element_attribute(xml_dom, element, attribute, if attribute in element.attributes.keys(): return element.attributes[attribute].value return None - else: - return default_value + return default_value def _get_dom_elements(xml_dom, element): @@ -99,6 +98,12 @@ def _on_message(self, web_socket, message): self._presets.append(Preset(preset)) self.__run_listener(self._presets_updated_listeners, self._presets) + if action == "sourcesUpdated" and action_node.hasChildNodes(): + self._sources = [] + for source_item in _get_dom_elements(dom, "sourceItem"): + self._sources.append(SourceItem(source_item)) + self.__run_listener(self._sources_updated_listeners, + self._sources) if action == "zoneUpdated": self.__run_listener(self._zone_status_updated_listeners, self.zone_status(True)) @@ -124,10 +129,12 @@ def __init__(self, host, port=8090, ws_port=8080, dlna_port=8091): self._volume = None self._zone_status = None self._presets = None + self._sources = None self._ws_client = None self._volume_updated_listeners = [] self._status_updated_listeners = [] self._presets_updated_listeners = [] + self._sources_updated_listeners = [] self._zone_status_updated_listeners = [] self._device_info_updated_listeners = [] self._snapshot = None @@ -160,6 +167,10 @@ def add_presets_listener(self, listener): """Add a new presets updated listener.""" self._presets_updated_listeners.append(listener) + def add_sources_listener(self, listener): + """Add a new sources updated listener.""" + self._sources_updated_listeners.append(listener) + def add_zone_status_listener(self, listener): """Add a new zone status updated listener.""" self._zone_status_updated_listeners.append(listener) @@ -183,6 +194,11 @@ def remove_presets_listener(self, listener): if listener in self._presets_updated_listeners: self._presets_updated_listeners.remove(listener) + def remove_sources_listener(self, listener): + """Remove a new sources updated listener.""" + if listener in self._sources_updated_listeners: + self._sources_updated_listeners.remove(listener) + def remove_zone_status_listener(self, listener): """Remove a new zone status updated listener.""" if listener in self._zone_status_updated_listeners: @@ -205,6 +221,10 @@ def clear_presets_listeners(self): """Clear presets updated listeners.""" del self._presets_updated_listeners[:] + def clear_sources_listeners(self): + """Clear sources updated listeners.""" + del self._sources_updated_listeners[:] + def clear_zone_status_listeners(self): """Clear zone status updated listeners.""" del self._zone_status_updated_listeners[:] @@ -228,6 +248,11 @@ def presets_updated_listeners(self): """Return Presets Updated listeners.""" return self._presets_updated_listeners + @property + def sources_updated_listeners(self): + """Return Sources Updated listeners.""" + return self._sources_updated_listeners + @property def zone_status_updated_listeners(self): """Return Zone Status Updated listeners.""" @@ -263,6 +288,16 @@ def refresh_presets(self): for preset in _get_dom_elements(dom, "preset"): self._presets.append(Preset(preset)) + def refresh_sources(self): + """Refersh sources.""" + response = requests.get( + "http://" + self._host + ":" + str(self._port) + "/sources") + response.encoding = 'UTF-8' + dom = minidom.parseString(response.text.encode('utf-8')) + self._sources = [] + for source_item in _get_dom_elements(dom, "sourceItem"): + self._sources.append(SourceItem(source_item)) + def refresh_zone_status(self): """Refresh Zone Status.""" response = requests.get( @@ -314,7 +349,7 @@ def select_source_bluetooth(self): self.select_content_item(Source.BLUETOOTH) def _create_zone(self, slaves): - if len(slaves) <= 0: + if not slaves: raise NoSlavesException() request_body = '' % ( self.config.device_id, self.config.device_ip @@ -326,7 +361,7 @@ def _create_zone(self, slaves): return request_body def _get_zone_request_body(self, slaves): - if len(slaves) <= 0: + if not slaves: raise NoSlavesException() request_body = '' % self.config.device_id for slave in slaves: @@ -380,7 +415,7 @@ def remove_zone_slave(self, slaves): if self.zone_status() is None: raise NoExistingZoneException() request_body = self._get_zone_request_body(slaves) - _LOGGER.info("Removing slaves from multi-room zone with master " + + _LOGGER.info("Removing slaves from multi-room zone with master " "device %s", self.config.name) requests.post( "http://" + self.host + ":" + str( @@ -509,6 +544,15 @@ def presets(self, refresh=True): self.refresh_presets() return self._presets + def sources(self, refresh=True): + """Sources. + + :param refresh: Force refresh, else return old data. + """ + if self._sources is None or refresh: + self.refresh_sources() + return self._sources + def set_volume(self, level): """Set volume level: from 0 to 100.""" action = '/volume' @@ -940,6 +984,47 @@ def __repr__(self): return 'ContentItem(' + ",".join(formated_fields) + ')' +class SourceItem: + """Source item.""" + + def __init__(self, xml_dom): + """Create a new source item. + + :param xml_dom: Source item XML DOM + """ + self._source = _get_dom_attribute(xml_dom, "source") + self._source_account = _get_dom_attribute(xml_dom, "sourceAccount") + self._status = _get_dom_attribute(xml_dom, "status") + self._is_local = _get_dom_attribute(xml_dom, "isLocal") == 'true' + self._multi_room_allowed = \ + _get_dom_attribute(xml_dom, "multiroomallowed") == 'true' + + @property + def source(self): + """Source.""" + return self._source + + @property + def source_account(self): + """Source account.""" + return self._source_account + + @property + def status(self): + """Status.""" + return self._status + + @property + def is_local(self): + """Return true if local.""" + return self._is_local + + @property + def multi_room_allowed(self): + """Return true if multi room allowed.""" + return self._multi_room_allowed + + class Volume: """Volume configuration.""" diff --git a/libsoundtouch/utils.py b/libsoundtouch/utils.py index b097464..55bf8a2 100644 --- a/libsoundtouch/utils.py +++ b/libsoundtouch/utils.py @@ -75,7 +75,7 @@ class Type(Enum): PLAYLIST = "playlist" -class SoundtouchDeviceListener(object): +class SoundtouchDeviceListener: """Message listener.""" def __init__(self, add_device_function): diff --git a/setup.py b/setup.py index 1654bd7..0fda792 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ def gen_data_files(*dirs): setup( name="libsoundtouch", - version="0.8.0", + version="0.8.1", license="Apache License 2.0", url="http://libsoundtouch.readthedocs.io", download_url="https://github.com/CharlesBlonde/libsoundtouch", diff --git a/tox.ini b/tox.ini index 79dcf98..8644acc 100644 --- a/tox.ini +++ b/tox.ini @@ -58,4 +58,4 @@ basepython = python3 deps = -r{toxinidir}/requirements_test.txt commands = - mypy --silent-imports libsoundtouch + mypy --ignore-missing-imports --follow-imports=skip libsoundtouch