From 51b69fd0fab7252f44814a93c93c9383436ad24b Mon Sep 17 00:00:00 2001 From: MicroBlock Date: Sat, 18 May 2024 01:06:34 +0800 Subject: [PATCH 1/3] feat(telegram): attempt to reuse fileid if possible --- adapters/telegram/src/bot.ts | 29 +++++-- adapters/telegram/src/message.ts | 132 ++++++++++++++++++++++--------- 2 files changed, 118 insertions(+), 43 deletions(-) diff --git a/adapters/telegram/src/bot.ts b/adapters/telegram/src/bot.ts index 1fecb8bf..ba894d7a 100644 --- a/adapters/telegram/src/bot.ts +++ b/adapters/telegram/src/bot.ts @@ -56,11 +56,19 @@ export class TelegramBot { - const { data, mime } = await this.$getFile(ctx.params.file) - ctx.set('content-type', mime) - ctx.body = Buffer.from(data) - }) + ctx.get('server') + .get(route + '/tg-fileid/:file+', async ctx => { + const file = await this.internal.getFile({ file_id: ctx.params.file }) + const { data, mime } = await this.$getFile(file.file_path) + ctx.set('content-type', mime) + ctx.set('content-disposition', `inline; filename="${file.file_path}"`) + ctx.body = Buffer.from(data) + }) + .get(route + '/:file+', async ctx => { + const { data, mime } = await this.$getFile(ctx.params.file) + ctx.set('content-type', mime) + ctx.body = Buffer.from(data) + }) } } @@ -152,8 +160,16 @@ export class TelegramBot extends Message } async flush() { - if (this.payload.caption || this.asset.length > 0) { + const send = async ({ + reuseFileId + }) => { + const results = [] + const payload = JSON.parse(JSON.stringify(this.payload)) + let rows = this.rows + + this.trimButtons() + if (this.asset.length > 0) { const files: { filename: string @@ -40,6 +48,7 @@ export class TelegramMessageEncoder extends Message mime: string type: string element: Element + fileid?: string }[] = [] const typeMap = { @@ -52,6 +61,23 @@ export class TelegramMessageEncoder extends Message let i = 0 for (const element of this.asset) { + if (reuseFileId) { + const url = element.attrs.src || element.attrs.url + const hash = url.slice(url.lastIndexOf('#') + 1) + const fileid = /^fileid="(.*?)"$/.exec(hash)?.[1] || /\/tg\-fileid\/(.*)/.exec(url)?.[1] + if (fileid) { + this.session.bot.logger.debug('try to reuse fileid', fileid) + files.push({ + filename: (i++).toString(), + data: null, + mime: 'application/octet-stream', + type: typeMap[element.type] ?? element.type, + fileid, + element + }) + continue + } + } const { filename, data, mime } = await this.bot.ctx.http.file(element.attrs.src || element.attrs.url, element.attrs) files.push({ filename: (i++) + filename, @@ -75,8 +101,8 @@ export class TelegramMessageEncoder extends Message } if (files.length > 1) { - inputFiles[0].caption = this.payload.caption - inputFiles[0].parse_mode = this.payload.parse_mode + inputFiles[0].caption = payload.caption + inputFiles[0].parse_mode = payload.parse_mode const form = new FormData() @@ -91,7 +117,8 @@ export class TelegramMessageEncoder extends Message } for (const { filename, data, mime } of files) { - form.append(filename, new Blob([data], { type: mime }), filename) + if (data) + form.append(filename, new Blob([data], { type: mime }), filename) } // @ts-ignore @@ -99,28 +126,28 @@ export class TelegramMessageEncoder extends Message for (const x of result) { await this.addResult(x) } - if (this.rows.length > 0 && this.rows[0].length > 0) { + if (rows.length > 0 && rows[0].length > 0) { const result2 = await this.bot.internal.sendMessage({ - chat_id: this.payload.chat_id, - text: this.payload.caption, - parse_mode: this.payload.parse_mode, + chat_id: payload.chat_id, + text: payload.caption, + parse_mode: payload.parse_mode, reply_to_message_id: result[0].message_id, - message_thread_id: this.payload.message_thread_id, + message_thread_id: payload.message_thread_id, disable_web_page_preview: !this.options.linkPreview, reply_markup: { - inline_keyboard: this.rows, + inline_keyboard: rows, }, }) - await this.addResult(result2) - delete this.payload.reply_to_message_id - this.payload.caption = '' - this.rows = [] + results.push(result2) + delete payload.reply_to_message_id + payload.caption = '' + rows = [] } - delete this.payload.reply_to_message_id - this.payload.caption = '' - this.rows = [] + delete payload.reply_to_message_id + payload.caption = '' + rows = [] } else { const sendMap = [ ['audio', ['sendAudio', 'audio']], @@ -135,38 +162,69 @@ export class TelegramMessageEncoder extends Message const [, [method, dataKey]] = sendMap.find(([key]) => files[0].type.startsWith(key)) || [] const formData = new FormData() - formData.append('chat_id', this.payload.chat_id) - formData.append('caption', this.payload.caption) - formData.append('parse_mode', this.payload.parse_mode) - formData.append('reply_to_message_id', this.payload.reply_to_message_id) - formData.append('message_thread_id', this.payload.message_thread_id) + formData.append('chat_id', payload.chat_id) + formData.append('caption', payload.caption) + formData.append('parse_mode', payload.parse_mode) + formData.append('reply_to_message_id', payload.reply_to_message_id) + formData.append('message_thread_id', payload.message_thread_id) formData.append('has_spoiler', files[0].element.attrs.spoiler ? 'true' : 'false') - formData.append(dataKey, 'attach://' + files[0].filename) - formData.append(files[0].filename, new Blob([files[0].data], { type: files[0].mime }), files[0].filename) + formData.append(dataKey, files[0].fileid ? files[0].fileid : 'attach://' + files[0].filename) + if (files[0].data) + formData.append(files[0].filename, new Blob([files[0].data], { type: files[0].mime }), files[0].filename) // @ts-ignore const result = await this.bot.internal[method](formData) - await this.addResult(result) - this.payload.caption = '' - this.rows = [] - delete this.payload.reply_to_message_id + results.push(result) + payload.caption = '' + rows = [] + delete payload.reply_to_message_id } } else { const result = await this.bot.internal.sendMessage({ - chat_id: this.payload.chat_id, - text: this.payload.caption, - parse_mode: this.payload.parse_mode, - reply_to_message_id: this.payload.reply_to_message_id, - message_thread_id: this.payload.message_thread_id, + chat_id: payload.chat_id, + text: payload.caption, + parse_mode: payload.parse_mode, + reply_to_message_id: payload.reply_to_message_id, + message_thread_id: payload.message_thread_id, disable_web_page_preview: !this.options.linkPreview, reply_markup: { - inline_keyboard: this.rows, + inline_keyboard: rows, }, }) + results.push(result) + delete payload.reply_to_message_id + payload.caption = '' + rows = [] + } + + delete this.payload.reply_to_message_id + this.payload.caption = '' + this.rows = [] + this.asset = [] + + return results + } + + if (this.payload.caption || this.asset.length > 0) { + let res: unknown[] + + if (this.session.bot.config.files.reuseFileId) { + try { + res = await send({ reuseFileId: true }) + } catch (e) { + if (e.message.includes('Telegram API error 400.')) { + res = await send({ reuseFileId: false }) + } + else { + throw e + } + } + } else { + res = await send({ reuseFileId: false }) + } + + for (const result of res) { await this.addResult(result) - delete this.payload.reply_to_message_id - this.payload.caption = '' - this.rows = [] } } } From 60e37a7806009ceae3917e888f6bd6f394aa6290 Mon Sep 17 00:00:00 2001 From: MicroBlock Date: Sat, 18 May 2024 01:12:28 +0800 Subject: [PATCH 2/3] fix: config --- adapters/telegram/src/message.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/adapters/telegram/src/message.ts b/adapters/telegram/src/message.ts index a01dcefc..a34240ed 100644 --- a/adapters/telegram/src/message.ts +++ b/adapters/telegram/src/message.ts @@ -207,8 +207,7 @@ export class TelegramMessageEncoder extends Message if (this.payload.caption || this.asset.length > 0) { let res: unknown[] - - if (this.session.bot.config.files.reuseFileId) { + if (this.session.bot.config.files.reuseFileid) { try { res = await send({ reuseFileId: true }) } catch (e) { From 65290633f0031b6aaa0e5f4d96cf9440bfda551c Mon Sep 17 00:00:00 2001 From: MicroBlock Date: Sat, 18 May 2024 01:19:39 +0800 Subject: [PATCH 3/3] fix: log --- adapters/telegram/src/message.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapters/telegram/src/message.ts b/adapters/telegram/src/message.ts index a34240ed..b62dab40 100644 --- a/adapters/telegram/src/message.ts +++ b/adapters/telegram/src/message.ts @@ -66,7 +66,7 @@ export class TelegramMessageEncoder extends Message const hash = url.slice(url.lastIndexOf('#') + 1) const fileid = /^fileid="(.*?)"$/.exec(hash)?.[1] || /\/tg\-fileid\/(.*)/.exec(url)?.[1] if (fileid) { - this.session.bot.logger.debug('try to reuse fileid', fileid) + this.session.bot.logger.debug('trying to reuse fileid', fileid) files.push({ filename: (i++).toString(), data: null,