From ec50f65f8ba627bf7be968daa5204aacf439ccdf Mon Sep 17 00:00:00 2001 From: geo-martino Date: Thu, 25 Jul 2024 16:44:51 -0400 Subject: [PATCH] fix '&' escape bug in XMLPlaylistParser --- docs/info/release-history.rst | 11 +++++++++++ musify/libraries/local/playlist/xautopf.py | 6 ++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/info/release-history.rst b/docs/info/release-history.rst index b8a5b615..b21aa428 100644 --- a/docs/info/release-history.rst +++ b/docs/info/release-history.rst @@ -31,6 +31,17 @@ Release History The format is based on `Keep a Changelog `_, and this project adheres to `Semantic Versioning `_ + +1.1.5 +===== + +Fixed +----- +* Bug in escaping of '&' characters when export :py:class:`.XAutoPF` playlists with the :py:class:`.XMLPlaylistParser`. + Was previously escaping multiple times when already escaped e.g. '&' > '&'. + Now correctly skips already occurrences of '&'. + + 1.1.4 ===== diff --git a/musify/libraries/local/playlist/xautopf.py b/musify/libraries/local/playlist/xautopf.py index b4c3c9a6..49998248 100644 --- a/musify/libraries/local/playlist/xautopf.py +++ b/musify/libraries/local/playlist/xautopf.py @@ -1,6 +1,7 @@ """ The XAutoPF implementation of a :py:class:`LocalPlaylist`. """ +import re from collections.abc import Collection, Mapping, Sequence from copy import deepcopy from dataclasses import dataclass @@ -513,12 +514,13 @@ def parse_exception_paths( include_items = tuple(items_mapped[path] for path in matcher.include if path in items_mapped) exclude_items = tuple(matched_mapped[path] for path in matcher.exclude if path in matched_mapped) + amp_pattern = re.compile('&(?!amp;)') if len(include_items) > 0: include_paths = self.path_mapper.unmap_many(include_items, check_existence=False) - self.xml_source["ExceptionsInclude"] = "|".join(include_paths).replace("&", "&") + self.xml_source["ExceptionsInclude"] = amp_pattern.sub("&", "|".join(include_paths)) if len(exclude_items) > 0: exclude_paths = self.path_mapper.unmap_many(exclude_items, check_existence=False) - self.xml_source["Exceptions"] = "|".join(exclude_paths).replace("&", "&") + self.xml_source["Exceptions"] = amp_pattern.sub("&", "|".join(exclude_paths)) def get_limiter(self) -> ItemLimiter | None: """Initialise and return a :py:class:`ItemLimiter` object from loaded XML playlist data."""