fix: render Telegram media captions

This commit is contained in:
Peter Steinberger
2026-01-24 03:39:21 +00:00
parent d57cb2e1a8
commit de2d986008
10 changed files with 176 additions and 80 deletions

View File

@@ -74,4 +74,38 @@ describe("deliverReplies", () => {
expect(sendVoice).toHaveBeenCalledTimes(1);
expect(events).toEqual(["recordVoice", "sendVoice"]);
});
it("renders markdown in media captions", async () => {
const runtime = { error: vi.fn(), log: vi.fn() };
const sendPhoto = vi.fn().mockResolvedValue({
message_id: 2,
chat: { id: "123" },
});
const bot = { api: { sendPhoto } } as unknown as Bot;
loadWebMedia.mockResolvedValueOnce({
buffer: Buffer.from("image"),
contentType: "image/jpeg",
fileName: "photo.jpg",
});
await deliverReplies({
replies: [{ mediaUrl: "https://example.com/photo.jpg", text: "hi **boss**" }],
chatId: "123",
token: "tok",
runtime,
bot,
replyToMode: "off",
textLimit: 4000,
});
expect(sendPhoto).toHaveBeenCalledWith(
"123",
expect.anything(),
expect.objectContaining({
caption: "hi <b>boss</b>",
parse_mode: "HTML",
}),
);
});
});

View File

@@ -1,5 +1,9 @@
import { type Bot, InputFile } from "grammy";
import { markdownToTelegramChunks, markdownToTelegramHtml } from "../format.js";
import {
markdownToTelegramChunks,
markdownToTelegramHtml,
renderTelegramHtmlText,
} from "../format.js";
import { splitTelegramCaption } from "../caption.js";
import type { ReplyPayload } from "../../auto-reply/types.js";
import type { ReplyToMode } from "../../config/config.js";
@@ -87,6 +91,9 @@ export async function deliverReplies(params: {
const { caption, followUpText } = splitTelegramCaption(
isFirstMedia ? (reply.text ?? undefined) : undefined,
);
const htmlCaption = caption
? renderTelegramHtmlText(caption, { tableMode: params.tableMode })
: undefined;
if (followUpText) {
pendingFollowUpText = followUpText;
}
@@ -94,8 +101,9 @@ export async function deliverReplies(params: {
const replyToMessageId =
replyToId && (replyToMode === "all" || !hasReplied) ? replyToId : undefined;
const mediaParams: Record<string, unknown> = {
caption,
caption: htmlCaption,
reply_to_message_id: replyToMessageId,
...(htmlCaption ? { parse_mode: "HTML" } : {}),
};
if (threadParams) {
mediaParams.message_thread_id = threadParams.message_thread_id;
@@ -149,14 +157,12 @@ export async function deliverReplies(params: {
for (const chunk of chunks) {
const replyToMessageIdFollowup =
replyToId && (replyToMode === "all" || !hasReplied) ? replyToId : undefined;
await bot.api.sendMessage(
chatId,
chunk.text,
buildTelegramSendParams({
replyToMessageId: replyToMessageIdFollowup,
messageThreadId,
}),
);
await sendTelegramText(bot, chatId, chunk.html, runtime, {
replyToMessageId: replyToMessageIdFollowup,
messageThreadId,
textMode: "html",
plainText: chunk.text,
});
if (replyToId && !hasReplied) {
hasReplied = true;
}