"""Plex summaries and taglines as plain text Revision ID: 0101_plex_text_plain Revises: 0100_drop_plex_item_markers Create Date: 2026-10-08 Some Plex agents write a summary as HTML (`

…

`, `á`), and the app showed the tags as text. The sync now stores every summary and tagline through `plain_text` (app/plex/plaintext.py); this cleans the rows it wrote before, through the same function, so nothing waits for a full resync. """ import sqlalchemy as sa from alembic import op from app.plex.plaintext import plain_text revision: str = "0101_plex_text_plain" down_revision: str | None = "0100_drop_plex_item_markers" branch_labels: str | None = None depends_on: str | None = None _COLUMNS = { "plex_items": ("summary", "summary_hu", "tagline", "tagline_hu"), "plex_shows": ("summary", "summary_hu", "tagline", "tagline_hu"), "plex_collections": ("summary",), } def upgrade() -> None: conn = op.get_bind() for table, columns in _COLUMNS.items(): for col in columns: rows = conn.execute( sa.text(f"SELECT id, {col} FROM {table} WHERE {col} ~ '[<&]'") ).fetchall() updates = [ {"id": rid, "v": clean} for rid, value in rows if (clean := plain_text(value)) != value ] if updates: conn.execute(sa.text(f"UPDATE {table} SET {col} = :v WHERE id = :id"), updates) def downgrade() -> None: pass # the markup is not wanted back; the next sync would clean it again