import datetime
from typing import TYPE_CHECKING
+from xml.sax.saxutils import escape as xmlescape
from music_assistant_models.enums import MediaType
return (
'<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/">'
f'<item id="flowmode" parentID="0" restricted="1">'
- f"<dc:title>{escape_string(title)}</dc:title>"
- f"<upnp:albumArtURI>{escape_string(image_url)}</upnp:albumArtURI>"
+ f"<dc:title>{xmlescape(title)}</dc:title>"
+ f"<upnp:albumArtURI>{xmlescape(image_url)}</upnp:albumArtURI>"
f"<dc:queueItemId>{media.uri}</dc:queueItemId>"
"<upnp:class>object.item.audioItem.audioBroadcast</upnp:class>"
f"<upnp:mimeType>audio/{ext}</upnp:mimeType>"
- f'<res protocolInfo="http-get:*:audio/{ext}:DLNA.ORG_PN={ext.upper()};DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000">{escape_string(media.uri)}</res>'
+ f'<res protocolInfo="http-get:*:audio/{ext}:DLNA.ORG_PN={ext.upper()};DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000">{xmlescape(media.uri)}</res>'
"</item>"
"</DIDL-Lite>"
)
duration_str = str(datetime.timedelta(seconds=media.duration or 0)) + ".000"
+
return (
'<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/">'
- f'<item id="{media.queue_item_id or media.uri}" restricted="true">'
- f"<dc:title>{escape_string(media.title or media.uri)}</dc:title>"
- f"<dc:creator>{escape_string(media.artist or '')}</dc:creator>"
- f"<upnp:album>{escape_string(media.album or '')}</upnp:album>"
- f"<upnp:artist>{escape_string(media.artist or '')}</upnp:artist>"
+ f'<item id="{media.queue_item_id or xmlescape(media.uri)}" restricted="true" parentID="{media.queue_id or ""}">'
+ f"<dc:title>{xmlescape(media.title or media.uri)}</dc:title>"
+ f"<dc:creator>{xmlescape(media.artist or '')}</dc:creator>"
+ f"<upnp:album>{xmlescape(media.album or '')}</upnp:album>"
+ f"<upnp:artist>{xmlescape(media.artist or '')}</upnp:artist>"
f"<upnp:duration>{int(media.duration or 0)}</upnp:duration>"
- f"<dc:queueItemId>{media.uri}</dc:queueItemId>"
+ f"<dc:queueItemId>{xmlescape(media.queue_item_id)}</dc:queueItemId>"
f"<dc:description>Music Assistant</dc:description>"
- f"<upnp:albumArtURI>{escape_string(image_url)}</upnp:albumArtURI>"
+ f"<upnp:albumArtURI>{xmlescape(image_url)}</upnp:albumArtURI>"
"<upnp:class>object.item.audioItem.musicTrack</upnp:class>"
f"<upnp:mimeType>audio/{ext}</upnp:mimeType>"
- f'<res duration="{duration_str}" protocolInfo="http-get:*:audio/{ext}:DLNA.ORG_PN={ext.upper()};DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000">{escape_string(media.uri)}</res>'
+ f'<res duration="{duration_str}" protocolInfo="http-get:*:audio/{ext}:DLNA.ORG_PN={ext.upper()};DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=0d500000000000000000000000000000">{xmlescape(media.uri)}</res>'
+ '<desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">RINCON_AssociatedZPUDN</desc>'
"</item>"
"</DIDL-Lite>"
)
-def escape_string(data: str) -> str:
- """Create DIDL-safe string."""
- data = data.replace("&", "&")
- # data = data.replace("?", "?")
- data = data.replace(">", ">")
- return data.replace("<", "<")
+def create_didl_metadata_str(media: PlayerMedia) -> str:
+ """Create (xml-escaped) DIDL metadata string from url and PlayerMedia."""
+ return xmlescape(create_didl_metadata(media))