From: Fabian Munkes <105975993+fmunkes@users.noreply.github.com> Date: Wed, 2 Jul 2025 10:10:02 +0000 (+0200) Subject: fix non-ascii characters in didl_lite metadata (#2256) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=3aa5d529abd9bb73c1d93d62d7d3a5528a83fc12;p=music-assistant-server.git fix non-ascii characters in didl_lite metadata (#2256) --- diff --git a/music_assistant/helpers/upnp.py b/music_assistant/helpers/upnp.py index 47041a8c..de289156 100644 --- a/music_assistant/helpers/upnp.py +++ b/music_assistant/helpers/upnp.py @@ -111,6 +111,21 @@ def get_xml_soap_set_next_url(player_media: PlayerMedia) -> tuple[str, str]: # DIDL-LITE def create_didl_metadata(media: PlayerMedia) -> str: """Create DIDL metadata string from url and PlayerMedia.""" + + def escape_metadata(data: str) -> str: + """Escape didl metadata.""" + data = xmlescape(data) + # Escape non-ascii to decimal code. + result = "" + for char in data: + unicode_code = ord(char) + if unicode_code < 128: + # ascii + result += char + else: + result += f"&#{unicode_code};" + return result + ext = media.uri.split(".")[-1].split("?")[0] image_url = media.image_url or MASS_LOGO_ONLINE if media.media_type in (MediaType.FLOW_STREAM, MediaType.RADIO) or not media.duration: @@ -119,12 +134,12 @@ def create_didl_metadata(media: PlayerMedia) -> str: return ( '' f'' - f"{xmlescape(title)}" - f"{xmlescape(image_url)}" - f"{media.uri}" + f"{escape_metadata(title)}" + f"{escape_metadata(image_url)}" + f"{escape_metadata(media.uri)}" "object.item.audioItem.audioBroadcast" f"audio/{ext}" - f'{xmlescape(media.uri)}' + f'{escape_metadata(media.uri)}' "" "" ) @@ -135,17 +150,17 @@ def create_didl_metadata(media: PlayerMedia) -> str: return ( '' f'' - f"{xmlescape(media.title or media.uri)}" - f"{xmlescape(media.artist or '')}" - f"{xmlescape(media.album or '')}" - f"{xmlescape(media.artist or '')}" + f"{escape_metadata(media.title or media.uri)}" + f"{escape_metadata(media.artist or '')}" + f"{escape_metadata(media.album or '')}" + f"{escape_metadata(media.artist or '')}" f"{int(media.duration or 0)}" - f"{xmlescape(media.queue_item_id)}" + f"{escape_metadata(media.queue_item_id)}" f"Music Assistant" - f"{xmlescape(image_url)}" + f"{escape_metadata(image_url)}" "object.item.audioItem.musicTrack" f"audio/{ext}" - f'{xmlescape(media.uri)}' + f'{escape_metadata(media.uri)}' 'RINCON_AssociatedZPUDN' "" ""