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
+32 -1
View File
@@ -8,6 +8,7 @@ summary path and the HU overlay store through it, and migration 0101 cleaned the
import pytest
from alembic import command
from alembic.config import Config
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.db import engine
@@ -15,7 +16,8 @@ from app.models import PlexCollection, PlexItem, PlexLibrary, PlexShow
from app.plex.detail import rich_detail
from app.plex.overlay import sync_overlay
from app.plex.plaintext import plain_text
from app.plex.sync import _apply_item
from app.plex import sync
from app.plex.sync import _apply_item, _upsert_collection
HU_SUMMARY = "<p>A műsorban minden p&aacute;rosnak stoppal kell eljutnia.</p>"
@@ -29,6 +31,9 @@ HU_SUMMARY = "<p>A műsorban minden p&aacute;rosnak stoppal kell eljutnia.</p>"
("<b>Bold</b> &amp; <i>more</i>", "Bold & more"),
# Prose that only looks like markup stays as written.
("a < b and 1 <3 you", "a < b and 1 <3 you"),
# Only a reference with its semicolon is one: an ampersand in prose stays as written.
("AT&notice, R&copy and H&M", "AT&notice, R&copy and H&M"),
("&#233;t&#xE9; &copy;", "été ©"),
("Plain summary.", "Plain summary."),
(" padded ", "padded"),
("<p></p>", None),
@@ -46,6 +51,32 @@ def test_the_item_sync_stores_a_summary_as_plain_text():
assert row.summary == "A műsorban minden párosnak stoppal kell eljutnia."
def test_the_show_sync_stores_a_summary_as_plain_text(db, monkeypatch):
lib = PlexLibrary(plex_key="2", title="Shows", kind="show", enabled=True)
db.add(lib)
db.commit()
meta = {"ratingKey": "s1", "title": "Show", "summary": HU_SUMMARY}
def listing(_plex, _key, typ, progress=None):
if progress is not None:
progress["complete"] = True
return [meta] if typ == sync._TYPE_SHOW else []
monkeypatch.setattr(sync, "_paginate", listing)
sync._sync_shows(db, object(), lib, {"shows": 0, "seasons": 0, "episodes": 0})
db.commit()
show = db.execute(select(PlexShow).where(PlexShow.rating_key == "s1")).scalar_one()
assert show.summary == "A műsorban minden párosnak stoppal kell eljutnia."
def test_a_collection_stores_its_summary_as_plain_text(db):
lib = PlexLibrary(plex_key="1", title="Movies", kind="movie", enabled=True)
db.add(lib)
db.flush()
col = _upsert_collection(db, None, "c1", lib.id, {"title": "C", "summary": "<p>A &amp; B</p>"})
assert col.summary == "A & B"
def test_a_fetched_tagline_is_plain_text():
assert rich_detail({"tagline": "<i>An offer</i> &amp; more"})["tagline"] == "An offer & more"