feat(ux): onboard users, expose the chat's settings, name failed posts

`/start` was "Hello!" and `/help` was the bare command list teloxide can
render — no argument syntax, no caption placeholders, no mention that
links only work in private chats. Both now carry that guidance, and the
bot's profile description / short description are set at startup so a
shared link says what the bot does.

`/settings` reports what this chat is configured to do (forward channel,
edit-before-forward, per-site formats, saved templates) to anyone in the
chat — `/bot_dict` is a raw admin-only dump. Templates can be removed
(`/remove_template`, listing the live names on a typo) and the prompt's
keyboard folds 3 per row with a cap: Telegram rejects a keyboard over 100
buttons outright, which would silently drop the whole prompt.

Inline results hand URLs to Telegram, which fetches them without any
site headers — pixiv's pximg.net answers 403 to that, so those items are
skipped instead of shipped broken. `needs_media_headers` answers that
question from the same per-site rule the downloader uses.

Dead-letter and retry notices name the failing post and the cause
(`failure_text`), since "Task failed after retries: task failed after 2
retries" said neither which link it was nor what happened.
This commit is contained in:
2026-09-20 15:57:45 +08:00
parent d6707133cc
commit 5d0acdac01
10 changed files with 448 additions and 31 deletions
+6 -1
View File
@@ -192,11 +192,16 @@ async fn dispatch_send(
log_key(url)
);
send::enqueue_retry(ctx.task_queue, *task, delay_seconds).await;
// Name the post and the wait: "queued for retry" alone left the
// user guessing which link it was and how long the wait is.
let _ = reply(
ctx.sender,
chat_id,
reply_to,
"Send failed. Task queued for retry.",
format!(
"Send failed for {} — retrying in {delay_seconds:.0}s.",
log_key(url)
),
)
.await;
}