Merge pull request #12 from avoylenko/new-download-endpoint
New download endpoint
This commit is contained in:
commit
15443afe8d
6 changed files with 183 additions and 12 deletions
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -9,7 +9,7 @@
|
|||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.8.3",
|
||||
"axios": "^1.8.4",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.21.2",
|
||||
"express-rate-limit": "^7.4.1",
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
"qr-image": "^3.2.0",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"whatsapp-web.js": "^1.26.1-alpha.3",
|
||||
"whatsapp-web.js": "^1.27.0",
|
||||
"ws": "^8.18.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -1725,9 +1725,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
|
||||
"integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
|
||||
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
|
|
@ -8108,9 +8108,9 @@
|
|||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/whatsapp-web.js": {
|
||||
"version": "1.26.1-alpha.3",
|
||||
"resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.26.1-alpha.3.tgz",
|
||||
"integrity": "sha512-W8RoTf6rZfHJx+JZGWUlsX0mbtZpYnoXzbSmtOtSn+pgTPO70rmdef4J9kuTWi4CRgnLLTQnCzpbDkEMXCUDBw==",
|
||||
"version": "1.27.0",
|
||||
"resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.27.0.tgz",
|
||||
"integrity": "sha512-hUhHpNXFTiQwTPfw/5WwV9MZLX+9sQXT1MoI14QYOuNxOxoJU12P2ODoqYnIWiqwIhyn++wQLpPsBC4LzcdzAQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@pedroslopez/moduleraid": "^5.0.2",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
"swagger": "node swagger.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.8.3",
|
||||
"axios": "^1.8.4",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.21.2",
|
||||
"express-rate-limit": "^7.4.1",
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
"qr-image": "^3.2.0",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"whatsapp-web.js": "^1.26.1-alpha.3",
|
||||
"whatsapp-web.js": "^1.27.0",
|
||||
"ws": "^8.18.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
11
src/utils.js
11
src/utils.js
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
110
swagger.json
110
swagger.json
|
|
@ -8664,6 +8664,116 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/message/downloadMediaAsData/{sessionId}": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Message"
|
||||
],
|
||||
"summary": "Download attached message media as binary data",
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "sessionId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Unique identifier for the session (alphanumeric and - allowed)",
|
||||
"example": "f8377d8d-a589-4242-9ba6-9486a04ef80c"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Binary data."
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ForbiddenResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NotFoundResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Unprocessable Entity.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Server failure.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"apiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"chatId": {
|
||||
"type": "string",
|
||||
"description": "The chat id which contains the message",
|
||||
"example": "6281288888888@c.us"
|
||||
},
|
||||
"messageId": {
|
||||
"type": "string",
|
||||
"description": "Unique WhatsApp ID for the message",
|
||||
"example": "ABCDEF999999999"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"application/xml": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"chatId": {
|
||||
"type": "string",
|
||||
"description": "The chat id which contains the message",
|
||||
"example": "6281288888888@c.us"
|
||||
},
|
||||
"messageId": {
|
||||
"type": "string",
|
||||
"description": "Unique WhatsApp ID for the message",
|
||||
"example": "ABCDEF999999999"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/message/forward/{sessionId}": {
|
||||
"post": {
|
||||
"tags": [
|
||||
|
|
|
|||
Loading…
Reference in a new issue