ci(telegram): use public mhrv_rs link in main-channel post + add invite

Two related changes to the main-channel cross-post (one message per
release that points at the files channel):

1. Post-link now uses the public-username form `t.me/mhrv_rs/<msg_id>`
   instead of the private `t.me/c/<chat_id>/<msg_id>`. The latter only
   resolves for channel members; the former works for everyone, so
   recipients seeing the main-channel announcement can click through
   to a specific release post even if they're not yet subscribed.

   Wired via the existing `FILES_CHANNEL_USERNAME` workflow env var,
   now defaulting to `mhrv_rs` (the channel's public username) if the
   `vars.FILES_CHANNEL_USERNAME` repo variable is unset. Override per
   repo if the channel is renamed.

2. Channel-join links rendered in the body of the main-channel post,
   below the post-link:

       لینک کانال:
       https://t.me/mhrv_rs
       و یا: https://t.me/+R1OyoHX2boA1ZDgx

   Two forms cover the cases where one or the other is filtered:
   - `t.me/mhrv_rs` — public username form, prettier, surfaces in
     Telegram search
   - `t.me/+<hash>` — invite link, the only join path that works for
     private/restricted channels and for users whose client doesn't
     resolve public usernames cleanly

   Wired via new `FILES_CHANNEL_INVITE` env var, defaulting to the
   current invite hash; override via `vars.FILES_CHANNEL_INVITE` if
   rotated.

Per user request — not running this against v1.8.0 retroactively,
just wiring it up for the next release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
therealaleph
2026-04-28 03:30:37 +03:00
parent 0669b9310c
commit 0d54c5c6fb
2 changed files with 73 additions and 17 deletions
+57 -11
View File
@@ -339,24 +339,51 @@ def files_channel_post_link(chat_id: str, message_id: int) -> str:
def post_main_channel_pointer(
bot_token: str,
main_chat_id: str,
files_channel_link: str,
files_channel_post_link: str,
version: str,
hashtag: str,
channel_username_link: str = "",
channel_invite_link: str = "",
) -> bool:
"""Post a short cross-link to the main announcement channel pointing
at the anchor post in the files channel. Replaces the previous
behaviour of posting the universal APK + full changelog directly
to the main channel — the main channel becomes a discovery surface
while the files channel hosts the actual artifacts.
Includes channel-join links (public username + invite hash) at the
bottom so recipients who aren't yet members can subscribe before
clicking through to the specific release post.
"""
text = (
f"<b>📦 mhrv-rs v{html_escape(version)} منتشر شد</b>\n"
f"\nبرای دانلود فایل‌ها (Android، Windows، macOS، Linux و ...) "
f"به کانال فایل‌ها مراجعه کنید:\n"
f"\n👉 <a href=\"{html_escape(files_channel_link)}\">"
f"v{html_escape(version)} — همه فایل‌ها + SHA-256</a>\n"
f"\n{hashtag}"
)
parts = [
f"<b>📦 mhrv-rs v{html_escape(version)} منتشر شد</b>",
"",
f"برای دانلود فایل‌ها (Android، Windows، macOS، Linux و ...) "
f"به کانال فایل‌ها مراجعه کنید:",
"",
f"👉 <a href=\"{html_escape(files_channel_post_link)}\">"
f"v{html_escape(version)} — همه فایل‌ها + SHA-256</a>",
]
# Channel-join links. Two forms handle different states of the
# files channel: the `t.me/<username>` form works for public
# channels and is the prettier link; the `t.me/+<hash>` invite
# link works regardless of whether the channel is public, and is
# the only path in for private/restricted channels. Showing both
# is forgiving — recipients click whichever works for them.
if channel_username_link or channel_invite_link:
parts.append("")
parts.append("لینک کانال:")
if channel_username_link:
# Render as plain URL (not HTML <a>) so the text shows the
# link itself — useful when users share the message via
# screenshot or copy-paste outside Telegram, which would
# strip the <a href> wrapper.
parts.append(html_escape(channel_username_link))
if channel_invite_link:
parts.append(f"و یا: {html_escape(channel_invite_link)}")
parts.append("")
parts.append(hashtag)
text = "\n".join(parts)
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
data = urllib.parse.urlencode({
"chat_id": main_chat_id,
@@ -472,11 +499,30 @@ def main() -> int:
main_chat_id = os.environ.get("MAIN_CHAT_ID", "").strip()
if main_chat_id and announce_msg_id is not None:
link = files_channel_post_link(chat_id, announce_msg_id)
# Optional channel-join links rendered alongside the cross-link.
# `FILES_CHANNEL_USERNAME` is the public-username form (clean
# `t.me/<name>` URL — clickable for everyone). `FILES_CHANNEL_INVITE`
# is the `t.me/+<hash>` invite link, the only join path for
# private channels. Either or both can be set; both render in
# the body as separate lines.
username = os.environ.get("FILES_CHANNEL_USERNAME", "").strip().lstrip("@")
username_link = f"https://t.me/{username}" if username else ""
invite_link = os.environ.get("FILES_CHANNEL_INVITE", "").strip()
print()
print(f"posting cross-link to main channel:")
print(f" link: {link}")
print(f" post link: {link}")
if username_link:
print(f" channel username link: {username_link}")
if invite_link:
print(f" channel invite link: {invite_link}")
ok = post_main_channel_pointer(
bot_token, main_chat_id, link, args.version, args.hashtag
bot_token,
main_chat_id,
link,
args.version,
args.hashtag,
channel_username_link=username_link,
channel_invite_link=invite_link,
)
if not ok:
failures += 1
+16 -6
View File
@@ -110,12 +110,22 @@ jobs:
# APK + full changelog. Sourced from the same secret the
# legacy `telegram` job in release.yml used.
MAIN_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
# Optional: if the files channel later gets a public username,
# set the repo variable `FILES_CHANNEL_USERNAME` (without the
# `@`) so the cross-link uses the prettier `t.me/<name>/<msg>`
# form instead of `t.me/c/<id>/<msg>` (which only resolves for
# channel members).
FILES_CHANNEL_USERNAME: ${{ vars.FILES_CHANNEL_USERNAME }}
# Public-username form of the files channel link. Used for
# both (a) the post-link in the main-channel cross-post — so
# `t.me/<name>/<msg>` works for everyone, not just members
# via `t.me/c/<id>/<msg>` — and (b) one of the two
# channel-join links rendered at the bottom of the cross-post.
# Defaults to `mhrv_rs` (current public username); override via
# repo variable if the channel is renamed.
FILES_CHANNEL_USERNAME: ${{ vars.FILES_CHANNEL_USERNAME || 'mhrv_rs' }}
# `t.me/+<hash>` invite link for the files channel. Rendered
# as the second channel-join option in the main-channel
# cross-post — the only join path that works for users coming
# from outside Telegram search (private/restricted channels)
# or whose Telegram client doesn't resolve usernames cleanly.
# Override via repo variable if the channel's invite hash is
# rotated.
FILES_CHANNEL_INVITE: ${{ vars.FILES_CHANNEL_INVITE || 'https://t.me/+R1OyoHX2boA1ZDgx' }}
run: |
if [ -z "${BOT_TOKEN:-}" ]; then
echo "::error::TELEGRAM_BOT_TOKEN not set; can't publish"