From dd61e0ebf13bf863d043b0cf27b46d3b949f9aa9 Mon Sep 17 00:00:00 2001 From: Nevo David Date: Fri, 1 Aug 2025 22:03:43 +0700 Subject: [PATCH] feat: telegram formatted text --- .../src/components/new-launch/editor.tsx | 2 +- .../src/utils/strip.html.validation.ts | 5 +- .../integrations/social/telegram.provider.ts | 24 +++++++--- package.json | 3 +- pnpm-lock.yaml | 48 +++++++++---------- 5 files changed, 46 insertions(+), 36 deletions(-) diff --git a/apps/frontend/src/components/new-launch/editor.tsx b/apps/frontend/src/components/new-launch/editor.tsx index 818012d2..333cb308 100644 --- a/apps/frontend/src/components/new-launch/editor.tsx +++ b/apps/frontend/src/components/new-launch/editor.tsx @@ -524,7 +524,7 @@ export const Editor: FC<{ editor={editorRef?.current?.editor} currentValue={props.value!} /> - {(editorType === 'markdown' || editorType === 'html') && ( + {(editorType === 'markdown' || editorType === 'html') && identifier !== 'telegram' && ( <> ') === -1 && !none) { diff --git a/libraries/nestjs-libraries/src/integrations/social/telegram.provider.ts b/libraries/nestjs-libraries/src/integrations/social/telegram.provider.ts index ff8ad4c4..22803f2e 100644 --- a/libraries/nestjs-libraries/src/integrations/social/telegram.provider.ts +++ b/libraries/nestjs-libraries/src/integrations/social/telegram.provider.ts @@ -11,6 +11,7 @@ import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.ab import mime from 'mime'; import TelegramBot from 'node-telegram-bot-api'; import { Integration } from '@prisma/client'; +import striptags from 'striptags'; const telegramBot = new TelegramBot(process.env.TELEGRAM_TOKEN!); // Added to support local storage posting @@ -23,7 +24,7 @@ export class TelegramProvider extends SocialAbstract implements SocialProvider { isBetweenSteps = false; isWeb3 = true; scopes = [] as string[]; - editor = 'markdown' as const; + editor = 'html' as const; async refreshToken(refresh_token: string): Promise { return { @@ -145,7 +146,14 @@ export class TelegramProvider extends SocialAbstract implements SocialProvider { for (const message of postDetails) { let messageId: number | null = null; const mediaFiles = message.media || []; - const text = message.message || ''; + const text = striptags(message.message || '', [ + 'u', + 'strong', + 'p', + ]) + .replace(//g, '') + .replace(/<\/strong>/g, '') + .replace(/

(.*?)<\/p>/g, '$1\n') // check if media is local to modify url const processedMedia = mediaFiles.map((media) => { let mediaUrl = media.path; @@ -176,7 +184,9 @@ export class TelegramProvider extends SocialAbstract implements SocialProvider { }); // if there's no media, bot sends a text message only if (processedMedia.length === 0) { - const response = await telegramBot.sendMessage(accessToken, text); + const response = await telegramBot.sendMessage(accessToken, text, { + parse_mode: 'HTML', + }); messageId = response.message_id; } // if there's only one media, bot sends the media with the text message as caption @@ -187,20 +197,20 @@ export class TelegramProvider extends SocialAbstract implements SocialProvider { ? await telegramBot.sendVideo( accessToken, media.media, - { caption: text, parse_mode: 'Markdown' }, + { caption: text, parse_mode: 'HTML' }, media.fileOptions ) : media.type === 'photo' ? await telegramBot.sendPhoto( accessToken, media.media, - { caption: text, parse_mode: 'Markdown' }, + { caption: text, parse_mode: 'HTML' }, media.fileOptions ) : await telegramBot.sendDocument( accessToken, media.media, - { caption: text, parse_mode: 'Markdown' }, + { caption: text, parse_mode: 'HTML' }, media.fileOptions ); messageId = response.message_id; @@ -213,7 +223,7 @@ export class TelegramProvider extends SocialAbstract implements SocialProvider { type: m.type === 'document' ? 'document' : m.type, // Documents are not allowed in media groups media: m.media, caption: i === 0 && index === 0 ? text : undefined, - parse_mode: 'Markdown' + parse_mode: 'HTML', })); const response = await telegramBot.sendMediaGroup( diff --git a/package.json b/package.json index 6d046ffe..0af0cab8 100644 --- a/package.json +++ b/package.json @@ -109,6 +109,7 @@ "@types/sha256": "^0.2.2", "@types/stripe": "^8.0.417", "@types/striptags": "^0.0.5", + "@types/turndown": "^5.0.5", "@types/yup": "^0.32.0", "@uidotdev/usehooks": "^2.4.1", "@uiw/react-md-editor": "^4.0.3", @@ -167,7 +168,6 @@ "next": "^14.2.30", "next-plausible": "^3.12.0", "node-fetch": "^3.3.2", - "node-html-markdown": "^1.3.0", "node-telegram-bot-api": "^0.66.0", "nodemailer": "^6.9.15", "nostr-tools": "^2.10.4", @@ -213,6 +213,7 @@ "tldts": "^6.1.47", "transloadit": "^3.0.2", "tslib": "^2.3.0", + "turndown": "^7.2.0", "tweetnacl": "^1.0.3", "twitter-api-v2": "^1.24.0", "twitter-text": "^3.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc4ed2d8..6dea25fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -207,6 +207,9 @@ importers: '@types/striptags': specifier: ^0.0.5 version: 0.0.5 + '@types/turndown': + specifier: ^5.0.5 + version: 5.0.5 '@types/yup': specifier: ^0.32.0 version: 0.32.0 @@ -381,9 +384,6 @@ importers: node-fetch: specifier: ^3.3.2 version: 3.3.2 - node-html-markdown: - specifier: ^1.3.0 - version: 1.3.0 node-telegram-bot-api: specifier: ^0.66.0 version: 0.66.0(request@2.88.2) @@ -519,6 +519,9 @@ importers: tslib: specifier: ^2.3.0 version: 2.8.1 + turndown: + specifier: ^7.2.0 + version: 7.2.0 tweetnacl: specifier: ^1.0.3 version: 1.0.3 @@ -2998,6 +3001,9 @@ packages: '@microsoft/tsdoc@0.15.1': resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + '@mixmark-io/domino@2.2.0': + resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} + '@modelcontextprotocol/sdk@1.15.0': resolution: {integrity: sha512-67hnl/ROKdb03Vuu0YOr+baKTvf1/5YBHBm9KnZdjdAh8hjt4FRCPD5ucwxGB237sBpzlqQsLy1PFu7z/ekZ9Q==} engines: {node: '>=18'} @@ -6396,6 +6402,9 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/turndown@5.0.5': + resolution: {integrity: sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -9729,10 +9738,6 @@ packages: hastscript@9.0.1: resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - header-case@2.0.4: resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} @@ -11908,13 +11913,6 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true - node-html-markdown@1.3.0: - resolution: {integrity: sha512-OeFi3QwC/cPjvVKZ114tzzu+YoR+v9UXW5RwSXGUqGb0qCl0DvP406tzdL7SFn8pZrMyzXoisfG2zcuF9+zw4g==} - engines: {node: '>=10.0.0'} - - node-html-parser@6.1.13: - resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} - node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -14529,6 +14527,9 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + turndown@7.2.0: + resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==} + tus-js-client@2.3.2: resolution: {integrity: sha512-5a2rm7gp+G7Z+ZB0AO4PzD/dwczB3n1fZeWO5W8AWLJ12RRk1rY4Aeb2VAYX9oKGE+/rGPrdxoFPA/vDSVKnpg==} @@ -18710,6 +18711,8 @@ snapshots: '@microsoft/tsdoc@0.15.1': {} + '@mixmark-io/domino@2.2.0': {} + '@modelcontextprotocol/sdk@1.15.0': dependencies: ajv: 6.12.6 @@ -22970,6 +22973,8 @@ snapshots: '@types/trusted-types@2.0.7': {} + '@types/turndown@5.0.5': {} + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -27597,8 +27602,6 @@ snapshots: property-information: 7.1.0 space-separated-tokens: 2.0.2 - he@1.2.0: {} - header-case@2.0.4: dependencies: capital-case: 1.0.4 @@ -30509,15 +30512,6 @@ snapshots: node-gyp-build@4.8.4: {} - node-html-markdown@1.3.0: - dependencies: - node-html-parser: 6.1.13 - - node-html-parser@6.1.13: - dependencies: - css-select: 5.2.2 - he: 1.2.0 - node-int64@0.4.0: {} node-mock-http@1.0.1: {} @@ -33683,6 +33677,10 @@ snapshots: dependencies: safe-buffer: 5.2.1 + turndown@7.2.0: + dependencies: + '@mixmark-io/domino': 2.2.0 + tus-js-client@2.3.2: dependencies: buffer-from: 1.1.2