如何判断Telegram Webhook接收的媒体组事件是否为最后一个?
Telegram机器人转发相册媒体组的实现困境
背景
用Google Apps Script开发Telegram聊天机器人,已配置Webhook接收事件,无法使用logger.log输出日志,因此通过Telegram API的sendMessage方法记录事件,用doPost处理请求。需求是实现机器人转发群组中上传的相册形式照片组,但在使用Telegram API的sendMediaGroup方法时遇到问题。
核心问题
sendMediaGroup需要传入chat_id和media参数,其中media是InputMediaPhoto(对应照片场景)组成的数组。但Telegram API在接收相册时,会返回与照片数量相等的独立事件——每个事件包含相同的media_group_id,但仅携带单张照片的属性,而非包含完整媒体组的单个事件。因此需要逐个从事件中提取InputMediaPhoto存入数组,但无法判断当前事件是否为该媒体组的最后一个,导致无法确定何时调用sendMediaGroup执行转发。
现有代码框架
// 声明bot token、设置webhook、声明myID为机器人ID // 声明sendMessage、sendMediaGroup等函数 // 主逻辑通过doPost响应事件 var cache = CacheService.getScriptCache(); var msgIDstring = cache.get("msgID"); var mediastring = cache.get("mymedia"); if (mediastring == null){ var media = [] } else{ var media = JSON.parse(mediastring); } function doPost(e) { let update = JSON.parse(e.postData.contents); let chat_id = update.message.chat.id; // 群组chat id sendMessage(myID, JSON.stringify(update), 'HTML'); if (update.message.media_group_id == null) { // 处理其他逻辑 } else { if (msgIDstring == null){ cache.put("msgID",String(update.message.message_id)); let photo_id = String(update.message.photo[0].file_id); let InputMediaPhoto = { 'type': "photo", 'media': photo_id } media.push(InputMediaPhoto); cache.put("mymedia",JSON.stringify(media)); } else { let i = update.message.message_id - Number(msgIDstring); while (i==1) { let photo_id = String(update.message.photo[0].file_id); let InputMediaPhoto = { 'type': "photo", 'media': photo_id }; media.push(InputMediaPhoto); sendMessage(myID, JSON.stringify(media), 'HTML'); cache.put("mymedia",JSON.stringify(media)); cache.put("msgID",String(update.message.message_id)); if (i==0){ break; } } sendMessage(myID, String(i), 'HTML'); // 此处会发送"0",逻辑卡在这 sendMessage(myID, cache.get("mymedia"), 'HTML'); sendMediaGroup(chat_id,media); } } //sendMessage(myID, JSON.stringify(media), 'HTML'); }
现有代码的问题
当前用message_id差值判断是否为同组后续事件的逻辑不成立——Telegram的message_id不一定是连续递增1的,且无法通过这个方式判断是否是最后一个事件。实际测试中i的值为0,导致循环不执行,直接触发sendMediaGroup,此时media数组并未收集全所有照片。
解决方案
1. 核心思路
- 以
media_group_id作为缓存键,同一个媒体组的所有事件共享唯一ID,以此归集同组照片。 - 引入超时机制:Telegram发送同媒体组事件的间隔通常很短,设置5秒超时,超时后认定该组所有事件已接收,执行转发并清理缓存。
2. 修改后的代码示例
// 声明bot token、设置webhook、声明myID为机器人ID // 声明sendMessage、sendMediaGroup等函数 const CACHE_TTL = 10; // 缓存有效期10秒,留足够时间接收同组事件 const TIMEOUT_DELAY = 5000; // 超时延迟5秒 function doPost(e) { let update = JSON.parse(e.postData.contents); let message = update.message; // 记录事件日志 sendMessage(myID, JSON.stringify(update), 'HTML'); if (!message.media_group_id) { // 处理非媒体组消息逻辑 return ContentService.createTextOutput(JSON.stringify({status: "ok"})).setMimeType(ContentService.MimeType.JSON); } const cache = CacheService.getScriptCache(); const mediaGroupId = message.media_group_id; const chatId = message.chat.id; // 从缓存获取当前媒体组的照片数组 let media = []; const cachedMedia = cache.get(`media_${mediaGroupId}`); if (cachedMedia) { media = JSON.parse(cachedMedia); } // 添加当前照片到数组(取最高分辨率的照片) const photoId = message.photo[message.photo.length - 1].file_id; media.push({ type: "photo", media: photoId }); // 更新缓存 cache.put(`media_${mediaGroupId}`, JSON.stringify(media), CACHE_TTL); cache.put(`chat_${mediaGroupId}`, chatId, CACHE_TTL); // 检查是否已设置该媒体组的超时触发器 const triggerKey = `trigger_${mediaGroupId}`; if (!cache.get(triggerKey)) { // 设置触发器,5秒后执行转发 ScriptApp.newTrigger('processMediaGroup') .timeBased() .after(TIMEOUT_DELAY) .create(); cache.put(triggerKey, "set", CACHE_TTL); } return ContentService.createTextOutput(JSON.stringify({status: "ok"})).setMimeType(ContentService.MimeType.JSON); } function processMediaGroup(e) { const triggerId = e.triggerUid; // 删除当前触发器 ScriptApp.deleteTrigger(ScriptApp.getTriggerById(triggerId)); const cache = CacheService.getScriptCache(); // 遍历缓存中的所有媒体组键 const allKeys = cache.getAllKeys(); const mediaGroupKeys = allKeys.filter(key => key.startsWith('media_')); for (const key of mediaGroupKeys) { const mediaGroupId = key.replace('media_', ''); const media = JSON.parse(cache.get(key)); const chatId = cache.get(`chat_${mediaGroupId}`); if (media && chatId) { // 执行转发 sendMediaGroup(chatId, media); // 清理缓存 cache.remove(`media_${mediaGroupId}`); cache.remove(`chat_${mediaGroupId}`); cache.remove(`trigger_${mediaGroupId}`); } } }
关键说明
- 用
media_group_id作为缓存键,确保同组照片被正确归集。 - 设置超时触发器,等待足够时间接收同组所有事件后再执行转发。
- 触发器执行时清理对应缓存和自身,避免重复执行。
内容的提问来源于stack exchange,提问作者Puca
相关产品推荐
相关产品推荐

