All checks were successful
Java Maven 3.9.9 & JDK 26 CI/CD Pipeline / build-and-deploy (push) Successful in 3m22s
73 lines
3.0 KiB
Python
73 lines
3.0 KiB
Python
import html
|
|
import os
|
|
|
|
import httpx
|
|
|
|
from .base import ImageAttachment, Notifier
|
|
from .image_utils import (
|
|
TELEGRAM_PHOTO_MAX_BYTES,
|
|
compressed_preview,
|
|
)
|
|
|
|
|
|
def esc(value: object) -> str:
|
|
return html.escape(str(value or ""))
|
|
|
|
|
|
class TelegramNotifier(Notifier):
|
|
name = "telegram"
|
|
|
|
def __init__(self, token: str = '', chat_ids: list[str] | None = None,
|
|
token_env: str = "TELEGRAM_BOT_TOKEN",
|
|
chat_ids_env: str = "TELEGRAM_NOTIFY_CHAT_ID") -> None:
|
|
self.token = token or os.environ.get(token_env, "")
|
|
raw = ""
|
|
if chat_ids:
|
|
raw = ",".join(chat_ids)
|
|
else:
|
|
raw = os.getenv(chat_ids_env) or (
|
|
os.getenv("TELEGRAM_HOME_CHANNEL") if chat_ids_env == "TELEGRAM_NOTIFY_CHAT_ID" else ""
|
|
) or ""
|
|
# FIX vs old code: fan-out to ALL chat ids, not just split(',',1)[0].
|
|
self.chat_ids = [c.strip() for c in raw.split(",") if c.strip()]
|
|
if not self.token:
|
|
raise RuntimeError("Telegram token is not configured")
|
|
if not self.chat_ids:
|
|
raise RuntimeError("Telegram notification target is not configured")
|
|
self.proxy = os.getenv("TELEGRAM_PROXY") or None
|
|
|
|
async def send(self, title: str, text: str,
|
|
images: list[ImageAttachment] | None = None) -> None:
|
|
body = f"<b>{esc(title)}</b>\n{text}" if title else text
|
|
failures = 0
|
|
async with httpx.AsyncClient(timeout=90, proxy=self.proxy, trust_env=False) as client:
|
|
for chat_id in self.chat_ids:
|
|
try:
|
|
response = await client.post(
|
|
f"https://api.telegram.org/bot{self.token}/sendMessage",
|
|
json={"chat_id": chat_id, "text": body[:4096], "parse_mode": "HTML", "disable_web_page_preview": True},
|
|
)
|
|
ok = response.status_code < 400 and response.json().get("ok") is True
|
|
if ok:
|
|
for image in images or []:
|
|
upload = (
|
|
image if len(image.data) <= TELEGRAM_PHOTO_MAX_BYTES
|
|
else compressed_preview(image)
|
|
)
|
|
response = await client.post(
|
|
f"https://api.telegram.org/bot{self.token}/sendPhoto",
|
|
data={"chat_id": chat_id},
|
|
files={"photo": (
|
|
upload.filename, upload.data, upload.content_type
|
|
)},
|
|
)
|
|
if response.status_code >= 400 or response.json().get("ok") is not True:
|
|
ok = False
|
|
break
|
|
except Exception:
|
|
ok = False
|
|
if not ok:
|
|
failures += 1
|
|
if failures:
|
|
raise RuntimeError(f"Telegram delivery failed for {failures} target(s)")
|