diff --git a/lib/notification/adapter/telegram.js b/lib/notification/adapter/telegram.js index d687028..ee1aad5 100644 --- a/lib/notification/adapter/telegram.js +++ b/lib/notification/adapter/telegram.js @@ -105,6 +105,32 @@ function buildText(jobName, serviceName, o) { ); } +/** + * Build a plain text Telegram photo caption (max 4096 characters). + * @param {string} jobName + * @param {string} serviceName + * @param {Object} o - Listing object + * @returns {string} + */ +function buildCaptionPlain(jobName, serviceName, o) { + const title = shorten((o.title || '').replace(/\*/g, ''), 90); + const meta = [o.address, o.price, o.size].filter(Boolean).join(' | '); + return `${jobName} (${serviceName})\n${title}\n${meta}\n\n${o.link || ''}`.slice(0, 4096); +} + +/** + * Build a plain text Telegram message. + * @param {string} jobName + * @param {string} serviceName + * @param {Object} o - Listing object + * @returns {string} + */ +function buildTextPlain(jobName, serviceName, o) { + const title = shorten((o.title || '').replace(/\*/g, ''), 90); + const meta = [o.address, o.price, o.size].filter(Boolean).join(' | '); + return `${jobName} (${serviceName})\n${title}\n${o.link || ''}\n${meta}`; +} + /** * Send new listings to Telegram. * - Respects per-chat Telegram rate limits using a lightweight throttle cache. @@ -122,7 +148,7 @@ export const send = ({ serviceName, newListings = [], notificationConfig, jobKey if (!adapterCfg || !adapterCfg.fields) { throw new Error(`Telegram adapter configuration missing for job '${jobKey || ''}'`); } - const { token, chatId, messageThreadId } = adapterCfg.fields; + const { token, chatId, messageThreadId, plainText } = adapterCfg.fields; if (!token || !chatId) { throw new Error("Telegram 'token' and 'chatId' must be provided in notification config"); } @@ -163,8 +189,8 @@ export const send = ({ serviceName, newListings = [], notificationConfig, jobKey const img = normalizeImageUrl(o.image); const textPayload = { chat_id: chatId, - text: buildText(jobName, serviceName, o), - parse_mode: 'HTML', + text: plainText ? buildTextPlain(jobName, serviceName, o) : buildText(jobName, serviceName, o), + ...(plainText ? {} : { parse_mode: 'HTML' }), disable_web_page_preview: true, ...(message_thread_id ? { message_thread_id } : {}), }; @@ -178,8 +204,8 @@ export const send = ({ serviceName, newListings = [], notificationConfig, jobKey return await throttledCall('sendPhoto', { chat_id: chatId, photo: img, - caption: buildCaption(jobName, serviceName, o), - parse_mode: 'HTML', + caption: plainText ? buildCaptionPlain(jobName, serviceName, o) : buildCaption(jobName, serviceName, o), + ...(plainText ? {} : { parse_mode: 'HTML' }), ...(message_thread_id ? { message_thread_id } : {}), }).catch(async (e) => { logger.error(`Error sending photo to Telegram and use a fallback: ${e.message}`); @@ -220,5 +246,11 @@ export const config = { description: 'Optional: The topic/thread id within a supergroup to post into (Telegram message_thread_id). Provide a positive integer.', }, + plainText: { + type: 'boolean', + optional: true, + label: 'Send as plain text', + description: 'Send messages as plain text instead of HTML formatted.', + }, }, }; diff --git a/ui/src/views/jobs/mutation/components/notificationAdapter/NotificationAdapterMutator.jsx b/ui/src/views/jobs/mutation/components/notificationAdapter/NotificationAdapterMutator.jsx index ad432d0..581f8d6 100644 --- a/ui/src/views/jobs/mutation/components/notificationAdapter/NotificationAdapterMutator.jsx +++ b/ui/src/views/jobs/mutation/components/notificationAdapter/NotificationAdapterMutator.jsx @@ -156,14 +156,21 @@ export default function NotificationAdapterMutator({ return (