fix(plex): plain text decodes only well-formed character references

html.unescape also decodes the legacy forms without a semicolon, so prose like
"AT&notice" came out as "AT¬ice". The show and collection sync paths are
now tested too.
This commit is contained in:
2026-10-09 22:01:27 +02:00
parent 568bf93510
commit 76738f8ea9
2 changed files with 37 additions and 2 deletions
+5 -1
View File
@@ -17,6 +17,10 @@ _BLOCK = re.compile(r"</?(?:p|div|li|ul|ol|h[1-6]|blockquote)\b[^>]*>", re.IGNOR
_TAG = re.compile(r"</?[a-zA-Z][^>]*>")
_BLANKS = re.compile(r"[ \t]*\n[ \t]*\n\s*")
# A well-formed character reference only. `html.unescape` alone also decodes the legacy forms that
# have no semicolon, so prose like "AT&notice" or "R&copy" came out as "AT¬ice" and "R©".
_REF = re.compile(r"&(?:#[0-9]+|#[xX][0-9a-fA-F]+|[A-Za-z][A-Za-z0-9]*);")
def plain_text(value: str | None) -> str | None:
"""`value` with its markup gone: line breaks kept as newlines, paragraphs as a blank line,
@@ -27,6 +31,6 @@ def plain_text(value: str | None) -> str | None:
value = _BREAK.sub("\n", value)
value = _BLOCK.sub("\n\n", value)
value = _TAG.sub("", value)
value = html.unescape(value)
value = _REF.sub(lambda m: html.unescape(m.group()), value)
value = _BLANKS.sub("\n\n", value)
return value.strip() or None