From e23540593a17bf87720b9f22d11b830f934a8124 Mon Sep 17 00:00:00 2001 From: Leifer Mendez Date: Wed, 23 Feb 2022 09:29:16 +0100 Subject: [PATCH] add voice note --- .gitignore | 1 + README.md | 42 ++++++++++++++++++++++++++--- app.js | 4 ++- controllers/send.js | 25 +++++++++++++---- mediaSend/PTT-20220223-WA0000.opus | Bin 0 -> 12001 bytes 5 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 mediaSend/PTT-20220223-WA0000.opus diff --git a/.gitignore b/.gitignore index 8ddf74a..305b65b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ media/* !media/.gitkeep mediaSend/* !mediaSend/.gitkeep +!mediaSend/PTT-20220223-WA0000.opus .env \ No newline at end of file diff --git a/README.md b/README.md index 32bce13..b8076f2 100644 --- a/README.md +++ b/README.md @@ -27,18 +27,52 @@ El siguiente proyecto se realizó con fines educativos para el canal de [Youtube | QR Scan (route) | ✅ | | Easy deploy heroku | ✅ | | Buttons | ✅ | +| Send Voice Note | ✅ | | Add support ubuntu/linux | ✅ | -### (Nuevo) Botones - -[![btn](https://i.imgur.com/W7oYlSu.png)](https://youtu.be/5lEMCeWEJ8o) - ## Requisitos - node v14 o superior - VSCode (Editor de codigo) [Descargar](https://code.visualstudio.com/download) - MySql (opcional) solo aplica si vas a usar el modo 'mysql' [sql-bot.sql migración](https://github.com/leifermendez/bot-whatsapp/blob/main/sql-bot.sql) - Dialogflow (opcional) solo aplica si vas a usar el modo 'dialogflow' +### (Nuevo) Botones + +[![btn](https://i.imgur.com/W7oYlSu.png)](https://youtu.be/5lEMCeWEJ8o) + +> Implementar los botones solo necesitas hacer uso del metodo __sendMessageButton__ que se encuentra dentro `./controllers/send` dejo un ejemplo de como usarlo. +[Ver implementación](https://github.com/leifermendez/bot-whatsapp/blob/main/app.js#L123) + +``` javascript +const { sendMessageButton } = require('./controllers/send') + +await sendMessageButton( + { + "title":"¿Que te interesa ver?", + "message":"Recuerda todo este contenido es gratis y estaria genial que me siguas!", + "footer":"Gracias", + "buttons":[ + {"body":"😎 Cursos"}, + {"body":"👉 Youtube"}, + {"body":"😁 Telegram"} + ] + } +) + +``` + +## Notas de Voz +[![voice note](https://i.imgur.com/zq6xYDp.png)](https://i.imgur.com/zq6xYDp.png) + +> Se pueden enviar notas de voz con formato nativo para que no se vea como reenviado. En este ejemplo enviare el archivo __PTT-20220223-WA0000.opus__ que se encuentra dentro de la carpeta de __/mediaSend__ + +``` javascript +const { sendMediaVoiceNote } = require('./controllers/send') + +await sendMediaVoiceNote(client, from, 'PTT-20220223-WA0000.opus') + +``` + ## Instruciones __Descargar o Clonar repositorio__ ![](https://i.imgur.com/dSpUbFz.png) diff --git a/app.js b/app.js index 6c81086..4fe259d 100644 --- a/app.js +++ b/app.js @@ -13,7 +13,7 @@ const { generateImage, cleanNumber } = require('./controllers/handle') const { connectionReady, connectionLost } = require('./controllers/connection') const { saveMedia } = require('./controllers/save') const { getMessages, responseMessages, bothResponse } = require('./controllers/flows') -const { sendMedia, sendMessage, lastTrigger, sendMessageButton, readChat } = require('./controllers/send') +const { sendMedia, sendMessage, lastTrigger, sendMessageButton, readChat, sendMediaVoiceNote } = require('./controllers/send') const app = express(); app.use(cors()) app.use(express.json()) @@ -54,6 +54,8 @@ const listenMessage = () => client.on('message', async msg => { console.log('BODY',message) const number = cleanNumber(from) await readChat(number, message) + + await sendMediaVoiceNote(client, from, 'PTT-20220223-WA0000.opus') /** * Guardamos el archivo multimedia que envia */ diff --git a/controllers/send.js b/controllers/send.js index feb85d9..6494698 100644 --- a/controllers/send.js +++ b/controllers/send.js @@ -4,8 +4,8 @@ const moment = require('moment'); const fs = require('fs'); const { MessageMedia, Buttons } = require('whatsapp-web.js'); const { cleanNumber } = require('./handle') -const { saveMedia } = require('../controllers/save') const DELAY_TIME = 170; //ms +const DIR_MEDIA = `${__dirname}/../mediaSend`; /** * Enviamos archivos multimedia a nuestro cliente @@ -14,14 +14,29 @@ const DELAY_TIME = 170; //ms */ const sendMedia = (client, number, fileName) => { - const dirMedia = `${__dirname}/../mediaSend/${fileName}`; number = cleanNumber(number) - if (fs.existsSync(dirMedia)) { - const media = MessageMedia.fromFilePath(dirMedia); + const file = `${DIR_MEDIA}/${fileName}`; + if (fs.existsSync(file)) { + const media = MessageMedia.fromFilePath(file); client.sendMessage(number, media); } } +/** + * Enviamos archivos como notas de voz + * @param {*} number + * @param {*} fileName + */ + + const sendMediaVoiceNote = (client, number, fileName) => { + number = cleanNumber(number) + const file = `${DIR_MEDIA}/${fileName}`; + if (fs.existsSync(file)) { + const media = MessageMedia.fromFilePath(file); + client.sendMessage(number, media ,{ sendAudioAsVoice: true }); + } +} + /** * Enviamos un mensaje simple (texto) a nuestro cliente * @param {*} number @@ -123,4 +138,4 @@ const readChat = async (number, message, trigger = null) => { }, 150) } -module.exports = { sendMessage, sendMedia, lastTrigger, sendMessageButton, readChat } \ No newline at end of file +module.exports = { sendMessage, sendMedia, lastTrigger, sendMessageButton, readChat, sendMediaVoiceNote } \ No newline at end of file diff --git a/mediaSend/PTT-20220223-WA0000.opus b/mediaSend/PTT-20220223-WA0000.opus new file mode 100644 index 0000000000000000000000000000000000000000..6e6e9951aa63ffac14e3a566a67f38433ca9c13a GIT binary patch literal 12001 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