fix(telegram): handle sendVoice caption-too-long by resending without caption
When TTS text exceeds Telegram's 1024-char caption limit, sendVoice throws "message caption is too long" and the entire reply (voice + text) is lost. Now catch this specific error, resend the voice note without caption, then deliver the full text as a separate message. Closes #30980 Made-with: Cursor
This commit is contained in:
committed by
Peter Steinberger
parent
a262a3ea08
commit
60f8e832e0
@@ -35,6 +35,7 @@ import type { StickerMetadata, TelegramContext } from "./types.js";
|
||||
const PARSE_ERR_RE = /can't parse entities|parse entities|find end of the entity/i;
|
||||
const EMPTY_TEXT_ERR_RE = /message text is empty/i;
|
||||
const VOICE_FORBIDDEN_RE = /VOICE_MESSAGES_FORBIDDEN/;
|
||||
const CAPTION_TOO_LONG_RE = /caption is too long/i;
|
||||
const FILE_TOO_BIG_RE = /file is too big/i;
|
||||
const TELEGRAM_MEDIA_SSRF_POLICY = {
|
||||
// Telegram file downloads should trust api.telegram.org even when DNS/proxy
|
||||
@@ -230,8 +231,6 @@ export async function deliverReplies(params: {
|
||||
markDelivered();
|
||||
} catch (voiceErr) {
|
||||
// Fall back to text if voice messages are forbidden in this chat.
|
||||
// This happens when the recipient has Telegram Premium privacy settings
|
||||
// that block voice messages (Settings > Privacy > Voice Messages).
|
||||
if (isVoiceMessagesForbidden(voiceErr)) {
|
||||
const fallbackText = reply.text;
|
||||
if (!fallbackText || !fallbackText.trim()) {
|
||||
@@ -256,7 +255,38 @@ export async function deliverReplies(params: {
|
||||
hasReplied = true;
|
||||
}
|
||||
markDelivered();
|
||||
// Skip this media item; continue with next.
|
||||
continue;
|
||||
}
|
||||
if (isCaptionTooLong(voiceErr)) {
|
||||
logVerbose(
|
||||
"telegram sendVoice caption too long; resending voice without caption + text separately",
|
||||
);
|
||||
const noCaptionParams = { ...mediaParams };
|
||||
delete noCaptionParams.caption;
|
||||
delete noCaptionParams.parse_mode;
|
||||
await withTelegramApiErrorLogging({
|
||||
operation: "sendVoice",
|
||||
runtime,
|
||||
fn: () => bot.api.sendVoice(chatId, file, { ...noCaptionParams }),
|
||||
});
|
||||
markDelivered();
|
||||
const fallbackText = reply.text;
|
||||
if (fallbackText?.trim()) {
|
||||
await sendTelegramVoiceFallbackText({
|
||||
bot,
|
||||
chatId,
|
||||
runtime,
|
||||
text: fallbackText,
|
||||
chunkText,
|
||||
replyToId: undefined,
|
||||
thread,
|
||||
linkPreview,
|
||||
replyMarkup,
|
||||
});
|
||||
}
|
||||
if (replyToMessageIdForPayload && !hasReplied) {
|
||||
hasReplied = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
throw voiceErr;
|
||||
@@ -463,6 +493,13 @@ function isVoiceMessagesForbidden(err: unknown): boolean {
|
||||
return VOICE_FORBIDDEN_RE.test(formatErrorMessage(err));
|
||||
}
|
||||
|
||||
function isCaptionTooLong(err: unknown): boolean {
|
||||
if (err instanceof GrammyError) {
|
||||
return CAPTION_TOO_LONG_RE.test(err.description);
|
||||
}
|
||||
return CAPTION_TOO_LONG_RE.test(formatErrorMessage(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the error is Telegram's "file is too big" error.
|
||||
* This happens when trying to download files >20MB via the Bot API.
|
||||
|
||||
Reference in New Issue
Block a user