mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 07:07:39 +00:00
feat: Implement Telegram video note support with tests and docs (#12408)
* feat: Implement Telegram video note support with tests and docs * fixing lint * feat: add doctor-state-integrity command, Telegram messaging, and PowerShell Docker setup scripts. * Update src/telegram/send.video-note.test.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: Set video note follow-up text to undefined for empty input and adjust caption test expectation. * test: add assertion for `sendMessage` with reply markup and HTML parse mode in `send.video-note` test. * docs: add changelog entry for Telegram video notes --------- Co-authored-by: Evgenii Utkin <thewulf7@gmail.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: CLAWDINATOR Bot <clawdinator[bot]@users.noreply.github.com>
This commit is contained in:
@@ -42,6 +42,8 @@ type TelegramSendOpts = {
|
||||
plainText?: string;
|
||||
/** Send audio as voice message (voice bubble) instead of audio file. Defaults to false. */
|
||||
asVoice?: boolean;
|
||||
/** Send video as video note (voice bubble) instead of regular video. Defaults to false. */
|
||||
asVideoNote?: boolean;
|
||||
/** Send message silently (no notification). Defaults to false. */
|
||||
silent?: boolean;
|
||||
/** Message ID to reply to (for threading) */
|
||||
@@ -387,9 +389,20 @@ export async function sendMessageTelegram(
|
||||
contentType: media.contentType,
|
||||
fileName: media.fileName,
|
||||
});
|
||||
const isVideoNote = kind === "video" && opts.asVideoNote === true;
|
||||
const fileName = media.fileName ?? (isGif ? "animation.gif" : inferFilename(kind)) ?? "file";
|
||||
const file = new InputFile(media.buffer, fileName);
|
||||
const { caption, followUpText } = splitTelegramCaption(text);
|
||||
let caption: string | undefined;
|
||||
let followUpText: string | undefined;
|
||||
|
||||
if (isVideoNote) {
|
||||
caption = undefined;
|
||||
followUpText = text.trim() ? text : undefined;
|
||||
} else {
|
||||
const split = splitTelegramCaption(text);
|
||||
caption = split.caption;
|
||||
followUpText = split.followUpText;
|
||||
}
|
||||
const htmlCaption = caption ? renderHtmlText(caption) : undefined;
|
||||
// If text exceeds Telegram's caption limit, send media without caption
|
||||
// then send text as a separate follow-up message.
|
||||
@@ -401,14 +414,14 @@ export async function sendMessageTelegram(
|
||||
...(!needsSeparateText && replyMarkup ? { reply_markup: replyMarkup } : {}),
|
||||
};
|
||||
const mediaParams = {
|
||||
caption: htmlCaption,
|
||||
...(htmlCaption ? { parse_mode: "HTML" as const } : {}),
|
||||
...(htmlCaption ? { caption: htmlCaption, parse_mode: "HTML" as const } : {}),
|
||||
...baseMediaParams,
|
||||
...(opts.silent === true ? { disable_notification: true } : {}),
|
||||
};
|
||||
let result:
|
||||
| Awaited<ReturnType<typeof api.sendPhoto>>
|
||||
| Awaited<ReturnType<typeof api.sendVideo>>
|
||||
| Awaited<ReturnType<typeof api.sendVideoNote>>
|
||||
| Awaited<ReturnType<typeof api.sendAudio>>
|
||||
| Awaited<ReturnType<typeof api.sendVoice>>
|
||||
| Awaited<ReturnType<typeof api.sendAnimation>>
|
||||
@@ -440,14 +453,37 @@ export async function sendMessageTelegram(
|
||||
}),
|
||||
);
|
||||
} else if (kind === "video") {
|
||||
result = await sendWithThreadFallback(mediaParams, "video", async (effectiveParams, label) =>
|
||||
requestWithDiag(
|
||||
() => api.sendVideo(chatId, file, effectiveParams as Parameters<typeof api.sendVideo>[2]),
|
||||
label,
|
||||
).catch((err) => {
|
||||
throw wrapChatNotFound(err);
|
||||
}),
|
||||
);
|
||||
if (isVideoNote) {
|
||||
result = await sendWithThreadFallback(
|
||||
mediaParams,
|
||||
"video_note",
|
||||
async (effectiveParams, label) =>
|
||||
requestWithDiag(
|
||||
() =>
|
||||
api.sendVideoNote(
|
||||
chatId,
|
||||
file,
|
||||
effectiveParams as Parameters<typeof api.sendVideoNote>[2],
|
||||
),
|
||||
label,
|
||||
).catch((err) => {
|
||||
throw wrapChatNotFound(err);
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
result = await sendWithThreadFallback(
|
||||
mediaParams,
|
||||
"video",
|
||||
async (effectiveParams, label) =>
|
||||
requestWithDiag(
|
||||
() =>
|
||||
api.sendVideo(chatId, file, effectiveParams as Parameters<typeof api.sendVideo>[2]),
|
||||
label,
|
||||
).catch((err) => {
|
||||
throw wrapChatNotFound(err);
|
||||
}),
|
||||
);
|
||||
}
|
||||
} else if (kind === "audio") {
|
||||
const { useVoice } = resolveTelegramVoiceSend({
|
||||
wantsVoice: opts.asVoice === true, // default false (backward compatible)
|
||||
|
||||
Reference in New Issue
Block a user