2026-09-05 20:09:26 +08:00
|
|
|
import html
|
2024-10-14 10:03:23 +08:00
|
|
|
import json
|
2026-09-05 20:09:26 +08:00
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
|
2024-10-14 10:03:23 +08:00
|
|
|
import requests
|
|
|
|
|
|
|
|
|
|
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
|
|
|
|
|
TAG = os.getenv("TAG")
|
2025-04-18 17:50:46 +08:00
|
|
|
RUN_ID = os.getenv("RUN_ID")
|
2024-10-14 10:03:23 +08:00
|
|
|
|
2025-03-12 17:15:31 +08:00
|
|
|
IS_STABLE = "-" not in TAG
|
2024-10-14 10:03:23 +08:00
|
|
|
|
|
|
|
|
CHAT_ID = "@FlClash"
|
|
|
|
|
API_URL = f"http://localhost:8081/bot{TELEGRAM_BOT_TOKEN}/sendMediaGroup"
|
|
|
|
|
|
|
|
|
|
DIST_DIR = os.path.join(os.getcwd(), "dist")
|
2026-09-05 20:09:26 +08:00
|
|
|
# Rendered by `tool/changelog.dart render telegram`: plain bullets, already
|
|
|
|
|
# truncated to fit the caption limit. release.md carries the download table and
|
|
|
|
|
# would blow past that limit.
|
|
|
|
|
release = os.path.join(os.getcwd(), "telegram.md")
|
2024-10-14 10:03:23 +08:00
|
|
|
|
|
|
|
|
text = ""
|
|
|
|
|
|
|
|
|
|
media = []
|
|
|
|
|
files = {}
|
|
|
|
|
|
|
|
|
|
i = 1
|
2025-04-09 16:46:14 +08:00
|
|
|
|
|
|
|
|
releaseKeywords = [
|
|
|
|
|
"windows-amd64-setup",
|
|
|
|
|
"android-arm64",
|
|
|
|
|
"macos-arm64",
|
|
|
|
|
"macos-amd64"
|
|
|
|
|
]
|
|
|
|
|
|
2024-10-14 10:03:23 +08:00
|
|
|
for file in os.listdir(DIST_DIR):
|
|
|
|
|
file_path = os.path.join(DIST_DIR, file)
|
|
|
|
|
if os.path.isfile(file_path):
|
2025-04-09 16:46:14 +08:00
|
|
|
file_lower = file.lower()
|
|
|
|
|
if any(kw in file_lower for kw in releaseKeywords):
|
|
|
|
|
file_key = f"file{i}"
|
|
|
|
|
media.append({
|
|
|
|
|
"type": "document",
|
|
|
|
|
"media": f"attach://{file_key}"
|
|
|
|
|
})
|
|
|
|
|
files[file_key] = open(file_path, 'rb')
|
|
|
|
|
i += 1
|
2024-10-14 10:03:23 +08:00
|
|
|
|
|
|
|
|
if TAG:
|
2026-09-05 20:09:26 +08:00
|
|
|
text += f"\n<b>{html.escape(TAG)}</b>\n"
|
2024-10-14 10:03:23 +08:00
|
|
|
|
2025-03-12 17:15:31 +08:00
|
|
|
if IS_STABLE:
|
2024-10-14 10:03:23 +08:00
|
|
|
text += f"\nhttps://github.com/chen08209/FlClash/releases/tag/{TAG}\n"
|
2025-04-18 17:50:46 +08:00
|
|
|
else:
|
|
|
|
|
text += f"\nhttps://github.com/chen08209/FlClash/actions/runs/{RUN_ID}\n"
|
2024-10-14 10:03:23 +08:00
|
|
|
|
|
|
|
|
if os.path.exists(release):
|
|
|
|
|
text += "\n"
|
|
|
|
|
with open(release, 'r') as f:
|
|
|
|
|
text += f.read()
|
|
|
|
|
text += "\n"
|
|
|
|
|
|
|
|
|
|
if media:
|
|
|
|
|
media[-1]["caption"] = text
|
2026-09-05 20:09:26 +08:00
|
|
|
# HTML, not Markdown: the caption carries changelog entries written by
|
|
|
|
|
# whoever wrote the commit, and HTML is the one Telegram parse mode with a
|
|
|
|
|
# defined escape for them. `tool/changelog.dart render telegram` emits the
|
|
|
|
|
# matching markup.
|
|
|
|
|
media[-1]["parse_mode"] = "HTML"
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
response = requests.post(
|
|
|
|
|
API_URL,
|
|
|
|
|
data={
|
|
|
|
|
"chat_id": CHAT_ID,
|
|
|
|
|
"media": json.dumps(media)
|
|
|
|
|
},
|
|
|
|
|
files=files,
|
|
|
|
|
timeout=300
|
|
|
|
|
)
|
|
|
|
|
finally:
|
|
|
|
|
for handle in files.values():
|
|
|
|
|
handle.close()
|
|
|
|
|
|
|
|
|
|
# A rejected caption comes back as a 400 with a description, not an exception.
|
|
|
|
|
# Without this the release job stays green while the announcement never posted.
|
|
|
|
|
try:
|
|
|
|
|
payload = response.json()
|
|
|
|
|
except ValueError:
|
|
|
|
|
payload = None
|
|
|
|
|
|
|
|
|
|
print("Response JSON:", payload if payload is not None else response.text)
|
|
|
|
|
|
|
|
|
|
if not response.ok or not (payload or {}).get("ok"):
|
|
|
|
|
description = (payload or {}).get("description", response.text)
|
|
|
|
|
print(f"Telegram rejected the release post: {description}", file=sys.stderr)
|
|
|
|
|
sys.exit(1)
|