Skip to content

Commit a02ecc8

Browse files
committed
refactor(whatsapp.business.service): enhance media handling and audio processing
- Updated media message preparation to conditionally include filename and caption based on media type. - Improved error handling in media ID retrieval and audio processing methods. - Refactored audio processing to support file uploads and URL handling more effectively. - Enhanced logging for better error tracking during media operations.
1 parent bc451e8 commit a02ecc8

File tree

2 files changed

+113
-52
lines changed

2 files changed

+113
-52
lines changed

src/api/integrations/channel/meta/whatsapp.business.service.ts

Lines changed: 112 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import axios from 'axios';
2828
import { arrayUnique, isURL } from 'class-validator';
2929
import EventEmitter2 from 'eventemitter2';
3030
import FormData from 'form-data';
31-
import { createReadStream } from 'fs';
3231
import mimeTypes from 'mime-types';
3332
import { join } from 'path';
3433

@@ -997,9 +996,10 @@ export class BusinessStartupService extends ChannelStartupService {
997996
to: number.replace(/\D/g, ''),
998997
[message['mediaType']]: {
999998
[message['type']]: message['id'],
1000-
preview_url: Boolean(options?.linkPreview),
1001-
...(message['fileName'] && !isImage && { filename: message['fileName'] }),
1002-
caption: message['caption'],
999+
...(message['mediaType'] !== 'audio' &&
1000+
message['fileName'] &&
1001+
!isImage && { filename: message['fileName'] }),
1002+
...(message['mediaType'] !== 'audio' && message['caption'] && { caption: message['caption'] }),
10031003
},
10041004
};
10051005
quoted ? (content.context = { message_id: quoted.id }) : content;
@@ -1097,7 +1097,7 @@ export class BusinessStartupService extends ChannelStartupService {
10971097
}
10981098
})();
10991099

1100-
if (messageSent?.error_data) {
1100+
if (messageSent?.error_data || messageSent.message) {
11011101
this.logger.error(messageSent);
11021102
return messageSent;
11031103
}
@@ -1164,28 +1164,50 @@ export class BusinessStartupService extends ChannelStartupService {
11641164
return res;
11651165
}
11661166

1167-
private async getIdMedia(mediaMessage: any) {
1168-
const formData = new FormData();
1169-
const fileStream = createReadStream(mediaMessage.media);
1167+
private async getIdMedia(mediaMessage: any, isFile = false) {
1168+
try {
1169+
const formData = new FormData();
1170+
1171+
if (isFile === false) {
1172+
if (isURL(mediaMessage.media)) {
1173+
const response = await axios.get(mediaMessage.media, { responseType: 'arraybuffer' });
1174+
const buffer = Buffer.from(response.data, 'base64');
1175+
formData.append('file', buffer, {
1176+
filename: mediaMessage.fileName || 'media',
1177+
contentType: mediaMessage.mimetype,
1178+
});
1179+
} else {
1180+
const buffer = Buffer.from(mediaMessage.media, 'base64');
1181+
formData.append('file', buffer, {
1182+
filename: mediaMessage.fileName || 'media',
1183+
contentType: mediaMessage.mimetype,
1184+
});
1185+
}
1186+
} else {
1187+
formData.append('file', mediaMessage.media.buffer, {
1188+
filename: mediaMessage.media.originalname,
1189+
contentType: mediaMessage.media.mimetype,
1190+
});
1191+
}
11701192

1171-
formData.append('file', fileStream, { filename: 'media', contentType: mediaMessage.mimetype });
1172-
formData.append('typeFile', mediaMessage.mimetype);
1173-
formData.append('messaging_product', 'whatsapp');
1193+
const mimetype = mediaMessage.mimetype || mediaMessage.media.mimetype;
11741194

1175-
// const fileBuffer = await fs.readFile(mediaMessage.media);
1195+
formData.append('typeFile', mimetype);
1196+
formData.append('messaging_product', 'whatsapp');
11761197

1177-
// const fileBlob = new Blob([fileBuffer], { type: mediaMessage.mimetype });
1178-
// formData.append('file', fileBlob);
1179-
// formData.append('typeFile', mediaMessage.mimetype);
1180-
// formData.append('messaging_product', 'whatsapp');
1198+
const token = process.env.FACEBOOK_USER_TOKEN;
11811199

1182-
const headers = { Authorization: `Bearer ${this.token}` };
1183-
const res = await axios.post(
1184-
process.env.API_URL + '/' + process.env.VERSION + '/' + this.number + '/media',
1185-
formData,
1186-
{ headers },
1187-
);
1188-
return res.data.id;
1200+
const headers = { Authorization: `Bearer ${token}` };
1201+
const url = `${this.configService.get<WaBusiness>('WA_BUSINESS').URL}/${
1202+
this.configService.get<WaBusiness>('WA_BUSINESS').VERSION
1203+
}/${this.number}/media`;
1204+
1205+
const res = await axios.post(url, formData, { headers });
1206+
return res.data.id;
1207+
} catch (error) {
1208+
this.logger.error(error.response.data);
1209+
throw new InternalServerErrorException(error?.toString() || error);
1210+
}
11891211
}
11901212

11911213
protected async prepareMediaMessage(mediaMessage: MediaMessage) {
@@ -1258,48 +1280,87 @@ export class BusinessStartupService extends ChannelStartupService {
12581280
return mediaSent;
12591281
}
12601282

1261-
public async processAudio(audio: string, number: string) {
1283+
public async processAudio(audio: string, number: string, file: any) {
12621284
number = number.replace(/\D/g, '');
12631285
const hash = `${number}-${new Date().getTime()}`;
12641286

1265-
let mimetype: string | false;
1287+
if (process.env.API_AUDIO_CONVERTER) {
1288+
this.logger.verbose('Using audio converter API');
1289+
const formData = new FormData();
12661290

1267-
const prepareMedia: any = {
1268-
fileName: `${hash}.mp3`,
1269-
mediaType: 'audio',
1270-
media: audio,
1271-
};
1291+
if (file) {
1292+
formData.append('file', file.buffer, {
1293+
filename: file.originalname,
1294+
contentType: file.mimetype,
1295+
});
1296+
} else if (isURL(audio)) {
1297+
formData.append('url', audio);
1298+
} else {
1299+
formData.append('base64', audio);
1300+
}
1301+
1302+
formData.append('format', 'mp3');
1303+
1304+
const response = await axios.post(process.env.API_AUDIO_CONVERTER, formData, {
1305+
headers: {
1306+
...formData.getHeaders(),
1307+
apikey: process.env.API_AUDIO_CONVERTER_KEY,
1308+
},
1309+
});
1310+
1311+
const audioConverter = response?.data?.audio || response?.data?.url;
1312+
1313+
if (!audioConverter) {
1314+
throw new InternalServerErrorException('Failed to convert audio');
1315+
}
1316+
1317+
const prepareMedia: any = {
1318+
fileName: `${hash}.mp3`,
1319+
mediaType: 'audio',
1320+
media: audioConverter,
1321+
mimetype: 'audio/mpeg',
1322+
};
12721323

1273-
if (isURL(audio)) {
1274-
mimetype = mimeTypes.lookup(audio);
1275-
prepareMedia.id = audio;
1276-
prepareMedia.type = 'link';
1277-
} else {
1278-
mimetype = mimeTypes.lookup(prepareMedia.fileName);
12791324
const id = await this.getIdMedia(prepareMedia);
12801325
prepareMedia.id = id;
12811326
prepareMedia.type = 'id';
1282-
}
12831327

1284-
prepareMedia.mimetype = mimetype;
1328+
this.logger.verbose('Audio converted');
1329+
return prepareMedia;
1330+
} else {
1331+
let mimetype: string | false;
12851332

1286-
return prepareMedia;
1287-
}
1333+
const prepareMedia: any = {
1334+
fileName: `${hash}.mp3`,
1335+
mediaType: 'audio',
1336+
media: audio,
1337+
};
12881338

1289-
public async audioWhatsapp(data: SendAudioDto, file?: any, isIntegration = false) {
1290-
const mediaData: SendAudioDto = { ...data };
1339+
if (isURL(audio)) {
1340+
mimetype = mimeTypes.lookup(audio);
1341+
prepareMedia.id = audio;
1342+
prepareMedia.type = 'link';
1343+
} else if (audio && !file) {
1344+
mimetype = mimeTypes.lookup(prepareMedia.fileName);
1345+
const id = await this.getIdMedia(prepareMedia);
1346+
prepareMedia.id = id;
1347+
prepareMedia.type = 'id';
1348+
} else if (file) {
1349+
prepareMedia.media = file;
1350+
const id = await this.getIdMedia(prepareMedia, true);
1351+
prepareMedia.id = id;
1352+
prepareMedia.type = 'id';
1353+
mimetype = file.mimetype;
1354+
}
12911355

1292-
if (file?.buffer) {
1293-
mediaData.audio = file.buffer.toString('base64');
1294-
} else if (isURL(mediaData.audio)) {
1295-
// DO NOTHING
1296-
// mediaData.audio = mediaData.audio;
1297-
} else {
1298-
console.error('El archivo no tiene buffer o file es undefined');
1299-
throw new Error('File or buffer is undefined');
1356+
prepareMedia.mimetype = mimetype;
1357+
1358+
return prepareMedia;
13001359
}
1360+
}
13011361

1302-
const message = await this.processAudio(mediaData.audio, data.number);
1362+
public async audioWhatsapp(data: SendAudioDto, file?: any, isIntegration = false) {
1363+
const message = await this.processAudio(data.audio, data.number, file);
13031364

13041365
const audioSent = await this.sendMessageWithTyping(
13051366
data.number,

src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1819,7 +1819,7 @@ export class BaileysStartupService extends ChannelStartupService {
18191819
// setTimeout(() => this.client.terminateCall(call.id, call.to), callDuration * 1000);
18201820

18211821
// return call;
1822-
return { id: '123' };
1822+
return { id: '123', jid, isVideo, callDuration };
18231823
} catch (error) {
18241824
return error;
18251825
}

0 commit comments

Comments
 (0)