Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/@adiwajshing/baileys/lib/Utils/messages.js
1129 views
1
"use strict";
2
var __importDefault = (this && this.__importDefault) || function (mod) {
3
return (mod && mod.__esModule) ? mod : { "default": mod };
4
};
5
Object.defineProperty(exports, "__esModule", { value: true });
6
exports.patchMessageForMdIfRequired = exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
7
const boom_1 = require("@hapi/boom");
8
const axios_1 = __importDefault(require("axios"));
9
const fs_1 = require("fs");
10
const WAProto_1 = require("../../WAProto");
11
const Defaults_1 = require("../Defaults");
12
const Types_1 = require("../Types");
13
const WABinary_1 = require("../WABinary");
14
const generics_1 = require("./generics");
15
const messages_media_1 = require("./messages-media");
16
const MIMETYPE_MAP = {
17
image: 'image/jpeg',
18
video: 'video/mp4',
19
document: 'application/pdf',
20
audio: 'audio/ogg; codecs=opus',
21
sticker: 'image/webp',
22
history: 'application/x-protobuf',
23
'md-app-state': 'application/x-protobuf',
24
};
25
const MessageTypeProto = {
26
'image': Types_1.WAProto.Message.ImageMessage,
27
'video': Types_1.WAProto.Message.VideoMessage,
28
'audio': Types_1.WAProto.Message.AudioMessage,
29
'sticker': Types_1.WAProto.Message.StickerMessage,
30
'document': Types_1.WAProto.Message.DocumentMessage,
31
};
32
const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType;
33
/**
34
* Uses a regex to test whether the string contains a URL, and returns the URL if it does.
35
* @param text eg. hello https://google.com
36
* @returns the URL, eg. https://google.com
37
*/
38
const extractUrlFromText = (text) => {
39
var _a;
40
return (!Defaults_1.URL_EXCLUDE_REGEX.test(text) ? (_a = text.match(Defaults_1.URL_REGEX)) === null || _a === void 0 ? void 0 : _a[0] : undefined);
41
};
42
exports.extractUrlFromText = extractUrlFromText;
43
const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
44
const url = (0, exports.extractUrlFromText)(text);
45
if (!!getUrlInfo && url) {
46
try {
47
const urlInfo = await getUrlInfo(url);
48
return urlInfo;
49
}
50
catch (error) { // ignore if fails
51
logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'url generation failed');
52
}
53
}
54
};
55
exports.generateLinkPreviewIfRequired = generateLinkPreviewIfRequired;
56
const prepareWAMessageMedia = async (message, options) => {
57
const logger = options.logger;
58
let mediaType;
59
for (const key of Defaults_1.MEDIA_KEYS) {
60
if (key in message) {
61
mediaType = key;
62
}
63
}
64
if (!mediaType) {
65
throw new boom_1.Boom('Invalid media type', { statusCode: 400 });
66
}
67
const uploadData = {
68
...message,
69
media: message[mediaType]
70
};
71
delete uploadData[mediaType];
72
// check if cacheable + generate cache key
73
const cacheableKey = typeof uploadData.media === 'object' &&
74
('url' in uploadData.media) &&
75
!!uploadData.media.url &&
76
!!options.mediaCache && (
77
// generate the key
78
mediaType + ':' + uploadData.media.url.toString());
79
if (mediaType === 'document' && !uploadData.fileName) {
80
uploadData.fileName = 'file';
81
}
82
if (!uploadData.mimetype) {
83
uploadData.mimetype = MIMETYPE_MAP[mediaType];
84
}
85
// check for cache hit
86
if (cacheableKey) {
87
const mediaBuff = options.mediaCache.get(cacheableKey);
88
if (mediaBuff) {
89
logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'got media cache hit');
90
const obj = Types_1.WAProto.Message.decode(mediaBuff);
91
const key = `${mediaType}Message`;
92
Object.assign(obj[key], { ...uploadData, media: undefined });
93
return obj;
94
}
95
}
96
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
97
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
98
(typeof uploadData['jpegThumbnail'] === 'undefined');
99
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation;
100
const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath } = await (0, messages_media_1.encryptedStream)(uploadData.media, mediaType, requiresOriginalForSomeProcessing);
101
// url safe Base64 encode the SHA256 hash of the body
102
const fileEncSha256B64 = encodeURIComponent(fileEncSha256.toString('base64')
103
.replace(/\+/g, '-')
104
.replace(/\//g, '_')
105
.replace(/\=+$/, ''));
106
const [{ mediaUrl, directPath }] = await Promise.all([
107
(async () => {
108
const result = await options.upload(encWriteStream, { fileEncSha256B64, mediaType, timeoutMs: options.mediaUploadTimeoutMs });
109
logger === null || logger === void 0 ? void 0 : logger.debug({ mediaType, cacheableKey }, 'uploaded media');
110
return result;
111
})(),
112
(async () => {
113
try {
114
if (requiresThumbnailComputation) {
115
uploadData.jpegThumbnail = await (0, messages_media_1.generateThumbnail)(bodyPath, mediaType, options);
116
logger === null || logger === void 0 ? void 0 : logger.debug('generated thumbnail');
117
}
118
if (requiresDurationComputation) {
119
uploadData.seconds = await (0, messages_media_1.getAudioDuration)(bodyPath);
120
logger === null || logger === void 0 ? void 0 : logger.debug('computed audio duration');
121
}
122
}
123
catch (error) {
124
logger === null || logger === void 0 ? void 0 : logger.warn({ trace: error.stack }, 'failed to obtain extra info');
125
}
126
})(),
127
])
128
.finally(async () => {
129
encWriteStream.destroy();
130
// remove tmp files
131
if (didSaveToTmpPath && bodyPath) {
132
await fs_1.promises.unlink(bodyPath);
133
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp files');
134
}
135
});
136
const obj = Types_1.WAProto.Message.fromObject({
137
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
138
url: mediaUrl,
139
directPath,
140
mediaKey,
141
fileEncSha256,
142
fileSha256,
143
fileLength,
144
mediaKeyTimestamp: (0, generics_1.unixTimestampSeconds)(),
145
...uploadData,
146
media: undefined
147
})
148
});
149
if (cacheableKey) {
150
logger === null || logger === void 0 ? void 0 : logger.debug({ cacheableKey }, 'set cache');
151
options.mediaCache.set(cacheableKey, Types_1.WAProto.Message.encode(obj).finish());
152
}
153
return obj;
154
};
155
exports.prepareWAMessageMedia = prepareWAMessageMedia;
156
const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
157
ephemeralExpiration = ephemeralExpiration || 0;
158
const content = {
159
ephemeralMessage: {
160
message: {
161
protocolMessage: {
162
type: Types_1.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
163
ephemeralExpiration
164
}
165
}
166
}
167
};
168
return Types_1.WAProto.Message.fromObject(content);
169
};
170
exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
171
/**
172
* Generate forwarded message content like WA does
173
* @param message the message to forward
174
* @param options.forceForward will show the message as forwarded even if it is from you
175
*/
176
const generateForwardMessageContent = (message, forceForward) => {
177
var _a;
178
let content = message.message;
179
if (!content) {
180
throw new boom_1.Boom('no content in message', { statusCode: 400 });
181
}
182
// hacky copy
183
content = (0, exports.normalizeMessageContent)(content);
184
content = WAProto_1.proto.Message.decode(WAProto_1.proto.Message.encode(content).finish());
185
let key = Object.keys(content)[0];
186
let score = ((_a = content[key].contextInfo) === null || _a === void 0 ? void 0 : _a.forwardingScore) || 0;
187
score += message.key.fromMe && !forceForward ? 0 : 1;
188
if (key === 'conversation') {
189
content.extendedTextMessage = { text: content[key] };
190
delete content.conversation;
191
key = 'extendedTextMessage';
192
}
193
if (score > 0) {
194
content[key].contextInfo = { forwardingScore: score, isForwarded: true };
195
}
196
else {
197
content[key].contextInfo = {};
198
}
199
return content;
200
};
201
exports.generateForwardMessageContent = generateForwardMessageContent;
202
const generateWAMessageContent = async (message, options) => {
203
var _a;
204
let m = {};
205
if ('text' in message) {
206
const extContent = { text: message.text };
207
let urlInfo = message.linkPreview;
208
if (typeof urlInfo === 'undefined') {
209
urlInfo = await (0, exports.generateLinkPreviewIfRequired)(message.text, options.getUrlInfo, options.logger);
210
}
211
if (urlInfo) {
212
extContent.canonicalUrl = urlInfo['canonical-url'];
213
extContent.matchedText = urlInfo['matched-text'];
214
extContent.jpegThumbnail = urlInfo.jpegThumbnail;
215
extContent.description = urlInfo.description;
216
extContent.title = urlInfo.title;
217
extContent.previewType = 0;
218
}
219
m.extendedTextMessage = extContent;
220
}
221
else if ('contacts' in message) {
222
const contactLen = message.contacts.contacts.length;
223
if (!contactLen) {
224
throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 });
225
}
226
if (contactLen === 1) {
227
m.contactMessage = Types_1.WAProto.Message.ContactMessage.fromObject(message.contacts.contacts[0]);
228
}
229
else {
230
m.contactsArrayMessage = Types_1.WAProto.Message.ContactsArrayMessage.fromObject(message.contacts);
231
}
232
}
233
else if ('location' in message) {
234
m.locationMessage = Types_1.WAProto.Message.LocationMessage.fromObject(message.location);
235
}
236
else if ('react' in message) {
237
if (!message.react.senderTimestampMs) {
238
message.react.senderTimestampMs = Date.now();
239
}
240
m.reactionMessage = Types_1.WAProto.Message.ReactionMessage.fromObject(message.react);
241
}
242
else if ('delete' in message) {
243
m.protocolMessage = {
244
key: message.delete,
245
type: Types_1.WAProto.Message.ProtocolMessage.Type.REVOKE
246
};
247
}
248
else if ('forward' in message) {
249
m = (0, exports.generateForwardMessageContent)(message.forward, message.force);
250
}
251
else if ('disappearingMessagesInChat' in message) {
252
const exp = typeof message.disappearingMessagesInChat === 'boolean' ?
253
(message.disappearingMessagesInChat ? Defaults_1.WA_DEFAULT_EPHEMERAL : 0) :
254
message.disappearingMessagesInChat;
255
m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
256
}
257
else if ('buttonReply' in message) {
258
switch (message.type) {
259
case 'template':
260
m.templateButtonReplyMessage = {
261
selectedDisplayText: message.buttonReply.displayText,
262
selectedId: message.buttonReply.id,
263
selectedIndex: message.buttonReply.index,
264
};
265
break;
266
case 'plain':
267
m.buttonsResponseMessage = {
268
selectedButtonId: message.buttonReply.id,
269
selectedDisplayText: message.buttonReply.displayText,
270
type: WAProto_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT,
271
};
272
break;
273
}
274
}
275
else if ('product' in message) {
276
const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
277
m.productMessage = Types_1.WAProto.Message.ProductMessage.fromObject({
278
...message,
279
product: {
280
...message.product,
281
productImage: imageMessage,
282
}
283
});
284
}
285
else {
286
m = await (0, exports.prepareWAMessageMedia)(message, options);
287
}
288
if ('buttons' in message && !!message.buttons) {
289
const buttonsMessage = {
290
buttons: message.buttons.map(b => ({ ...b, type: WAProto_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
291
};
292
if ('text' in message) {
293
buttonsMessage.contentText = message.text;
294
buttonsMessage.headerType = ButtonType.EMPTY;
295
}
296
else {
297
if ('caption' in message) {
298
buttonsMessage.contentText = message.caption;
299
}
300
const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
301
buttonsMessage.headerType = ButtonType[type];
302
Object.assign(buttonsMessage, m);
303
}
304
if ('footer' in message && !!message.footer) {
305
buttonsMessage.footerText = message.footer;
306
}
307
m = { buttonsMessage };
308
}
309
else if ('templateButtons' in message && !!message.templateButtons) {
310
const msg = {
311
hydratedButtons: message.templateButtons
312
};
313
if ('text' in message) {
314
msg.hydratedContentText = message.text;
315
}
316
else {
317
if ('caption' in message) {
318
msg.hydratedContentText = message.caption;
319
}
320
Object.assign(msg, m);
321
}
322
if ('footer' in message && !!message.footer) {
323
msg.hydratedFooterText = message.footer;
324
}
325
m = {
326
templateMessage: {
327
fourRowTemplate: msg,
328
hydratedTemplate: msg
329
}
330
};
331
}
332
if ('sections' in message && !!message.sections) {
333
const listMessage = {
334
sections: message.sections,
335
buttonText: message.buttonText,
336
title: message.title,
337
footerText: message.footer,
338
description: message.text,
339
listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
340
};
341
m = { listMessage };
342
}
343
if ('viewOnce' in message && !!message.viewOnce) {
344
m = { viewOnceMessage: { message: m } };
345
}
346
if ('mentions' in message && ((_a = message.mentions) === null || _a === void 0 ? void 0 : _a.length)) {
347
const [messageType] = Object.keys(m);
348
m[messageType].contextInfo = m[messageType] || {};
349
m[messageType].contextInfo.mentionedJid = message.mentions;
350
}
351
return Types_1.WAProto.Message.fromObject(m);
352
};
353
exports.generateWAMessageContent = generateWAMessageContent;
354
const generateWAMessageFromContent = (jid, message, options) => {
355
if (!options.timestamp) {
356
options.timestamp = new Date();
357
} // set timestamp to now
358
const key = Object.keys(message)[0];
359
const timestamp = (0, generics_1.unixTimestampSeconds)(options.timestamp);
360
const { quoted, userJid } = options;
361
if (quoted) {
362
const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid);
363
let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
364
const msgType = (0, exports.getContentType)(quotedMsg);
365
// strip any redundant properties
366
quotedMsg = WAProto_1.proto.Message.fromObject({ [msgType]: quotedMsg[msgType] });
367
const quotedContent = quotedMsg[msgType];
368
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
369
delete quotedContent.contextInfo;
370
}
371
const contextInfo = message[key].contextInfo || {};
372
contextInfo.participant = (0, WABinary_1.jidNormalizedUser)(participant);
373
contextInfo.stanzaId = quoted.key.id;
374
contextInfo.quotedMessage = quotedMsg;
375
// if a participant is quoted, then it must be a group
376
// hence, remoteJid of group must also be entered
377
if (quoted.key.participant || quoted.participant) {
378
contextInfo.remoteJid = quoted.key.remoteJid;
379
}
380
message[key].contextInfo = contextInfo;
381
}
382
if (
383
// if we want to send a disappearing message
384
!!(options === null || options === void 0 ? void 0 : options.ephemeralExpiration) &&
385
// and it's not a protocol message -- delete, toggle disappear message
386
key !== 'protocolMessage' &&
387
// already not converted to disappearing message
388
key !== 'ephemeralMessage') {
389
message[key].contextInfo = {
390
...(message[key].contextInfo || {}),
391
expiration: options.ephemeralExpiration || Defaults_1.WA_DEFAULT_EPHEMERAL,
392
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
393
};
394
message = {
395
ephemeralMessage: {
396
message
397
}
398
};
399
}
400
message = Types_1.WAProto.Message.fromObject(message);
401
const messageJSON = {
402
key: {
403
remoteJid: jid,
404
fromMe: true,
405
id: (options === null || options === void 0 ? void 0 : options.messageId) || (0, generics_1.generateMessageID)(),
406
},
407
message: message,
408
messageTimestamp: timestamp,
409
messageStubParameters: [],
410
participant: (0, WABinary_1.isJidGroup)(jid) ? userJid : undefined,
411
status: Types_1.WAMessageStatus.PENDING
412
};
413
return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON);
414
};
415
exports.generateWAMessageFromContent = generateWAMessageFromContent;
416
const generateWAMessage = async (jid, content, options) => {
417
var _a;
418
// ensure msg ID is with every log
419
options.logger = (_a = options === null || options === void 0 ? void 0 : options.logger) === null || _a === void 0 ? void 0 : _a.child({ msgId: options.messageId });
420
return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, options), options);
421
};
422
exports.generateWAMessage = generateWAMessage;
423
/** Get the key to access the true type of content */
424
const getContentType = (content) => {
425
if (content) {
426
const keys = Object.keys(content);
427
const key = keys.find(k => (k === 'conversation' || k.endsWith('Message')) && k !== 'senderKeyDistributionMessage');
428
return key;
429
}
430
};
431
exports.getContentType = getContentType;
432
/**
433
* Normalizes ephemeral, view once messages to regular message content
434
* Eg. image messages in ephemeral messages, in view once messages etc.
435
* @param content
436
* @returns
437
*/
438
const normalizeMessageContent = (content) => {
439
var _a, _b, _c, _d, _e;
440
content = ((_c = (_b = (_a = content === null || content === void 0 ? void 0 : content.ephemeralMessage) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.viewOnceMessage) === null || _c === void 0 ? void 0 : _c.message) ||
441
((_d = content === null || content === void 0 ? void 0 : content.ephemeralMessage) === null || _d === void 0 ? void 0 : _d.message) ||
442
((_e = content === null || content === void 0 ? void 0 : content.viewOnceMessage) === null || _e === void 0 ? void 0 : _e.message) ||
443
content ||
444
undefined;
445
return content;
446
};
447
exports.normalizeMessageContent = normalizeMessageContent;
448
/**
449
* Extract the true message content from a message
450
* Eg. extracts the inner message from a disappearing message/view once message
451
*/
452
const extractMessageContent = (content) => {
453
var _a, _b, _c, _d, _e, _f;
454
const extractFromTemplateMessage = (msg) => {
455
if (msg.imageMessage) {
456
return { imageMessage: msg.imageMessage };
457
}
458
else if (msg.documentMessage) {
459
return { documentMessage: msg.documentMessage };
460
}
461
else if (msg.videoMessage) {
462
return { videoMessage: msg.videoMessage };
463
}
464
else if (msg.locationMessage) {
465
return { locationMessage: msg.locationMessage };
466
}
467
else {
468
return { conversation: 'contentText' in msg ? msg.contentText : ('hydratedContentText' in msg ? msg.hydratedContentText : '') };
469
}
470
};
471
content = (0, exports.normalizeMessageContent)(content);
472
if (content === null || content === void 0 ? void 0 : content.buttonsMessage) {
473
return extractFromTemplateMessage(content.buttonsMessage);
474
}
475
if ((_a = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _a === void 0 ? void 0 : _a.hydratedFourRowTemplate) {
476
return extractFromTemplateMessage((_b = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _b === void 0 ? void 0 : _b.hydratedFourRowTemplate);
477
}
478
if ((_c = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _c === void 0 ? void 0 : _c.hydratedTemplate) {
479
return extractFromTemplateMessage((_d = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _d === void 0 ? void 0 : _d.hydratedTemplate);
480
}
481
if ((_e = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _e === void 0 ? void 0 : _e.fourRowTemplate) {
482
return extractFromTemplateMessage((_f = content === null || content === void 0 ? void 0 : content.templateMessage) === null || _f === void 0 ? void 0 : _f.fourRowTemplate);
483
}
484
return content;
485
};
486
exports.extractMessageContent = extractMessageContent;
487
/**
488
* Returns the device predicted by message ID
489
*/
490
const getDevice = (id) => {
491
const deviceType = id.length > 21 ? 'android' : id.substring(0, 2) === '3A' ? 'ios' : 'web';
492
return deviceType;
493
};
494
exports.getDevice = getDevice;
495
/** Upserts a receipt in the message */
496
const updateMessageWithReceipt = (msg, receipt) => {
497
msg.userReceipt = msg.userReceipt || [];
498
const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid);
499
if (recp) {
500
Object.assign(recp, receipt);
501
}
502
else {
503
msg.userReceipt.push(receipt);
504
}
505
};
506
exports.updateMessageWithReceipt = updateMessageWithReceipt;
507
const getKeyAuthor = (key) => (((key === null || key === void 0 ? void 0 : key.fromMe) ? 'me' : (key === null || key === void 0 ? void 0 : key.participant) || (key === null || key === void 0 ? void 0 : key.remoteJid)) || '');
508
/** Update the message with a new reaction */
509
const updateMessageWithReaction = (msg, reaction) => {
510
const authorID = getKeyAuthor(reaction.key);
511
const reactions = (msg.reactions || [])
512
.filter(r => getKeyAuthor(r.key) !== authorID);
513
if (reaction.text) {
514
reactions.push(reaction);
515
}
516
msg.reactions = reactions;
517
};
518
exports.updateMessageWithReaction = updateMessageWithReaction;
519
/** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
520
const aggregateMessageKeysNotFromMe = (keys) => {
521
const keyMap = {};
522
for (const { remoteJid, id, participant, fromMe } of keys) {
523
if (!fromMe) {
524
const uqKey = `${remoteJid}:${participant || ''}`;
525
if (!keyMap[uqKey]) {
526
keyMap[uqKey] = {
527
jid: remoteJid,
528
participant: participant,
529
messageIds: []
530
};
531
}
532
keyMap[uqKey].messageIds.push(id);
533
}
534
}
535
return Object.values(keyMap);
536
};
537
exports.aggregateMessageKeysNotFromMe = aggregateMessageKeysNotFromMe;
538
const REUPLOAD_REQUIRED_STATUS = [410, 404];
539
/**
540
* Downloads the given message. Throws an error if it's not a media message
541
*/
542
const downloadMediaMessage = async (message, type, options, ctx) => {
543
var _a;
544
try {
545
const result = await downloadMsg();
546
return result;
547
}
548
catch (error) {
549
if (ctx) {
550
if (axios_1.default.isAxiosError(error)) {
551
// check if the message requires a reupload
552
if (REUPLOAD_REQUIRED_STATUS.includes((_a = error.response) === null || _a === void 0 ? void 0 : _a.status)) {
553
ctx.logger.info({ key: message.key }, 'sending reupload media request...');
554
// request reupload
555
message = await ctx.reuploadRequest(message);
556
const result = await downloadMsg();
557
return result;
558
}
559
}
560
}
561
throw error;
562
}
563
async function downloadMsg() {
564
const mContent = (0, exports.extractMessageContent)(message.message);
565
if (!mContent) {
566
throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
567
}
568
const contentType = (0, exports.getContentType)(mContent);
569
const mediaType = contentType === null || contentType === void 0 ? void 0 : contentType.replace('Message', '');
570
const media = mContent[contentType];
571
if (!media || typeof media !== 'object' || !('url' in media)) {
572
throw new boom_1.Boom(`"${contentType}" message is not a media message`);
573
}
574
const stream = await (0, messages_media_1.downloadContentFromMessage)(media, mediaType, options);
575
if (type === 'buffer') {
576
let buffer = Buffer.from([]);
577
for await (const chunk of stream) {
578
buffer = Buffer.concat([buffer, chunk]);
579
}
580
return buffer;
581
}
582
return stream;
583
}
584
};
585
exports.downloadMediaMessage = downloadMediaMessage;
586
/** Checks whether the given message is a media message; if it is returns the inner content */
587
const assertMediaContent = (content) => {
588
content = (0, exports.extractMessageContent)(content);
589
const mediaContent = (content === null || content === void 0 ? void 0 : content.documentMessage)
590
|| (content === null || content === void 0 ? void 0 : content.imageMessage)
591
|| (content === null || content === void 0 ? void 0 : content.videoMessage)
592
|| (content === null || content === void 0 ? void 0 : content.audioMessage)
593
|| (content === null || content === void 0 ? void 0 : content.stickerMessage);
594
if (!mediaContent) {
595
throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content });
596
}
597
return mediaContent;
598
};
599
exports.assertMediaContent = assertMediaContent;
600
const generateContextInfo = () => {
601
const info = {
602
deviceListMetadataVersion: 2,
603
deviceListMetadata: {}
604
};
605
return info;
606
};
607
/**
608
* this is an experimental patch to make buttons work
609
* Don't know how it works, but it does for now
610
*/
611
const patchMessageForMdIfRequired = (message) => {
612
const requiresPatch = !!(message.buttonsMessage
613
// || message.templateMessage
614
|| message.listMessage);
615
if (requiresPatch) {
616
message = {
617
viewOnceMessage: {
618
message: {
619
messageContextInfo: generateContextInfo(),
620
...message
621
}
622
}
623
};
624
}
625
return message;
626
};
627
exports.patchMessageForMdIfRequired = patchMessageForMdIfRequired;
628
629