be33664be2
The daily digest is now formatted with Telegram HTML: bold section headers
with <pre>-aligned columns, colored circle emoji as status dots, a branded
header line, and a top blockquote callout (all clear vs N issues). All free
text is &/</> escaped so a stray angle bracket in a log snippet can't break
the parse and swallow the whole message. notify-telegram.sh gains an --html
flag (parse_mode=HTML) used by the digest send; plain-text callers are
unchanged. Truncation is now tag-safe in HTML mode: cut on a line boundary,
re-close an open <pre>, and use an escaped marker -- the old literal
"...<truncated>" tail would itself have 400'd the send.
Two real bugs surfaced while testing:
- pipeline-status.sh pins its own PATH, which lacked /opt/venv/bin where
beet lives, so every beet probe ("added today", "Library by format", the
mp3-now count) has been silently empty behind 2>/dev/null since the cron
migration. PATH now includes the venv; both sections show real numbers.
- strip-watermark-art.py aborted its entire weekly run when metaflac stalled
on ONE file (seen today: a healthy 190KB cover took >15s under disk
contention, TimeoutExpired killed the job). Per-file timeout is now 60s
and a timeout skips that file with a warning instead of failing the run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
87 lines
3.0 KiB
Bash
Executable File
87 lines
3.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# notify-telegram.sh — send a message to the configured Telegram chat.
|
|
# Sources credentials from $ALEMBIC_CONFIG_DIR/pipeline/telegram/notify.env (chmod 600).
|
|
#
|
|
# Usage:
|
|
# echo "single line message" | notify-telegram.sh
|
|
# notify-telegram.sh "single line message"
|
|
# notify-telegram.sh --html < ${ALEMBIC_CONFIG_DIR:-/config}/logs/STATUS.log
|
|
#
|
|
# --html sends with parse_mode=HTML for messages authored as Telegram-HTML
|
|
# (pipeline-status.sh's digest: <b>/<i>/<code>/<pre>/<blockquote>). The
|
|
# CALLER is responsible for escaping &, <, > in any free text; this script
|
|
# only guarantees the truncation below can't cut a tag in half. Without the
|
|
# flag, messages go as plain text exactly as before.
|
|
#
|
|
# Telegram messages are capped at 4096 chars. Anything longer is truncated;
|
|
# in HTML mode the cut lands on a line boundary and re-closes an open <pre>
|
|
# so the truncated message still parses (a mid-tag cut, or a bare "<" in the
|
|
# tail marker, makes the Bot API reject the ENTIRE message with a 400).
|
|
# Returns exit 0 on send-OK, non-zero otherwise.
|
|
|
|
set -euo pipefail
|
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
|
|
PARSE_MODE=""
|
|
if [[ "${1:-}" == "--html" ]]; then
|
|
PARSE_MODE="HTML"
|
|
shift
|
|
fi
|
|
|
|
CONFIG="${ALEMBIC_CONFIG_DIR:-/config}/pipeline/telegram/notify.env"
|
|
if [[ ! -f "$CONFIG" ]]; then
|
|
echo "[notify-telegram] no config at $CONFIG" >&2
|
|
exit 1
|
|
fi
|
|
# shellcheck disable=SC1090
|
|
source "$CONFIG"
|
|
: "${TG_BOT_TOKEN:?TG_BOT_TOKEN missing}"
|
|
: "${TG_CHAT_ID:?TG_CHAT_ID missing}"
|
|
|
|
# Read message from arg or stdin
|
|
if [[ $# -ge 1 ]]; then
|
|
MSG="$*"
|
|
else
|
|
MSG=$(cat)
|
|
fi
|
|
|
|
# Telegram caps at 4096 chars. Trim conservatively at 3900. Use python for
|
|
# proper UTF-8 length handling. Plain mode appends a literal marker; HTML
|
|
# mode cuts at the last newline inside the budget (our tags never span
|
|
# lines except <pre> blocks) and re-closes an unbalanced <pre>.
|
|
MSG=$(python3 -c "
|
|
import sys
|
|
s = sys.argv[1]
|
|
html = sys.argv[2] == 'HTML'
|
|
if len(s) > 3900:
|
|
s = s[:3900]
|
|
if html:
|
|
cut = s.rfind('\n')
|
|
if cut > 0:
|
|
s = s[:cut]
|
|
if s.count('<pre>') > s.count('</pre>'):
|
|
s += '</pre>'
|
|
s += '\n<i>… truncated</i>'
|
|
else:
|
|
s += '\n...(truncated)'
|
|
print(s, end='')
|
|
" "$MSG" "${PARSE_MODE:-plain}")
|
|
|
|
# Send via Bot API. Preview disabled; parse_mode only when requested so log
|
|
# content with special chars can't be misread as markup in plain sends.
|
|
# `|| true`: a curl timeout/network error must fall through to the explicit
|
|
# ok-check below (which reports "send failed" and exits 2), not abort here.
|
|
resp=$(curl -s --max-time 15 -X POST \
|
|
"https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
|
|
--data-urlencode "chat_id=${TG_CHAT_ID}" \
|
|
--data-urlencode "text=${MSG}" \
|
|
${PARSE_MODE:+--data-urlencode "parse_mode=${PARSE_MODE}"} \
|
|
--data-urlencode "disable_web_page_preview=true" || true)
|
|
|
|
ok=$(echo "$resp" | python3 -c "import sys,json;print(json.load(sys.stdin).get('ok',False))" 2>/dev/null || echo False)
|
|
if [[ "$ok" != "True" ]]; then
|
|
echo "[notify-telegram] send failed: $resp" >&2
|
|
exit 2
|
|
fi
|
|
exit 0
|