feat: new media download way

This commit is contained in:
Anton Voylenko 2025-03-31 10:55:15 +03:00
commit 5869d86177
4 changed files with 173 additions and 2 deletions

View file

@ -1,6 +1,7 @@
const { MessageMedia, Location, Poll } = require('whatsapp-web.js')
const { Readable } = require('stream')
const { sessions } = require('../sessions')
const { sendErrorResponse } = require('../utils')
const { sendErrorResponse, decodeBase64 } = require('../utils')
/**
* Get message by its ID from a given chat using the provided client.
@ -116,6 +117,7 @@ const downloadMedia = async (req, res) => {
const client = sessions.get(req.params.sessionId)
const message = await _getMessageById(client, messageId, chatId)
if (!message) { throw new Error('Message not found') }
if (!message.hasMedia) { throw new Error('Message media not found') }
const messageMedia = await message.downloadMedia()
res.json({ success: true, messageMedia })
} catch (error) {
@ -123,6 +125,54 @@ const downloadMedia = async (req, res) => {
}
}
/**
* Downloads media from a message and sends it as binary data.
* @async
* @function
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @param {string} req.params.sessionId - The session ID.
* @param {string} req.body.messageId - The message ID.
* @param {string} req.body.chatId - The chat ID.
* @returns {Promise<void>} - A Promise that resolves with no value when the function completes.
*/
const downloadMediaAsData = async (req, res) => {
/*
#swagger.summary = 'Download attached message media as binary data'
*/
try {
const { messageId, chatId } = req.body
const client = sessions.get(req.params.sessionId)
const message = await _getMessageById(client, messageId, chatId)
if (!message) { throw new Error('Message not found') }
if (!message.hasMedia) { throw new Error('Message media not found') }
const { data, mimetype, filename, filesize } = await message.downloadMedia()
/* #swagger.responses[200] = {
description: 'Binary data.'
}
*/
res.writeHead(200, {
...(mimetype && { 'Content-Type': mimetype }),
...(filesize && { 'Content-Length': filesize }),
...(filename && { 'Content-Disposition': `attachment; filename=${encodeURIComponent(filename)}` })
})
const readableStream = new Readable({
read () {
for (const chunk of decodeBase64(data)) {
this.push(chunk)
}
this.push(null)
}
})
readableStream.on('end', () => {
res.end()
})
readableStream.pipe(res)
} catch (error) {
sendErrorResponse(res, 500, error.message)
}
}
/**
* Forwards a message to a destination chat.
* @async
@ -684,6 +734,7 @@ module.exports = {
getClassInfo,
deleteMessage,
downloadMedia,
downloadMediaAsData,
forward,
getInfo,
getMentions,

View file

@ -170,6 +170,7 @@ routes.use('/message', messageRouter)
messageRouter.post('/getClassInfo/:sessionId', [middleware.sessionNameValidation, middleware.sessionValidation], messageController.getClassInfo)
messageRouter.post('/delete/:sessionId', [middleware.sessionNameValidation, middleware.sessionValidation], messageController.deleteMessage)
messageRouter.post('/downloadMedia/:sessionId', [middleware.sessionNameValidation, middleware.sessionValidation], messageController.downloadMedia)
messageRouter.post('/downloadMediaAsData/:sessionId', [middleware.sessionNameValidation, middleware.sessionValidation], messageController.downloadMediaAsData)
messageRouter.post('/forward/:sessionId', [middleware.sessionNameValidation, middleware.sessionValidation], messageController.forward)
messageRouter.post('/getInfo/:sessionId', [middleware.sessionNameValidation, middleware.sessionValidation], messageController.getInfo)
messageRouter.post('/getMentions/:sessionId', [middleware.sessionNameValidation, middleware.sessionValidation], messageController.getMentions)

View file

@ -51,10 +51,19 @@ const sendMessageSeenStatus = async (message) => {
}
}
const decodeBase64 = function * (base64String) {
const chunkSize = 1024
for (let i = 0; i < base64String.length; i += chunkSize) {
const chunk = base64String.slice(i, i + chunkSize)
yield Buffer.from(chunk, 'base64')
}
}
module.exports = {
triggerWebhook,
sendErrorResponse,
waitForNestedObject,
checkIfEventisEnabled,
sendMessageSeenStatus
sendMessageSeenStatus,
decodeBase64
}