def media_title(self): """Title of current playing media.""" state_var = self._state_variable('AVT', 'CurrentTrackMetaData') if state_var is None: return None xml = state_var.value if not xml or xml == 'NOT_IMPLEMENTED': return None items = didl_lite.from_xml_string(xml) if not items: return None item = items[0] return item.title
def media_title(self) -> Optional[str]: """Title of current playing media.""" state_var = self._state_variable("AVT", "CurrentTrackMetaData") if state_var is None: return None xml = state_var.value if not xml or xml == "NOT_IMPLEMENTED": return None items = didl_lite.from_xml_string(xml, strict=False) if not items: return None item = items[0] title: str = item.title return title
def test_descriptor_from_xml_root(self) -> None: """Test root descriptor from XML.""" didl_string = """ <DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/"> <desc id="1" nameSpace="ns" type="type">Text</desc> </DIDL-Lite>""" items = didl_lite.from_xml_string(didl_string) assert len(items) == 1 descriptor = items[0] assert descriptor is not None assert descriptor.xml_el is not None assert getattr(descriptor, "id") == "1" assert getattr(descriptor, "name_space") == "ns" assert getattr(descriptor, "type") == "type" assert getattr(descriptor, "text") == "Text"
def test_extra_properties(self) -> None: """Test extra item properties from XML.""" didl_string = """ <DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/"> <item restricted="1"> <dc:title>Video Item Title</dc:title> <upnp:class>object.item.videoItem</upnp:class> <upnp:albumArtURI>extra_property</upnp:albumArtURI> </item> </DIDL-Lite>""" items = didl_lite.from_xml_string(didl_string) assert len(items) == 1 item = items[0] assert hasattr(item, "album_art_uri") assert getattr(item, "album_art_uri") == "extra_property" assert getattr(item, "albumArtURI") == "extra_property"
def test_container_from_xml(self) -> None: """Test container from XML.""" didl_string = """ <DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/"> <container id="0" parentID="0" restricted="1"> <dc:title>Album Container Title</dc:title> <upnp:class>object.container.album</upnp:class> <item id="1" parentID="0" restricted="1"> <dc:title>Audio Item Title</dc:title> <upnp:class>object.item.audioItem</upnp:class> <dc:language>English</dc:language> <res protocolInfo="protocol_info">url</res> </item> </container> </DIDL-Lite>""" items = didl_lite.from_xml_string(didl_string) assert len(items) == 1 container = items[0] assert container.xml_el is not None assert isinstance(container, didl_lite.Container) assert getattr(container, "title") == "Album Container Title" assert getattr(container, "upnp_class") == "object.container.album" item = container[0] assert item.xml_el is not None assert item.title == "Audio Item Title" assert item.upnp_class == "object.item.audioItem" assert item.language == "English" resources = item.res assert len(resources) == 1 resource = resources[0] assert resource.xml_el is not None assert resource.protocol_info == "protocol_info" assert resource.uri == "url" assert item.res == item.resources
def media_image_url(self): """Image url of current playing media.""" state_var = self._state_variable('AVT', 'CurrentTrackMetaData') if state_var is None: return None xml = state_var.value if not xml or xml == 'NOT_IMPLEMENTED': return None items = didl_lite.from_xml_string(xml) if not items: return None for item in items: for res in item.resources: protocol_info = res.protocol_info if protocol_info.startswith('http-get:*:image/'): return res.url return None
def test_item_property_attribute_from_xml(self) -> None: """Test item property from XML attribute.""" didl_string = """ <DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/"> <item id="0" parentID="0" restricted="1"> <dc:title>Video Item Title</dc:title> <upnp:class>object.item.videoItem</upnp:class> <upnp:genre id="genreId">Action</upnp:genre> </item> </DIDL-Lite>""" items = didl_lite.from_xml_string(didl_string) assert len(items) == 1 item = items[0] assert item is not None assert getattr(item, "genre") == "Action" assert getattr(item, "genre_id") == "genreId"
def test_descriptor_from_xml_container_item(self) -> None: """Test item descriptor in container from XML.""" didl_string = """ <DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/"> <container id="0" parentID="0" restricted="1"> <dc:title>Album Container Title</dc:title> <upnp:class>object.container.album</upnp:class> <item id="1" parentID="0" restricted="1"> <dc:title>Audio Item Title</dc:title> <upnp:class>object.item.audioItem</upnp:class> <dc:language>English</dc:language> <res protocolInfo="protocol_info">url</res> <desc id="1" nameSpace="ns" type="type">Text</desc> </item> </container> </DIDL-Lite>""" items = didl_lite.from_xml_string(didl_string) assert len(items) == 1 container = items[0] assert container is not None assert isinstance(container, didl_lite.Container) item = container[0] assert item is not None descriptor = item.descriptors[0] assert descriptor is not None assert descriptor.xml_el is not None assert descriptor.id == "1" assert descriptor.name_space == "ns" assert descriptor.type == "type" assert descriptor.text == "Text"
def test_item_set_attributes(self) -> None: """Test item attribute from XML.""" didl_string = """ <DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/"> <item restricted="1"> <dc:title>Video Item Title</dc:title> <upnp:class>object.item.videoItem</upnp:class> </item> </DIDL-Lite>""" items = didl_lite.from_xml_string(didl_string) assert len(items) == 1 item = items[0] assert getattr(item, "title") == "Video Item Title" assert hasattr(item, "rating") assert getattr(item, "rating") is None assert isinstance(item, didl_lite.VideoItem) assert len(item.res) == 0 assert item.res == item.resources
def test_item_from_xml(self) -> None: """Test item from XML.""" didl_string = """ <DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sec="http://www.sec.co.kr/"> <item id="0" parentID="0" restricted="1"> <dc:title>Audio Item Title</dc:title> <upnp:class>object.item.audioItem</upnp:class> <dc:language>English</dc:language> <res protocolInfo="protocol_info">url</res> <upnp:longDescription>Long description</upnp:longDescription> </item> </DIDL-Lite>""" items = didl_lite.from_xml_string(didl_string) assert len(items) == 1 item = items[0] assert item.xml_el is not None assert getattr(item, "title") == "Audio Item Title" assert getattr(item, "upnp_class") == "object.item.audioItem" assert getattr(item, "language") == "English" assert getattr(item, "longDescription") == "Long description" assert getattr(item, "long_description") == "Long description" assert isinstance(item, didl_lite.AudioItem) assert not hasattr(item, "non_existing") resources = item.res assert len(resources) == 1 resource = resources[0] assert resource.xml_el is not None assert resource.protocol_info == "protocol_info" assert resource.uri == "url" assert not hasattr(item, "non_existing") assert item.res == item.resources
async def _get_inputs_upnp(self): await self._get_upnp_services() content_directory = self._upnp_device.service( next(s for s in self._upnp_discovery.upnp_services if "ContentDirectory" in s)) browse = content_directory.action("Browse") filter = ( "av:BIVL,av:liveType,av:containerClass,dc:title,dc:date," "res,res@duration,res@resolution,upnp:albumArtURI," "upnp:albumArtURI@dlna:profileID,upnp:artist,upnp:album,upnp:genre" ) result = await browse.async_call( ObjectID="0", BrowseFlag="BrowseDirectChildren", Filter=filter, StartingIndex=0, RequestedCount=25, SortCriteria="", ) root_items = didl_lite.from_xml_string(result["Result"]) input_item = next( (i for i in root_items if isinstance(i, didl_lite.Container) and i.title == "Input"), None, ) result = await browse.async_call( ObjectID=input_item.id, BrowseFlag="BrowseDirectChildren", Filter=filter, StartingIndex=0, RequestedCount=25, SortCriteria="", ) av_transport = self._upnp_renderer.service( next(s for s in self._upnp_renderer.services if "AVTransport" in s)) media_info = await av_transport.action("GetMediaInfo").async_call( InstanceID=0) current_uri = media_info.get("CurrentURI") inputs = didl_lite.from_xml_string(result["Result"]) def is_input_active(input, current_uri): if not current_uri: return False # when input is switched on device, uri can have file:// format if current_uri.startswith("file://"): # UPnP 'Bluetooth AUDIO' can be file://Bluetooth # UPnP 'AUDIO' can be file://Audio return current_uri.lower() in "file://" + input.title.lower() if current_uri.startswith("local://"): # current uri can have additional query params, such as zone return input.resources[0].uri in current_uri return [ Input.make( title=i.title, uri=i.resources[0].uri, active="active" if is_input_active(i, current_uri) else "", avTransport=av_transport, uriMetadata=didl_lite.to_xml_string(i).decode("utf-8"), ) for i in inputs ]