fix(notify): group counters instead of padding columns
Pushover renders the notification body in a proportional font, so the space-padded label/value columns never lined up on a phone — the body collapsed into a ragged flat list with no visual grouping. The html variant was worse: the padding sat inside the HTML, so it collapsed to a single space. Counters are now grouped two per line and joined with a middle dot, which survives any font. The body drops from 8 lines to 5 and no longer restates the outcome the title already carries. - replace _notify_row/LABEL_WIDTH/VALUE_WIDTH with _stat_row - add docs/notify-preview.py, which renders the real build_summary() output as a phone-width PNG so layout changes can be reviewed visually - tests: assert no space padding, two counters per row, and that the body does not repeat the title
This commit is contained in:
1 parent
881765cdf5
commit
b7094f728e
6 files changed
+315
-49
No files matched your search
+38
-21
@@ -108,8 +108,10 @@ def get_script_runtime(self):
|
||||
# ---------------------------------------------------------------------------
|
||||
NOTIFY_STYLES = ("plain", "html")
|
||||
DEFAULT_NOTIFY_STYLE = "plain"
|
||||
LABEL_WIDTH = 14
|
||||
VALUE_WIDTH = 4
|
||||
# Pushover renders the body in a proportional font, so space-padded columns
|
||||
# collapse into a ragged list. Rows are therefore joined with a visible
|
||||
# separator instead of being aligned with spaces.
|
||||
ROW_SEPARATOR = " \u00b7 "
|
||||
|
||||
NOTIFY_EMOJI = {
|
||||
"removed": "\U0001F5D1\uFE0F",
|
||||
@@ -211,18 +213,26 @@ def debug_torrent_list(self):
|
||||
self.tl.debug(self.torrent_list)
|
||||
|
||||
|
||||
def _notify_row(label, value, style, use_emoji, key):
|
||||
"""Render one label/value line for the chosen style."""
|
||||
emoji = NOTIFY_EMOJI.get(key, "") if use_emoji else ""
|
||||
if use_emoji:
|
||||
def _stat_row(pairs, style, use_emoji):
|
||||
"""Render one line of ``Label value`` pairs joined by a middle dot.
|
||||
|
||||
Args:
|
||||
pairs: Sequence of ``(emoji_key, label, value)`` tuples.
|
||||
style: ``"plain"`` or ``"html"``.
|
||||
use_emoji: Prefix each pair with its emoji marker.
|
||||
|
||||
Returns:
|
||||
A single line of text, e.g. ``Removed 7 \u00b7 Orphaned 4``.
|
||||
"""
|
||||
parts = []
|
||||
for key, label, value in pairs:
|
||||
emoji = NOTIFY_EMOJI.get(key, "") if use_emoji else ""
|
||||
prefix = f"{emoji} " if emoji else ""
|
||||
if style == "html":
|
||||
return f"{prefix}<b>{label}</b>: {value}"
|
||||
return f"{prefix}{label}: {value}"
|
||||
if style == "html":
|
||||
pad = " " * max(LABEL_WIDTH - len(label), 1)
|
||||
return f"<b>{label}</b>{pad}{value:>{VALUE_WIDTH}}"
|
||||
return f"{label:<{LABEL_WIDTH}}{value:>{VALUE_WIDTH}}"
|
||||
parts.append(f"{prefix}<b>{label}</b> {value}")
|
||||
else:
|
||||
parts.append(f"{prefix}{label} {value}")
|
||||
return ROW_SEPARATOR.join(parts)
|
||||
|
||||
|
||||
def build_summary(self, style=DEFAULT_NOTIFY_STYLE, use_emoji=False,
|
||||
@@ -230,10 +240,12 @@ def build_summary(self, style=DEFAULT_NOTIFY_STYLE, use_emoji=False,
|
||||
"""Build the ``(title, body)`` pair used by every notifier.
|
||||
|
||||
Result-first layout: the title states what happened, the body gives the
|
||||
scanned total, the actionable counters, then the tracker split.
|
||||
scanned total, the actionable counters, then the tracker split. Counters
|
||||
are grouped two-per-line and separated by a middle dot, because Pushover
|
||||
renders a proportional font and space-padded columns do not line up.
|
||||
|
||||
Args:
|
||||
style: ``"plain"`` for aligned text, ``"html"`` for Pushover HTML.
|
||||
style: ``"plain"`` for grouped text, ``"html"`` for Pushover HTML.
|
||||
use_emoji: Prefix each row with an emoji marker.
|
||||
include_hostname: Add a ``Host:`` line above the summary.
|
||||
|
||||
@@ -275,14 +287,19 @@ def build_summary(self, style=DEFAULT_NOTIFY_STYLE, use_emoji=False,
|
||||
lines.append("")
|
||||
|
||||
removed_label = "Removed" if delete_enabled else "Would remove"
|
||||
lines.append(_notify_row(removed_label, removed, style, use_emoji, "removed"))
|
||||
lines.append(_notify_row("Orphaned", stats["orphaned"], style, use_emoji, "orphaned"))
|
||||
lines.append(_notify_row("Ignored", stats["ignored"], style, use_emoji, "ignored"))
|
||||
lines.append(_notify_row("Premature", stats["premature"], style, use_emoji, "premature"))
|
||||
lines.append(_stat_row([
|
||||
("removed", removed_label, removed),
|
||||
("orphaned", "Orphaned", stats["orphaned"]),
|
||||
], style, use_emoji))
|
||||
lines.append(_stat_row([
|
||||
("ignored", "Ignored", stats["ignored"]),
|
||||
("premature", "Premature", stats["premature"]),
|
||||
], style, use_emoji))
|
||||
lines.append("")
|
||||
lines.append(_notify_row("Protected", stats["protected"], style, use_emoji, "protected"))
|
||||
lines.append(_notify_row("Non-protected", stats["non_protected"], style,
|
||||
use_emoji, "non_protected"))
|
||||
lines.append(_stat_row([
|
||||
("protected", "Protected", stats["protected"]),
|
||||
("non_protected", "Non-protected", stats["non_protected"]),
|
||||
], style, use_emoji))
|
||||
|
||||
return title, "\n".join(lines)
|
||||
|
||||
|
||||
Reference in new issue
Block a user