simple.js 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143
  1. import path from 'path';
  2. import {toAudio} from './converter.js';
  3. import chalk from 'chalk';
  4. import fetch from 'node-fetch';
  5. import PhoneNumber from 'awesome-phonenumber';
  6. import fs from 'fs';
  7. import util from 'util';
  8. import {fileTypeFromBuffer} from 'file-type';
  9. import {format} from 'util';
  10. import {fileURLToPath} from 'url';
  11. import store from './store.js';
  12. const __dirname = path.dirname(fileURLToPath(import.meta.url));
  13. /**
  14. * @type {import('@whiskeysockets/baileys')}
  15. */
  16. const {
  17. default: _makeWaSocket,
  18. makeWALegacySocket,
  19. proto,
  20. downloadContentFromMessage,
  21. jidDecode,
  22. areJidsSameUser,
  23. generateWAMessage,
  24. generateForwardMessageContent,
  25. generateWAMessageFromContent,
  26. WAMessageStubType,
  27. extractMessageContent,
  28. WA_DEFAULT_EPHEMERAL,
  29. prepareWAMessageMedia,
  30. } = (await import('@whiskeysockets/baileys')).default;
  31. export function makeWASocket(connectionOptions, options = {}) {
  32. /**
  33. * @type {import('@whiskeysockets/baileys').WASocket | import('@whiskeysockets/baileys').WALegacySocket}
  34. */
  35. const conn = (global.opts['legacy'] ? makeWALegacySocket : _makeWaSocket)(connectionOptions);
  36. const sock = Object.defineProperties(conn, {
  37. chats: {
  38. value: {...(options.chats || {})},
  39. writable: true,
  40. },
  41. decodeJid: {
  42. value(jid) {
  43. if (!jid || typeof jid !== 'string') return (!nullish(jid) && jid) || null;
  44. return jid.decodeJid();
  45. },
  46. },
  47. logger: {
  48. get() {
  49. return {
  50. info(...args) {
  51. console.log(
  52. chalk.bold.bgRgb(51, 204, 51)('INFO '),
  53. `[${chalk.rgb(255, 255, 255)(new Date().toUTCString())}]:`,
  54. chalk.cyan(format(...args)),
  55. );
  56. },
  57. error(...args) {
  58. console.log(
  59. chalk.bold.bgRgb(247, 38, 33)('ERROR '),
  60. `[${chalk.rgb(255, 255, 255)(new Date().toUTCString())}]:`,
  61. chalk.rgb(255, 38, 0)(format(...args)),
  62. );
  63. },
  64. warn(...args) {
  65. console.log(
  66. chalk.bold.bgRgb(255, 153, 0)('WARNING '),
  67. `[${chalk.rgb(255, 255, 255)(new Date().toUTCString())}]:`,
  68. chalk.redBright(format(...args)),
  69. );
  70. },
  71. trace(...args) {
  72. console.log(
  73. chalk.grey('TRACE '),
  74. `[${chalk.rgb(255, 255, 255)(new Date().toUTCString())}]:`,
  75. chalk.white(format(...args)),
  76. );
  77. },
  78. debug(...args) {
  79. console.log(
  80. chalk.bold.bgRgb(66, 167, 245)('DEBUG '),
  81. `[${chalk.rgb(255, 255, 255)(new Date().toUTCString())}]:`,
  82. chalk.white(format(...args)),
  83. );
  84. },
  85. };
  86. },
  87. enumerable: true,
  88. },
  89. sendNyanCat: {
  90. async value(jid, text = '', buffer, title, body, url, quoted, options) {
  91. if (buffer) {
  92. try {
  93. (type = await conn.getFile(buffer), buffer = type.data);
  94. } catch {
  95. buffer = buffer;
  96. }
  97. }
  98. const prep = generateWAMessageFromContent(jid, {extendedTextMessage: {text: text, contextInfo: {externalAdReply: {title: title, body: body, thumbnail: buffer, sourceUrl: url}, mentionedJid: await conn.parseMention(text)}}}, {quoted: quoted});
  99. return conn.relayMessage(jid, prep.message, {messageId: prep.key.id});
  100. },
  101. },
  102. sendPayment: {
  103. async value(jid, amount, text, quoted, options) {
  104. conn.relayMessage(jid, {
  105. requestPaymentMessage: {
  106. currencyCodeIso4217: 'PEN',
  107. amount1000: amount,
  108. requestFrom: null,
  109. noteMessage: {
  110. extendedTextMessage: {
  111. text: text,
  112. contextInfo: {
  113. externalAdReply: {
  114. showAdAttribution: true,
  115. }, mentionedJid: conn.parseMention(text)}}}}}, {});
  116. },
  117. },
  118. getFile: {
  119. /**
  120. * getBuffer hehe
  121. * @param {fs.PathLike} PATH
  122. * @param {Boolean} saveToFile
  123. */
  124. async value(PATH, saveToFile = false) {
  125. let res; let filename;
  126. const data = Buffer.isBuffer(PATH) ? PATH : PATH instanceof ArrayBuffer ? PATH.toBuffer() : /^data:.*?\/.*?;base64,/i.test(PATH) ? Buffer.from(PATH.split`,`[1], 'base64') : /^https?:\/\//.test(PATH) ? await (res = await fetch(PATH)).buffer() : fs.existsSync(PATH) ? (filename = PATH, fs.readFileSync(PATH)) : typeof PATH === 'string' ? PATH : Buffer.alloc(0);
  127. if (!Buffer.isBuffer(data)) throw new TypeError('Result is not a buffer');
  128. const type = await fileTypeFromBuffer(data) || {
  129. mime: 'application/octet-stream',
  130. ext: '.bin',
  131. };
  132. if (data && saveToFile && !filename) (filename = path.join(__dirname, '../tmp/' + new Date * 1 + '.' + type.ext), await fs.promises.writeFile(filename, data));
  133. return {
  134. res,
  135. filename,
  136. ...type,
  137. data,
  138. deleteFile() {
  139. return filename && fs.promises.unlink(filename);
  140. },
  141. };
  142. },
  143. enumerable: true,
  144. },
  145. waitEvent: {
  146. /**
  147. * waitEvent
  148. * @param {String} eventName
  149. * @param {Boolean} is
  150. * @param {Number} maxTries
  151. */
  152. value(eventName, is = () => true, maxTries = 25) { // Idk why this exist?
  153. return new Promise((resolve, reject) => {
  154. let tries = 0;
  155. const on = (...args) => {
  156. if (++tries > maxTries) reject('Max tries reached');
  157. else if (is()) {
  158. conn.ev.off(eventName, on);
  159. resolve(...args);
  160. }
  161. };
  162. conn.ev.on(eventName, on);
  163. });
  164. },
  165. },
  166. relayWAMessage: {
  167. async value(pesanfull) {
  168. if (pesanfull.message.audioMessage) {
  169. await conn.sendPresenceUpdate('recording', pesanfull.key.remoteJid);
  170. } else {
  171. await conn.sendPresenceUpdate('composing', pesanfull.key.remoteJid);
  172. }
  173. const mekirim = await conn.relayMessage(pesanfull.key.remoteJid, pesanfull.message, {messageId: pesanfull.key.id});
  174. conn.ev.emit('messages.upsert', {messages: [pesanfull], type: 'append'});
  175. return mekirim;
  176. },
  177. },
  178. sendFile: {
  179. /**
  180. * Send Media/File with Automatic Type Specifier
  181. * @param {String} jid
  182. * @param {String|Buffer} path
  183. * @param {String} filename
  184. * @param {String} caption
  185. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} quoted
  186. * @param {Boolean} ptt
  187. * @param {Object} options
  188. */
  189. async value(jid, path, filename = '', caption = '', quoted, ptt = false, options = {}) {
  190. const type = await conn.getFile(path, true);
  191. let {res, data: file, filename: pathFile} = type;
  192. if (res && res.status !== 200 || file.length <= 65536) {
  193. try {
  194. throw {json: JSON.parse(file.toString())};
  195. } catch (e) {
  196. if (e.json) throw e.json;
  197. }
  198. }
  199. // const fileSize = fs.statSync(pathFile).size / 1024 / 1024
  200. // if (fileSize >= 100) throw new Error('File size is too big!')
  201. const opt = {};
  202. if (quoted) opt.quoted = quoted;
  203. if (!type) options.asDocument = true;
  204. let mtype = ''; let mimetype = options.mimetype || type.mime; let convert;
  205. if (/webp/.test(type.mime) || (/image/.test(type.mime) && options.asSticker)) mtype = 'sticker';
  206. else if (/image/.test(type.mime) || (/webp/.test(type.mime) && options.asImage)) mtype = 'image';
  207. else if (/video/.test(type.mime)) mtype = 'video';
  208. else if (/audio/.test(type.mime)) {
  209. (
  210. convert = await toAudio(file, type.ext),
  211. file = convert.data,
  212. pathFile = convert.filename,
  213. mtype = 'audio',
  214. mimetype = options.mimetype || 'audio/mpeg; codecs=opus'
  215. );
  216. } else mtype = 'document';
  217. if (options.asDocument) mtype = 'document';
  218. delete options.asSticker;
  219. delete options.asLocation;
  220. delete options.asVideo;
  221. delete options.asDocument;
  222. delete options.asImage;
  223. const message = {
  224. ...options,
  225. caption,
  226. ptt,
  227. [mtype]: {url: pathFile},
  228. mimetype,
  229. fileName: filename || pathFile.split('/').pop(),
  230. };
  231. /**
  232. * @type {import('@whiskeysockets/baileys').proto.WebMessageInfo}
  233. */
  234. let m;
  235. try {
  236. m = await conn.sendMessage(jid, message, {...opt, ...options});
  237. } catch (e) {
  238. console.error(e);
  239. m = null;
  240. } finally {
  241. if (!m) m = await conn.sendMessage(jid, {...message, [mtype]: file}, {...opt, ...options});
  242. file = null; // releasing the memory
  243. return m;
  244. }
  245. },
  246. enumerable: true,
  247. },
  248. sendContact: {
  249. /**
  250. * Send Contact
  251. * @param {String} jid
  252. * @param {String[][]|String[]} data
  253. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} quoted
  254. * @param {Object} options
  255. */
  256. async value(jid, data, quoted, options) {
  257. if (!Array.isArray(data[0]) && typeof data[0] === 'string') data = [data];
  258. const contacts = [];
  259. for (let [number, name] of data) {
  260. number = number.replace(/[^0-9]/g, '');
  261. const njid = number + '@s.whatsapp.net';
  262. const biz = await conn.getBusinessProfile(njid).catch((_) => null) || {};
  263. const vcard = `
  264. BEGIN:VCARD
  265. VERSION:3.0
  266. N:;${name.replace(/\n/g, '\\n')};;;
  267. FN:${name.replace(/\n/g, '\\n')}
  268. TEL;type=CELL;type=VOICE;waid=${number}:${PhoneNumber('+' + number).getNumber('international')}${biz.description ? `
  269. X-WA-BIZ-NAME:${(conn.chats[njid]?.vname || conn.getName(njid) || name).replace(/\n/, '\\n')}
  270. X-WA-BIZ-DESCRIPTION:${biz.description.replace(/\n/g, '\\n')}
  271. `.trim() : ''}
  272. END:VCARD
  273. `.trim();
  274. contacts.push({vcard, displayName: name});
  275. }
  276. return await conn.sendMessage(jid, {
  277. ...options,
  278. contacts: {
  279. ...options,
  280. displayName: (contacts.length >= 2 ? `${contacts.length} kontak` : contacts[0].displayName) || null,
  281. contacts,
  282. },
  283. }, {quoted, ...options});
  284. },
  285. enumerable: true,
  286. },
  287. reply: {
  288. /**
  289. * Reply to a message
  290. * @param {String} jid
  291. * @param {String|Buffer} text
  292. * @param {import('@adiwajshing/baileys').proto.WebMessageInfo} quoted
  293. * @param {Object} options
  294. */
  295. async value(jid, text = '', quoted, options) {
  296. if (Buffer.isBuffer(text)) {
  297. return conn.sendFile(jid, text, 'file', '', quoted, false, options)
  298. } else {
  299. let canalId = ["120363371008200788@newsletter", "120363371008200788@newsletter", "120363371008200788@newsletter", "120363178718483875@newsletter"]
  300. let canalNombre = ["Hack Store X 💫", "Kantu Bot Ofc ⚡", "The Kantu Bot 🔥", "KantuBot Test ✨"]
  301. async function getRandomChannel() {
  302. let randomIndex = Math.floor(Math.random() * canalId.length)
  303. let id = canalId[randomIndex]
  304. let nombre = canalNombre[randomIndex]
  305. return { id, nombre }
  306. }
  307. let randomChannel = await getRandomChannel()
  308. const contextInfo = {
  309. mentionedJid: await conn.parseMention(text),
  310. isForwarded: true,
  311. forwardingScore: 1,
  312. forwardedNewsletterMessageInfo: {
  313. newsletterJid: randomChannel.id,
  314. newsletterName: randomChannel.nombre
  315. }}
  316. const messageOptions = { ...options, text, contextInfo }
  317. return conn.sendMessage(jid, messageOptions, { quoted, ...options })
  318. }}
  319. },
  320. // sendButton: {
  321. /**
  322. * send Button
  323. * @param {String} jid
  324. * @param {String} text
  325. * @param {String} footer
  326. * @param {Buffer} buffer
  327. * @param {String[] | String[][]} buttons
  328. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} quoted
  329. * @param {Object} options
  330. */
  331. /* async value(jid, text = '', footer = '', buffer, buttons, quoted, options) {
  332. let type
  333. if (Array.isArray(buffer)) (options = quoted, quoted = buttons, buttons = buffer, buffer = null)
  334. else if (buffer) try { (type = await conn.getFile(buffer), buffer = type.data) } catch { buffer = null }
  335. if (!Array.isArray(buttons[0]) && typeof buttons[0] === 'string') buttons = [buttons]
  336. if (!options) options = {}
  337. let message = {
  338. ...options,
  339. [buffer ? 'caption' : 'text']: text || '',
  340. footer,
  341. buttons: buttons.map(btn => ({
  342. buttonId: !nullish(btn[1]) && btn[1] || !nullish(btn[0]) && btn[0] || '',
  343. buttonText: {
  344. displayText: !nullish(btn[0]) && btn[0] || !nullish(btn[1]) && btn[1] || ''
  345. }
  346. })),
  347. ...(buffer ?
  348. options.asLocation && /image/.test(type.mime) ? {
  349. location: {
  350. ...options,
  351. jpegThumbnail: buffer
  352. }
  353. } : {
  354. [/video/.test(type.mime) ? 'video' : /image/.test(type.mime) ? 'image' : 'document']: buffer
  355. } : {})
  356. }
  357. return await conn.sendMessage(jid, message, {
  358. quoted,
  359. upload: conn.waUploadToServer,
  360. ...options
  361. })
  362. },
  363. enumerable: true
  364. },
  365. */
  366. //-- new
  367. sendButton: {
  368. async value(jid, text = '', footer = '', buffer, buttons, copy, urls, list, quoted, options) {
  369. let img, video
  370. if (/^https?:\/\//i.test(buffer)) {
  371. try {
  372. // Obtener el tipo MIME de la URL
  373. const response = await fetch(buffer)
  374. const contentType = response.headers.get('content-type')
  375. if (/^image\//i.test(contentType)) {
  376. img = await prepareWAMessageMedia({ image: { url: buffer } }, { upload: conn.waUploadToServer })
  377. } else if (/^video\//i.test(contentType)) {
  378. video = await prepareWAMessageMedia({ video: { url: buffer } }, { upload: conn.waUploadToServer })
  379. } else {
  380. console.error("Tipo MIME no compatible:", contentType)
  381. }
  382. } catch (error) {
  383. console.error("Error al obtener el tipo MIME:", error)
  384. }
  385. } else {
  386. try {
  387. const type = await conn.getFile(buffer)
  388. if (/^image\//i.test(type.mime)) {
  389. img = await prepareWAMessageMedia({ image: { url: buffer } }, { upload: conn.waUploadToServer })
  390. } else if (/^video\//i.test(type.mime)) {
  391. video = await prepareWAMessageMedia({ video: { url: buffer } }, { upload: conn.waUploadToServer })
  392. }
  393. } catch (error) {
  394. console.error("Error al obtener el tipo de archivo:", error);
  395. }
  396. }
  397. const dynamicButtons = []
  398. // Botones de tipo quick_reply
  399. if (buttons && Array.isArray(buttons)) {
  400. dynamicButtons.push(...buttons.map(btn => ({
  401. name: 'quick_reply',
  402. buttonParamsJson: JSON.stringify({
  403. display_text: btn[0],
  404. id: btn[1]
  405. })
  406. })));
  407. }
  408. // Botones de copiar
  409. if (copy && Array.isArray(copy)) {
  410. dynamicButtons.push(...copy.map(copyBtn => ({
  411. name: 'cta_copy',
  412. buttonParamsJson: JSON.stringify({
  413. display_text: copyBtn[0] || 'Copy',
  414. copy_code: copyBtn[1]
  415. })
  416. })));
  417. }
  418. // Botones de URL
  419. if (urls && Array.isArray(urls)) {
  420. urls.forEach(url => {
  421. dynamicButtons.push({
  422. name: 'cta_url',
  423. buttonParamsJson: JSON.stringify({
  424. display_text: url[0],
  425. url: url[1],
  426. merchant_url: url[1]
  427. })
  428. });
  429. });
  430. }
  431. // Botones de lista
  432. if (list && Array.isArray(list)) {
  433. list.forEach(lister => {
  434. dynamicButtons.push({
  435. name: 'single_select',
  436. buttonParamsJson: JSON.stringify({
  437. title: lister[0],
  438. sections: lister[1]
  439. })
  440. })
  441. })
  442. }
  443. const interactiveMessage = {
  444. body: { text: text },
  445. footer: { text: footer },
  446. header: {
  447. hasMediaAttachment: false,
  448. imageMessage: img ? img.imageMessage : null,
  449. videoMessage: video ? video.videoMessage : null
  450. },
  451. nativeFlowMessage: {
  452. buttons: dynamicButtons,
  453. messageParamsJson: ''
  454. }
  455. }
  456. let msgL = generateWAMessageFromContent(jid, {
  457. viewOnceMessage: {
  458. message: {
  459. interactiveMessage } } }, { userJid: conn.user.jid, quoted })
  460. conn.relayMessage(jid, msgL.message, { messageId: msgL.key.id, ...options })
  461. }
  462. },
  463. sendAlbumMessage: {
  464. async value(jid, medias, caption = "", quoted = null) {
  465. let img, video;
  466. const album = generateWAMessageFromContent(jid, {
  467. albumMessage: {
  468. expectedImageCount: medias.filter(media => media.type === "image").length,
  469. expectedVideoCount: medias.filter(media => media.type === "video").length,
  470. ...(quoted ? {
  471. contextInfo: {
  472. remoteJid: quoted.key.remoteJid,
  473. fromMe: quoted.key.fromMe,
  474. stanzaId: quoted.key.id,
  475. participant: quoted.key.participant || quoted.key.remoteJid,
  476. quotedMessage: quoted.message
  477. }
  478. } : {})
  479. }
  480. }, { quoted: quoted });
  481. await conn.relayMessage(album.key.remoteJid, album.message, {
  482. messageId: album.key.id
  483. });
  484. for (const media of medias) {
  485. const { type, data } = media;
  486. if (/^https?:\/\//i.test(data.url)) {
  487. try {
  488. const response = await fetch(data.url);
  489. const contentType = response.headers.get('content-type');
  490. if (/^image\//i.test(contentType)) {
  491. img = await prepareWAMessageMedia({ image: { url: data.url } }, { upload: conn.waUploadToServer });
  492. } else if (/^video\//i.test(contentType)) {
  493. video = await prepareWAMessageMedia({ video: { url: data.url } }, { upload: conn.waUploadToServer });
  494. }
  495. } catch (error) {
  496. console.error("Error al obtener el tipo MIME:", error);
  497. }
  498. }
  499. const mediaMessage = await generateWAMessage(album.key.remoteJid, {
  500. [type]: data,
  501. ...(media === medias[0] ? { caption } : {})
  502. }, {
  503. upload: conn.waUploadToServer
  504. });
  505. mediaMessage.message.messageContextInfo = {
  506. messageAssociation: {
  507. associationType: 1,
  508. parentMessageKey: album.key
  509. }
  510. };
  511. await conn.relayMessage(mediaMessage.key.remoteJid, mediaMessage.message, {
  512. messageId: mediaMessage.key.id
  513. });
  514. }
  515. return album;
  516. }
  517. },
  518. /**
  519. * Send nativeFlowMessage
  520. */
  521. sendNCarousel: {
  522. async value(jid, text = '', footer = '', buffer, buttons, copy, urls, list, quoted, options) {
  523. let img, video;
  524. if (buffer) {
  525. if (/^https?:\/\//i.test(buffer)) {
  526. try {
  527. const response = await fetch(buffer);
  528. const contentType = response.headers.get('content-type');
  529. if (/^image\//i.test(contentType)) {
  530. img = await prepareWAMessageMedia({
  531. image: {
  532. url: buffer
  533. }
  534. }, {
  535. upload: conn.waUploadToServer,
  536. ...options
  537. });
  538. } else if (/^video\//i.test(contentType)) {
  539. video = await prepareWAMessageMedia({
  540. video: {
  541. url: buffer
  542. }
  543. }, {
  544. upload: conn.waUploadToServer,
  545. ...options
  546. });
  547. } else {
  548. console.error("Incompatible MIME type:", contentType);
  549. }
  550. } catch (error) {
  551. console.error("Failed to get MIME type:", error);
  552. }
  553. } else {
  554. try {
  555. const type = await conn.getFile(buffer);
  556. if (/^image\//i.test(type.mime)) {
  557. img = await prepareWAMessageMedia({
  558. image: (/^https?:\/\//i.test(buffer)) ? {
  559. url: buffer
  560. } : (type && type?.data)
  561. }, {
  562. upload: conn.waUploadToServer,
  563. ...options
  564. });
  565. } else if (/^video\//i.test(type.mime)) {
  566. video = await prepareWAMessageMedia({
  567. video: (/^https?:\/\//i.test(buffer)) ? {
  568. url: buffer
  569. } : (type && type?.data)
  570. }, {
  571. upload: conn.waUploadToServer,
  572. ...options
  573. });
  574. }
  575. } catch (error) {
  576. console.error("Failed to get file type:", error);
  577. }
  578. }
  579. }
  580. const dynamicButtons = buttons.map(btn => ({
  581. name: 'quick_reply',
  582. buttonParamsJson: JSON.stringify({
  583. display_text: btn[0],
  584. id: btn[1]
  585. }),
  586. }));
  587. dynamicButtons.push(
  588. (copy && (typeof copy === 'string' || typeof copy === 'number')) ? {
  589. name: 'cta_copy',
  590. buttonParamsJson: JSON.stringify({
  591. display_text: 'Copy',
  592. copy_code: copy
  593. })
  594. } : null)
  595. urls?.forEach(url => {
  596. dynamicButtons.push({
  597. name: 'cta_url',
  598. buttonParamsJson: JSON.stringify({
  599. display_text: url[0],
  600. url: url[1],
  601. merchant_url: url[1]
  602. })
  603. });
  604. });
  605. list?.forEach(lister => {
  606. dynamicButtons.push({
  607. name: 'single_select',
  608. buttonParamsJson: JSON.stringify({
  609. title: lister[0],
  610. sections: lister[1]
  611. })
  612. });
  613. })
  614. const interactiveMessage = {
  615. body: {
  616. text: text || ''
  617. },
  618. footer: {
  619. text: footer || wm
  620. },
  621. header: {
  622. hasMediaAttachment: img?.imageMessage || video?.videoMessage ? true : false,
  623. imageMessage: img?.imageMessage || null,
  624. videoMessage: video?.videoMessage || null
  625. },
  626. nativeFlowMessage: {
  627. buttons: dynamicButtons.filter(Boolean),
  628. messageParamsJson: ''
  629. },
  630. ...Object.assign({
  631. mentions: typeof text === 'string' ? conn.parseMention(text || '@0') : [],
  632. contextInfo: {
  633. mentionedJid: typeof text === 'string' ? conn.parseMention(text || '@0') : [],
  634. }
  635. }, {
  636. ...(options || {}),
  637. ...(conn.temareply?.contextInfo && {
  638. contextInfo: {
  639. ...(options?.contextInfo || {}),
  640. ...conn.temareply?.contextInfo,
  641. externalAdReply: {
  642. ...(options?.contextInfo?.externalAdReply || {}),
  643. ...conn.temareply?.contextInfo?.externalAdReply,
  644. },
  645. },
  646. })
  647. })
  648. };
  649. const messageContent = proto.Message.fromObject({
  650. viewOnceMessage: {
  651. message: {
  652. messageContextInfo: {
  653. deviceListMetadata: {},
  654. deviceListMetadataVersion: 2
  655. },
  656. interactiveMessage
  657. }
  658. }
  659. });
  660. const msgs = await generateWAMessageFromContent(jid, messageContent, {
  661. userJid: conn.user.jid,
  662. quoted: quoted,
  663. upload: conn.waUploadToServer,
  664. ephemeralExpiration: WA_DEFAULT_EPHEMERAL
  665. });
  666. await conn.relayMessage(jid, msgs.message, {
  667. messageId: msgs.key.id
  668. });
  669. }
  670. },
  671. /**
  672. * Send carouselMessage
  673. */
  674. sendCarousel: {
  675. async value(jid, text = '', footer = '', messages, quoted, options = {}) {
  676. try {
  677. if (messages.length > 1) {
  678. const cards = await Promise.all(messages.map(async ([text = '', footer = '', buffer, buttons, copy, urls, list]) => {
  679. let img, video;
  680. if (/^https?:\/\//i.test(buffer)) {
  681. try {
  682. const response = await fetch(buffer);
  683. const contentType = response.headers.get('content-type');
  684. if (/^image\//i.test(contentType)) {
  685. img = await prepareWAMessageMedia({ image: { url: buffer } }, { upload: conn.waUploadToServer, ...options });
  686. } else if (/^video\//i.test(contentType)) {
  687. video = await prepareWAMessageMedia({ video: { url: buffer } }, { upload: conn.waUploadToServer, ...options });
  688. } else {
  689. console.error("Tipo MIME no compatible:", contentType);
  690. }
  691. } catch (error) {
  692. console.error("Error al obtener el tipo MIME:", error);
  693. }
  694. } else {
  695. try {
  696. const type = await conn.getFile(buffer);
  697. if (/^image\//i.test(type.mime)) {
  698. img = await prepareWAMessageMedia({ image: { url: buffer } }, { upload: conn.waUploadToServer, ...options });
  699. } else if (/^video\//i.test(type.mime)) {
  700. video = await prepareWAMessageMedia({ video: { url: buffer } }, { upload: conn.waUploadToServer, ...options });
  701. }
  702. } catch (error) {
  703. console.error("Error al obtener el tipo de archivo:", error);
  704. }
  705. }
  706. const dynamicButtons = [];
  707. if (buttons && Array.isArray(buttons)) {
  708. buttons.forEach(btn => {
  709. dynamicButtons.push({
  710. name: 'quick_reply',
  711. buttonParamsJson: JSON.stringify({
  712. display_text: btn[0],
  713. id: btn[1]
  714. })
  715. });
  716. });
  717. }
  718. if (copy && Array.isArray(copy)) {
  719. copy.forEach(copyBtn => {
  720. dynamicButtons.push({
  721. name: 'cta_copy',
  722. buttonParamsJson: JSON.stringify({
  723. display_text: copyBtn[0] || 'Copy',
  724. copy_code: copyBtn[1]
  725. })
  726. });
  727. });
  728. }
  729. if (urls && Array.isArray(urls)) {
  730. urls.forEach(url => {
  731. dynamicButtons.push({
  732. name: 'cta_url',
  733. buttonParamsJson: JSON.stringify({
  734. display_text: url[0],
  735. url: url[1],
  736. merchant_url: url[1]
  737. })
  738. });
  739. });
  740. }
  741. if (list && Array.isArray(list)) {
  742. list.forEach(lister => {
  743. dynamicButtons.push({
  744. name: 'single_select',
  745. buttonParamsJson: JSON.stringify({
  746. title: lister[0],
  747. sections: lister[1]
  748. })
  749. });
  750. });
  751. }
  752. return {
  753. body: proto.Message.InteractiveMessage.Body.fromObject({
  754. text: text || ''
  755. }),
  756. footer: proto.Message.InteractiveMessage.Footer.fromObject({
  757. text: footer || null
  758. }),
  759. header: proto.Message.InteractiveMessage.Header.fromObject({
  760. title: text || null,
  761. subtitle: text || null,
  762. hasMediaAttachment: img?.imageMessage || video?.videoMessage ? true : false,
  763. imageMessage: img?.imageMessage || null,
  764. videoMessage: video?.videoMessage || null
  765. }),
  766. nativeFlowMessage: proto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
  767. buttons: dynamicButtons.filter(Boolean),
  768. messageParamsJson: ''
  769. })
  770. };
  771. }));
  772. const interactiveMessage = proto.Message.InteractiveMessage.create({
  773. body: proto.Message.InteractiveMessage.Body.fromObject({
  774. text: text || ''
  775. }),
  776. footer: proto.Message.InteractiveMessage.Footer.fromObject({
  777. text: footer || ''
  778. }),
  779. header: proto.Message.InteractiveMessage.Header.fromObject({
  780. title: text || '',
  781. subtitle: text || '',
  782. hasMediaAttachment: false
  783. }),
  784. carouselMessage: proto.Message.InteractiveMessage.CarouselMessage.fromObject({
  785. cards: cards
  786. })
  787. });
  788. const messageContent = proto.Message.fromObject({
  789. viewOnceMessage: {
  790. message: {
  791. messageContextInfo: {
  792. deviceListMetadata: {},
  793. deviceListMetadataVersion: 2
  794. },
  795. interactiveMessage
  796. }
  797. }
  798. });
  799. const msgs = await generateWAMessageFromContent(jid, messageContent, {
  800. userJid: conn.user.jid,
  801. quoted: quoted,
  802. upload: conn.waUploadToServer,
  803. ephemeralExpiration: WA_DEFAULT_EPHEMERAL
  804. });
  805. await conn.relayMessage(jid, msgs.message, { messageId: msgs.key.id });
  806. } else {
  807. await conn.sendNCarousel(jid, ...messages[0], quoted, options);
  808. }
  809. } catch (error) {
  810. console.error("Error en sendCarousel:", error);
  811. throw error;
  812. }
  813. }
  814. },
  815. sendButton2: {
  816. async value(jid, text = '', footer = '', buffer, buttons, copy, urls, quoted, options) {
  817. let img, video
  818. if (/^https?:\/\//i.test(buffer)) {
  819. try {
  820. // Obtener el tipo MIME de la URL
  821. const response = await fetch(buffer)
  822. const contentType = response.headers.get('content-type')
  823. if (/^image\//i.test(contentType)) {
  824. img = await prepareWAMessageMedia({ image: { url: buffer } }, { upload: conn.waUploadToServer })
  825. } else if (/^video\//i.test(contentType)) {
  826. video = await prepareWAMessageMedia({ video: { url: buffer } }, { upload: conn.waUploadToServer })
  827. } else {
  828. console.error("Tipo MIME no compatible:", contentType)
  829. }
  830. } catch (error) {
  831. console.error("Error al obtener el tipo MIME:", error)
  832. }
  833. } else {
  834. try {
  835. const type = await conn.getFile(buffer)
  836. if (/^image\//i.test(type.mime)) {
  837. img = await prepareWAMessageMedia({ image: { url: buffer } }, { upload: conn.waUploadToServer })
  838. } else if (/^video\//i.test(type.mime)) {
  839. video = await prepareWAMessageMedia({ video: { url: buffer } }, { upload: conn.waUploadToServer })
  840. }
  841. } catch (error) {
  842. console.error("Error al obtener el tipo de archivo:", error);
  843. }
  844. }
  845. const dynamicButtons = buttons.map(btn => ({
  846. name: 'quick_reply',
  847. buttonParamsJson: JSON.stringify({
  848. display_text: btn[0],
  849. id: btn[1]
  850. }),
  851. }));
  852. if (copy && (typeof copy === 'string' || typeof copy === 'number')) {
  853. // Añadir botón de copiar
  854. dynamicButtons.push({
  855. name: 'cta_copy',
  856. buttonParamsJson: JSON.stringify({
  857. display_text: 'Copy',
  858. copy_code: copy
  859. })
  860. });
  861. }
  862. // Añadir botones de URL
  863. if (urls && Array.isArray(urls)) {
  864. urls.forEach(url => {
  865. dynamicButtons.push({
  866. name: 'cta_url',
  867. buttonParamsJson: JSON.stringify({
  868. display_text: url[0],
  869. url: url[1],
  870. merchant_url: url[1]
  871. })
  872. })
  873. })
  874. }
  875. const interactiveMessage = {
  876. body: { text: text },
  877. footer: { text: footer },
  878. header: {
  879. hasMediaAttachment: false,
  880. imageMessage: img ? img.imageMessage : null,
  881. videoMessage: video ? video.videoMessage : null
  882. },
  883. nativeFlowMessage: {
  884. buttons: dynamicButtons,
  885. messageParamsJson: ''
  886. }
  887. }
  888. let msgL = generateWAMessageFromContent(jid, {
  889. viewOnceMessage: {
  890. message: {
  891. interactiveMessage } } }, { userJid: conn.user.jid, quoted })
  892. conn.relayMessage(jid, msgL.message, { messageId: msgL.key.id, ...options })
  893. }
  894. },
  895. //---
  896. sendList: {
  897. async value(jid, title, text, buttonText, buffer, listSections, quoted, options = {}) {
  898. let img, video
  899. if (/^https?:\/\//i.test(buffer)) {
  900. try {
  901. // Obtener el tipo MIME de la URL
  902. const response = await fetch(buffer)
  903. const contentType = response.headers.get('content-type')
  904. if (/^image\//i.test(contentType)) {
  905. img = await prepareWAMessageMedia({ image: { url: buffer } }, { upload: conn.waUploadToServer })
  906. } else if (/^video\//i.test(contentType)) {
  907. video = await prepareWAMessageMedia({ video: { url: buffer } }, { upload: conn.waUploadToServer })
  908. } else {
  909. console.error("Tipo MIME no compatible:", contentType)
  910. }
  911. } catch (error) {
  912. console.error("Error al obtener el tipo MIME:", error)
  913. }
  914. } else {
  915. try {
  916. const type = await conn.getFile(buffer)
  917. if (/^image\//i.test(type.mime)) {
  918. img = await prepareWAMessageMedia({ image: { url: buffer } }, { upload: conn.waUploadToServer })
  919. } else if (/^video\//i.test(type.mime)) {
  920. video = await prepareWAMessageMedia({ video: { url: buffer } }, { upload: conn.waUploadToServer })
  921. }
  922. } catch (error) {
  923. console.error("Error al obtener el tipo de archivo:", error);
  924. }
  925. }
  926. const sections = [...listSections]
  927. const message = {
  928. interactiveMessage: {
  929. header: {title: title,
  930. hasMediaAttachment: false,
  931. imageMessage: img ? img.imageMessage : null,
  932. videoMessage: video ? video.videoMessage : null
  933. } ,
  934. body: {text: text},
  935. nativeFlowMessage: {
  936. buttons: [
  937. {
  938. name: 'single_select',
  939. buttonParamsJson: JSON.stringify({
  940. title: buttonText,
  941. sections
  942. })
  943. }
  944. ],
  945. messageParamsJson: ''
  946. }
  947. }
  948. };
  949. let msgL = generateWAMessageFromContent(jid, {
  950. viewOnceMessage: {
  951. message} }, { userJid: conn.user.jid, quoted })
  952. //await conn.relayMessage(jid, { viewOnceMessage: { message } }, {});
  953. conn.relayMessage(jid, msgL.message, { messageId: msgL.key.id, ...options })
  954. }
  955. },
  956. sendPoll: {
  957. async value(jid, name = '', optiPoll, options) {
  958. if (!Array.isArray(optiPoll[0]) && typeof optiPoll[0] === 'string') optiPoll = [optiPoll];
  959. if (!options) options = {};
  960. const pollMessage = {
  961. name: name,
  962. options: optiPoll.map((btn) => ({
  963. optionName: !nullish(btn[0]) && btn[0] || '',
  964. })),
  965. selectableOptionsCount: 1,
  966. };
  967. return conn.relayMessage(jid, {pollCreationMessage: pollMessage}, {...options});
  968. },
  969. },
  970. sendHydrated: {
  971. /**
  972. *
  973. * @param {String} jid
  974. * @param {String} text
  975. * @param {String} footer
  976. * @param {fs.PathLike} buffer
  977. * @param {String|string[]} url
  978. * @param {String|string[]} urlText
  979. * @param {String|string[]} call
  980. * @param {String|string[]} callText
  981. * @param {String[][]} buttons
  982. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} quoted
  983. * @param {Object} options
  984. */
  985. async value(jid, text = '', footer = '', buffer, url, urlText, call, callText, buttons, quoted, options) {
  986. let type;
  987. if (buffer) {
  988. try {
  989. (type = await conn.getFile(buffer), buffer = type.data);
  990. } catch {
  991. buffer = buffer;
  992. }
  993. }
  994. if (buffer && !Buffer.isBuffer(buffer) && (typeof buffer === 'string' || Array.isArray(buffer))) (options = quoted, quoted = buttons, buttons = callText, callText = call, call = urlText, urlText = url, url = buffer, buffer = null);
  995. if (!options) options = {};
  996. const templateButtons = [];
  997. if (url || urlText) {
  998. if (!Array.isArray(url)) url = [url];
  999. if (!Array.isArray(urlText)) urlText = [urlText];
  1000. templateButtons.push(...(
  1001. url.map((v, i) => [v, urlText[i]])
  1002. .map(([url, urlText], i) => ({
  1003. index: templateButtons.length + i + 1,
  1004. urlButton: {
  1005. displayText: !nullish(urlText) && urlText || !nullish(url) && url || '',
  1006. url: !nullish(url) && url || !nullish(urlText) && urlText || '',
  1007. },
  1008. })) || []
  1009. ));
  1010. }
  1011. if (call || callText) {
  1012. if (!Array.isArray(call)) call = [call];
  1013. if (!Array.isArray(callText)) callText = [callText];
  1014. templateButtons.push(...(
  1015. call.map((v, i) => [v, callText[i]])
  1016. .map(([call, callText], i) => ({
  1017. index: templateButtons.length + i + 1,
  1018. callButton: {
  1019. displayText: !nullish(callText) && callText || !nullish(call) && call || '',
  1020. phoneNumber: !nullish(call) && call || !nullish(callText) && callText || '',
  1021. },
  1022. })) || []
  1023. ));
  1024. }
  1025. if (buttons.length) {
  1026. if (!Array.isArray(buttons[0])) buttons = [buttons];
  1027. templateButtons.push(...(
  1028. buttons.map(([text, id], index) => ({
  1029. index: templateButtons.length + index + 1,
  1030. quickReplyButton: {
  1031. displayText: !nullish(text) && text || !nullish(id) && id || '',
  1032. id: !nullish(id) && id || !nullish(text) && text || '',
  1033. },
  1034. })) || []
  1035. ));
  1036. }
  1037. const message = {
  1038. ...options,
  1039. [buffer ? 'caption' : 'text']: text || '',
  1040. footer,
  1041. templateButtons,
  1042. ...(buffer ?
  1043. options.asLocation && /image/.test(type.mime) ? {
  1044. location: {
  1045. ...options,
  1046. jpegThumbnail: buffer,
  1047. },
  1048. } : {
  1049. [/video/.test(type.mime) ? 'video' : /image/.test(type.mime) ? 'image' : 'document']: buffer,
  1050. } : {}),
  1051. };
  1052. return await conn.sendMessage(jid, message, {
  1053. quoted,
  1054. upload: conn.waUploadToServer,
  1055. ...options,
  1056. });
  1057. },
  1058. enumerable: true,
  1059. },
  1060. sendHydrated2: {
  1061. /**
  1062. *
  1063. * @param {String} jid
  1064. * @param {String} text
  1065. * @param {String} footer
  1066. * @param {fs.PathLike} buffer
  1067. * @param {String|string[]} url
  1068. * @param {String|string[]} urlText
  1069. * @param {String|string[]} call
  1070. * @param {String|string[]} callText
  1071. * @param {String[][]} buttons
  1072. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} quoted
  1073. * @param {Object} options
  1074. */
  1075. async value(jid, text = '', footer = '', buffer, url, urlText, url2, urlText2, buttons, quoted, options) {
  1076. let type;
  1077. if (buffer) {
  1078. try {
  1079. (type = await conn.getFile(buffer), buffer = type.data);
  1080. } catch {
  1081. buffer = buffer;
  1082. }
  1083. }
  1084. if (buffer && !Buffer.isBuffer(buffer) && (typeof buffer === 'string' || Array.isArray(buffer))) (options = quoted, quoted = buttons, buttons = callText, callText = call, call = urlText, urlText = url, url = buffer, buffer = null);
  1085. if (!options) options = {};
  1086. const templateButtons = [];
  1087. if (url || urlText) {
  1088. if (!Array.isArray(url)) url = [url];
  1089. if (!Array.isArray(urlText)) urlText = [urlText];
  1090. templateButtons.push(...(
  1091. url.map((v, i) => [v, urlText[i]])
  1092. .map(([url, urlText], i) => ({
  1093. index: templateButtons.length + i + 1,
  1094. urlButton: {
  1095. displayText: !nullish(urlText) && urlText || !nullish(url) && url || '',
  1096. url: !nullish(url) && url || !nullish(urlText) && urlText || '',
  1097. },
  1098. })) || []
  1099. ));
  1100. }
  1101. if (url2 || urlText2) {
  1102. if (!Array.isArray(url2)) url2 = [url2];
  1103. if (!Array.isArray(urlText2)) urlText2 = [urlText2];
  1104. templateButtons.push(...(
  1105. url2.map((v, i) => [v, urlText2[i]])
  1106. .map(([url2, urlText2], i) => ({
  1107. index: templateButtons.length + i + 1,
  1108. urlButton: {
  1109. displayText: !nullish(urlText2) && urlText2 || !nullish(url2) && url2 || '',
  1110. url: !nullish(url2) && url2 || !nullish(urlText2) && urlText2 || '',
  1111. },
  1112. })) || []
  1113. ));
  1114. }
  1115. if (buttons.length) {
  1116. if (!Array.isArray(buttons[0])) buttons = [buttons];
  1117. templateButtons.push(...(
  1118. buttons.map(([text, id], index) => ({
  1119. index: templateButtons.length + index + 1,
  1120. quickReplyButton: {
  1121. displayText: !nullish(text) && text || !nullish(id) && id || '',
  1122. id: !nullish(id) && id || !nullish(text) && text || '',
  1123. },
  1124. })) || []
  1125. ));
  1126. }
  1127. const message = {
  1128. ...options,
  1129. [buffer ? 'caption' : 'text']: text || '',
  1130. footer,
  1131. templateButtons,
  1132. ...(buffer ?
  1133. options.asLocation && /image/.test(type.mime) ? {
  1134. location: {
  1135. ...options,
  1136. jpegThumbnail: buffer,
  1137. },
  1138. } : {
  1139. [/video/.test(type.mime) ? 'video' : /image/.test(type.mime) ? 'image' : 'document']: buffer,
  1140. } : {}),
  1141. };
  1142. return await conn.sendMessage(jid, message, {
  1143. quoted,
  1144. upload: conn.waUploadToServer,
  1145. ...options,
  1146. });
  1147. },
  1148. enumerable: true,
  1149. },
  1150. cMod: {
  1151. /**
  1152. * cMod
  1153. * @param {String} jid
  1154. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} message
  1155. * @param {String} text
  1156. * @param {String} sender
  1157. * @param {*} options
  1158. * @returns
  1159. */
  1160. value(jid, message, text = '', sender = conn.user.jid, options = {}) {
  1161. if (options.mentions && !Array.isArray(options.mentions)) options.mentions = [options.mentions];
  1162. const copy = message.toJSON();
  1163. delete copy.message.messageContextInfo;
  1164. delete copy.message.senderKeyDistributionMessage;
  1165. const mtype = Object.keys(copy.message)[0];
  1166. const msg = copy.message;
  1167. const content = msg[mtype];
  1168. if (typeof content === 'string') msg[mtype] = text || content;
  1169. else if (content.caption) content.caption = text || content.caption;
  1170. else if (content.text) content.text = text || content.text;
  1171. if (typeof content !== 'string') {
  1172. msg[mtype] = {...content, ...options};
  1173. msg[mtype].contextInfo = {
  1174. ...(content.contextInfo || {}),
  1175. mentionedJid: options.mentions || content.contextInfo?.mentionedJid || [],
  1176. };
  1177. }
  1178. if (copy.participant) sender = copy.participant = sender || copy.participant;
  1179. else if (copy.key.participant) sender = copy.key.participant = sender || copy.key.participant;
  1180. if (copy.key.remoteJid.includes('@s.whatsapp.net')) sender = sender || copy.key.remoteJid;
  1181. else if (copy.key.remoteJid.includes('@broadcast')) sender = sender || copy.key.remoteJid;
  1182. copy.key.remoteJid = jid;
  1183. copy.key.fromMe = areJidsSameUser(sender, conn.user.id) || false;
  1184. return proto.WebMessageInfo.fromObject(copy);
  1185. },
  1186. enumerable: true,
  1187. },
  1188. copyNForward: {
  1189. /**
  1190. * Exact Copy Forward
  1191. * @param {String} jid
  1192. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} message
  1193. * @param {Boolean|Number} forwardingScore
  1194. * @param {Object} options
  1195. */
  1196. async value(jid, message, forwardingScore = true, options = {}) {
  1197. let vtype;
  1198. if (options.readViewOnce && message.message.viewOnceMessage?.message) {
  1199. vtype = Object.keys(message.message.viewOnceMessage.message)[0];
  1200. delete message.message.viewOnceMessage.message[vtype].viewOnce;
  1201. message.message = proto.Message.fromObject(
  1202. JSON.parse(JSON.stringify(message.message.viewOnceMessage.message)),
  1203. );
  1204. message.message[vtype].contextInfo = message.message.viewOnceMessage.contextInfo;
  1205. }
  1206. const mtype = Object.keys(message.message)[0];
  1207. let m = generateForwardMessageContent(message, !!forwardingScore);
  1208. const ctype = Object.keys(m)[0];
  1209. if (forwardingScore && typeof forwardingScore === 'number' && forwardingScore > 1) m[ctype].contextInfo.forwardingScore += forwardingScore;
  1210. m[ctype].contextInfo = {
  1211. ...(message.message[mtype].contextInfo || {}),
  1212. ...(m[ctype].contextInfo || {}),
  1213. };
  1214. m = generateWAMessageFromContent(jid, m, {
  1215. ...options,
  1216. userJid: conn.user.jid,
  1217. });
  1218. await conn.relayMessage(jid, m.message, {messageId: m.key.id, additionalAttributes: {...options}});
  1219. return m;
  1220. },
  1221. enumerable: true,
  1222. },
  1223. fakeReply: {
  1224. /**
  1225. * Fake Replies
  1226. * @param {String} jid
  1227. * @param {String|Object} text
  1228. * @param {String} fakeJid
  1229. * @param {String} fakeText
  1230. * @param {String} fakeGroupJid
  1231. * @param {String} options
  1232. */
  1233. value(jid, text = '', fakeJid = this.user.jid, fakeText = '', fakeGroupJid, options) {
  1234. return conn.reply(jid, text, {key: {fromMe: areJidsSameUser(fakeJid, conn.user.id), participant: fakeJid, ...(fakeGroupJid ? {remoteJid: fakeGroupJid} : {})}, message: {conversation: fakeText}, ...options});
  1235. },
  1236. },
  1237. downloadM: {
  1238. /**
  1239. * Download media message
  1240. * @param {Object} m
  1241. * @param {String} type
  1242. * @param {fs.PathLike | fs.promises.FileHandle} saveToFile
  1243. * @return {Promise<fs.PathLike | fs.promises.FileHandle | Buffer>}
  1244. */
  1245. async value(m, type, saveToFile) {
  1246. let filename;
  1247. if (!m || !(m.url || m.directPath)) return Buffer.alloc(0);
  1248. const stream = await downloadContentFromMessage(m, type);
  1249. let buffer = Buffer.from([]);
  1250. for await (const chunk of stream) {
  1251. buffer = Buffer.concat([buffer, chunk]);
  1252. }
  1253. if (saveToFile) ({filename} = await conn.getFile(buffer, true));
  1254. return saveToFile && fs.existsSync(filename) ? filename : buffer;
  1255. },
  1256. enumerable: true,
  1257. },
  1258. parseMention: {
  1259. /**
  1260. * Parses string into mentionedJid(s)
  1261. * @param {String} text
  1262. * @return {Array<String>}
  1263. */
  1264. value(text = '') {
  1265. return [...text.matchAll(/@([0-9]{5,16}|0)/g)].map((v) => v[1] + '@s.whatsapp.net');
  1266. },
  1267. enumerable: true,
  1268. },
  1269. getName: {
  1270. /**
  1271. * Get name from jid
  1272. * @param {String} jid
  1273. * @param {Boolean} withoutContact
  1274. */
  1275. value(jid = '', withoutContact = false) {
  1276. jid = conn.decodeJid(jid);
  1277. withoutContact = conn.withoutContact || withoutContact;
  1278. let v;
  1279. if (jid.endsWith('@g.us')) {
  1280. return new Promise(async (resolve) => {
  1281. v = conn.chats[jid] || {};
  1282. if (!(v.name || v.subject)) v = await conn.groupMetadata(jid) || {};
  1283. resolve(v.name || v.subject || PhoneNumber('+' + jid.replace('@s.whatsapp.net', '')).getNumber('international'));
  1284. });
  1285. } else {
  1286. v = jid === '0@s.whatsapp.net' ? {
  1287. jid,
  1288. vname: 'WhatsApp',
  1289. } : areJidsSameUser(jid, conn.user.id) ?
  1290. conn.user :
  1291. (conn.chats[jid] || {});
  1292. }
  1293. return (withoutContact ? '' : v.name) || v.subject || v.vname || v.notify || v.verifiedName || PhoneNumber('+' + jid.replace('@s.whatsapp.net', '')).getNumber('international');
  1294. },
  1295. enumerable: true,
  1296. },
  1297. loadMessage: {
  1298. /**
  1299. *
  1300. * @param {String} messageID
  1301. * @returns {import('@whiskeysockets/baileys').proto.WebMessageInfo}
  1302. */
  1303. value(messageID) {
  1304. return Object.entries(conn.chats)
  1305. .filter(([_, {messages}]) => typeof messages === 'object')
  1306. .find(([_, {messages}]) => Object.entries(messages)
  1307. .find(([k, v]) => (k === messageID || v.key?.id === messageID)))
  1308. ?.[1].messages?.[messageID];
  1309. },
  1310. enumerable: true,
  1311. },
  1312. sendGroupV4Invite: {
  1313. /**
  1314. * sendGroupV4Invite
  1315. * @param {String} jid
  1316. * @param {*} participant
  1317. * @param {String} inviteCode
  1318. * @param {Number} inviteExpiration
  1319. * @param {String} groupName
  1320. * @param {String} caption
  1321. * @param {Buffer} jpegThumbnail
  1322. * @param {*} options
  1323. */
  1324. async value(jid, participant, inviteCode, inviteExpiration, groupName = 'unknown subject', caption = 'Invitation to join my WhatsApp group', jpegThumbnail, options = {}) {
  1325. const msg = proto.Message.fromObject({
  1326. groupInviteMessage: proto.GroupInviteMessage.fromObject({
  1327. inviteCode,
  1328. inviteExpiration: parseInt(inviteExpiration) || + new Date(new Date + (3 * 86400000)),
  1329. groupJid: jid,
  1330. groupName: (groupName ? groupName : await conn.getName(jid)) || null,
  1331. jpegThumbnail: Buffer.isBuffer(jpegThumbnail) ? jpegThumbnail : null,
  1332. caption,
  1333. }),
  1334. });
  1335. const message = generateWAMessageFromContent(participant, msg, options);
  1336. await conn.relayMessage(participant, message.message, {messageId: message.key.id, additionalAttributes: {...options}});
  1337. return message;
  1338. },
  1339. enumerable: true,
  1340. },
  1341. processMessageStubType: {
  1342. /**
  1343. * to process MessageStubType
  1344. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} m
  1345. */
  1346. async value(m) {
  1347. if (!m.messageStubType) return;
  1348. const chat = conn.decodeJid(m.key.remoteJid || m.message?.senderKeyDistributionMessage?.groupId || '');
  1349. if (!chat || chat === 'status@broadcast') return;
  1350. const emitGroupUpdate = (update) => {
  1351. conn.ev.emit('groups.update', [{ id: chat, ...update }]);
  1352. };
  1353. switch (m.messageStubType) {
  1354. case WAMessageStubType.REVOKE:
  1355. case WAMessageStubType.GROUP_CHANGE_INVITE_LINK:
  1356. if (Array.isArray(m.messageStubParameters) && m.messageStubParameters.length > 0) {
  1357. emitGroupUpdate({ revoke: m.messageStubParameters[0] });
  1358. }
  1359. break;
  1360. case WAMessageStubType.GROUP_CHANGE_ICON:
  1361. if (Array.isArray(m.messageStubParameters) && m.messageStubParameters.length > 0) {
  1362. emitGroupUpdate({ icon: m.messageStubParameters[0] });
  1363. }
  1364. break;
  1365. default: {
  1366. console.log({
  1367. messageStubType: m.messageStubType,
  1368. messageStubParameters: m.messageStubParameters || [],
  1369. type: WAMessageStubType[m.messageStubType]
  1370. });
  1371. break;
  1372. }
  1373. }
  1374. const isGroup = chat.endsWith('@g.us');
  1375. if (!isGroup) return;
  1376. let chats = conn.chats[chat];
  1377. if (!chats) chats = conn.chats[chat] = { id: chat };
  1378. chats.isChats = true;
  1379. const metadata = await conn.groupMetadata(chat).catch(() => null);
  1380. if (!metadata) return;
  1381. chats.subject = metadata.subject;
  1382. chats.metadata = metadata;
  1383. }
  1384. },
  1385. insertAllGroup: {
  1386. async value() {
  1387. const groups = await conn.groupFetchAllParticipating().catch((_) => null) || {};
  1388. for (const group in groups) conn.chats[group] = {...(conn.chats[group] || {}), id: group, subject: groups[group].subject, isChats: true, metadata: groups[group]};
  1389. return conn.chats;
  1390. },
  1391. },
  1392. pushMessage: {
  1393. /**
  1394. * pushMessage
  1395. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo[]} m
  1396. */
  1397. async value(m) {
  1398. if (!m) return;
  1399. if (!Array.isArray(m)) m = [m];
  1400. for (const message of m) {
  1401. try {
  1402. // if (!(message instanceof proto.WebMessageInfo)) continue // https://github.com/adiwajshing/Baileys/pull/696/commits/6a2cb5a4139d8eb0a75c4c4ea7ed52adc0aec20f
  1403. if (!message) continue;
  1404. if (message.messageStubType && message.messageStubType != WAMessageStubType.CIPHERTEXT) conn.processMessageStubType(message).catch(console.error);
  1405. const _mtype = Object.keys(message.message || {});
  1406. const mtype = (!['senderKeyDistributionMessage', 'messageContextInfo'].includes(_mtype[0]) && _mtype[0]) ||
  1407. (_mtype.length >= 3 && _mtype[1] !== 'messageContextInfo' && _mtype[1]) ||
  1408. _mtype[_mtype.length - 1];
  1409. const chat = conn.decodeJid(message.key.remoteJid || message.message?.senderKeyDistributionMessage?.groupId || '');
  1410. if (message.message?.[mtype]?.contextInfo?.quotedMessage) {
  1411. /**
  1412. * @type {import('@whiskeysockets/baileys').proto.IContextInfo}
  1413. */
  1414. const context = message.message[mtype].contextInfo;
  1415. let participant = conn.decodeJid(context.participant);
  1416. const remoteJid = conn.decodeJid(context.remoteJid || participant);
  1417. /**
  1418. * @type {import('@whiskeysockets/baileys').proto.IMessage}
  1419. *
  1420. */
  1421. const quoted = message.message[mtype].contextInfo.quotedMessage;
  1422. if ((remoteJid && remoteJid !== 'status@broadcast') && quoted) {
  1423. let qMtype = Object.keys(quoted)[0];
  1424. if (qMtype == 'conversation') {
  1425. quoted.extendedTextMessage = {text: quoted[qMtype]};
  1426. delete quoted.conversation;
  1427. qMtype = 'extendedTextMessage';
  1428. }
  1429. if (!quoted[qMtype].contextInfo) quoted[qMtype].contextInfo = {};
  1430. quoted[qMtype].contextInfo.mentionedJid = context.mentionedJid || quoted[qMtype].contextInfo.mentionedJid || [];
  1431. const isGroup = remoteJid.endsWith('g.us');
  1432. if (isGroup && !participant) participant = remoteJid;
  1433. const qM = {
  1434. key: {
  1435. remoteJid,
  1436. fromMe: areJidsSameUser(conn.user.jid, remoteJid),
  1437. id: context.stanzaId,
  1438. participant,
  1439. },
  1440. message: JSON.parse(JSON.stringify(quoted)),
  1441. ...(isGroup ? {participant} : {}),
  1442. };
  1443. let qChats = conn.chats[participant];
  1444. if (!qChats) qChats = conn.chats[participant] = {id: participant, isChats: !isGroup};
  1445. if (!qChats.messages) qChats.messages = {};
  1446. if (!qChats.messages[context.stanzaId] && !qM.key.fromMe) qChats.messages[context.stanzaId] = qM;
  1447. let qChatsMessages;
  1448. if ((qChatsMessages = Object.entries(qChats.messages)).length > 40) qChats.messages = Object.fromEntries(qChatsMessages.slice(30, qChatsMessages.length)); // maybe avoid memory leak
  1449. }
  1450. }
  1451. if (!chat || chat === 'status@broadcast') continue;
  1452. const isGroup = chat.endsWith('@g.us');
  1453. let chats = conn.chats[chat];
  1454. if (!chats) {
  1455. if (isGroup) await conn.insertAllGroup().catch(console.error);
  1456. chats = conn.chats[chat] = {id: chat, isChats: true, ...(conn.chats[chat] || {})};
  1457. }
  1458. let metadata; let sender;
  1459. if (isGroup) {
  1460. if (!chats.subject || !chats.metadata) {
  1461. metadata = await conn.groupMetadata(chat).catch((_) => ({})) || {};
  1462. if (!chats.subject) chats.subject = metadata.subject || '';
  1463. if (!chats.metadata) chats.metadata = metadata;
  1464. }
  1465. sender = conn.decodeJid(message.key?.fromMe && conn.user.id || message.participant || message.key?.participant || chat || '');
  1466. if (sender !== chat) {
  1467. let chats = conn.chats[sender];
  1468. if (!chats) chats = conn.chats[sender] = {id: sender};
  1469. if (!chats.name) chats.name = message.pushName || chats.name || '';
  1470. }
  1471. } else if (!chats.name) chats.name = message.pushName || chats.name || '';
  1472. if (['senderKeyDistributionMessage', 'messageContextInfo'].includes(mtype)) continue;
  1473. chats.isChats = true;
  1474. if (!chats.messages) chats.messages = {};
  1475. const fromMe = message.key.fromMe || areJidsSameUser(sender || chat, conn.user.id);
  1476. if (!['protocolMessage'].includes(mtype) && !fromMe && message.messageStubType != WAMessageStubType.CIPHERTEXT && message.message) {
  1477. delete message.message.messageContextInfo;
  1478. delete message.message.senderKeyDistributionMessage;
  1479. chats.messages[message.key.id] = JSON.parse(JSON.stringify(message, null, 2));
  1480. let chatsMessages;
  1481. if ((chatsMessages = Object.entries(chats.messages)).length > 40) chats.messages = Object.fromEntries(chatsMessages.slice(30, chatsMessages.length));
  1482. }
  1483. } catch (e) {
  1484. console.error(e);
  1485. }
  1486. }
  1487. },
  1488. },
  1489. serializeM: {
  1490. /**
  1491. * Serialize Message, so it easier to manipulate
  1492. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} m
  1493. */
  1494. value(m) {
  1495. return smsg(conn, m);
  1496. },
  1497. },
  1498. ...(typeof conn.chatRead !== 'function' ? {
  1499. chatRead: {
  1500. /**
  1501. * Read message
  1502. * @param {String} jid
  1503. * @param {String|undefined|null} participant
  1504. * @param {String} messageID
  1505. */
  1506. value(jid, participant = conn.user.jid, messageID) {
  1507. return conn.sendReadReceipt(jid, participant, [messageID]);
  1508. },
  1509. enumerable: true,
  1510. },
  1511. } : {}),
  1512. ...(typeof conn.setStatus !== 'function' ? {
  1513. setStatus: {
  1514. /**
  1515. * setStatus bot
  1516. * @param {String} status
  1517. */
  1518. value(status) {
  1519. return conn.query({
  1520. tag: 'iq',
  1521. attrs: {
  1522. to: S_WHATSAPP_NET,
  1523. type: 'set',
  1524. xmlns: 'status',
  1525. },
  1526. content: [
  1527. {
  1528. tag: 'status',
  1529. attrs: {},
  1530. content: Buffer.from(status, 'utf-8'),
  1531. },
  1532. ],
  1533. });
  1534. },
  1535. enumerable: true,
  1536. },
  1537. } : {}),
  1538. });
  1539. if (sock.user?.id) sock.user.jid = sock.decodeJid(sock.user.id);
  1540. store.bind(sock);
  1541. return sock;
  1542. }
  1543. /**
  1544. * Serialize Message
  1545. * @param {ReturnType<typeof makeWASocket>} conn
  1546. * @param {import('@whiskeysockets/baileys').proto.WebMessageInfo} m
  1547. * @param {Boolean} hasParent
  1548. */
  1549. export function smsg(conn, m, hasParent) {
  1550. if (!m) return m;
  1551. /**
  1552. * @type {import('@whiskeysockets/baileys').proto.WebMessageInfo}
  1553. */
  1554. const M = proto.WebMessageInfo;
  1555. m = M.fromObject(m);
  1556. m.conn = conn;
  1557. let protocolMessageKey;
  1558. if (m.message) {
  1559. if (m.mtype == 'protocolMessage' && m.msg.key) {
  1560. protocolMessageKey = m.msg.key;
  1561. if (protocolMessageKey == 'status@broadcast') protocolMessageKey.remoteJid = m.chat;
  1562. if (!protocolMessageKey.participant || protocolMessageKey.participant == 'status_me') protocolMessageKey.participant = m.sender;
  1563. protocolMessageKey.fromMe = conn.decodeJid(protocolMessageKey.participant) === conn.decodeJid(conn.user.id);
  1564. if (!protocolMessageKey.fromMe && protocolMessageKey.remoteJid === conn.decodeJid(conn.user.id)) protocolMessageKey.remoteJid = m.sender;
  1565. }
  1566. if (m.quoted) if (!m.quoted.mediaMessage) delete m.quoted.download;
  1567. }
  1568. if (!m.mediaMessage) delete m.download;
  1569. try {
  1570. if (protocolMessageKey && m.mtype == 'protocolMessage') conn.ev.emit('message.delete', protocolMessageKey);
  1571. } catch (e) {
  1572. console.error(e);
  1573. }
  1574. return m;
  1575. }
  1576. // https://github.com/Nurutomo/wabot-aq/issues/490
  1577. export function serialize() {
  1578. const MediaType = ['imageMessage', 'videoMessage', 'audioMessage', 'stickerMessage', 'documentMessage'];
  1579. return Object.defineProperties(proto.WebMessageInfo.prototype, {
  1580. conn: {
  1581. value: undefined,
  1582. enumerable: false,
  1583. writable: true,
  1584. },
  1585. id: {
  1586. get() {
  1587. return this.key?.id;
  1588. },
  1589. },
  1590. isBaileys: {
  1591. get() {
  1592. return (this?.fromMe || areJidsSameUser(this.conn?.user.id, this.sender)) && this.id.startsWith('3EB0') && (this.id.length === 20 || this.id.length === 22 || this.id.length === 12) || false
  1593. },
  1594. },
  1595. chat: {
  1596. get() {
  1597. const senderKeyDistributionMessage = this.message?.senderKeyDistributionMessage?.groupId;
  1598. return (
  1599. this.key?.remoteJid ||
  1600. (senderKeyDistributionMessage &&
  1601. senderKeyDistributionMessage !== 'status@broadcast'
  1602. ) || ''
  1603. ).decodeJid();
  1604. },
  1605. },
  1606. isGroup: {
  1607. get() {
  1608. return this.chat.endsWith('@g.us');
  1609. },
  1610. enumerable: true,
  1611. },
  1612. sender: {
  1613. get() {
  1614. return this.conn?.decodeJid(this.key?.fromMe && this.conn?.user.id || this.participant || this.key.participant || this.chat || '')
  1615. },
  1616. enumerable: true
  1617. },
  1618. fromMe: {
  1619. get() {
  1620. return this.key?.fromMe || areJidsSameUser(this.conn?.user.id, this.sender) || false
  1621. }
  1622. },
  1623. mtype: {
  1624. get() {
  1625. if (!this.message) return '';
  1626. const type = Object.keys(this.message);
  1627. return (!['senderKeyDistributionMessage', 'messageContextInfo'].includes(type[0]) && type[0]) || // Sometimes message in the front
  1628. (type.length >= 3 && type[1] !== 'messageContextInfo' && type[1]) || // Sometimes message in midle if mtype length is greater than or equal to 3
  1629. type[type.length - 1]; // common case
  1630. },
  1631. enumerable: true,
  1632. },
  1633. msg: {
  1634. get() {
  1635. if (!this.message) return null;
  1636. return this.message[this.mtype];
  1637. },
  1638. },
  1639. mediaMessage: {
  1640. get() {
  1641. if (!this.message) return null;
  1642. const Message = ((this.msg?.url || this.msg?.directPath) ? {...this.message} : extractMessageContent(this.message)) || null;
  1643. if (!Message) return null;
  1644. const mtype = Object.keys(Message)[0];
  1645. return MediaType.includes(mtype) ? Message : null;
  1646. },
  1647. enumerable: true,
  1648. },
  1649. mediaType: {
  1650. get() {
  1651. let message;
  1652. if (!(message = this.mediaMessage)) return null;
  1653. return Object.keys(message)[0];
  1654. },
  1655. enumerable: true,
  1656. },
  1657. quoted: {
  1658. get() {
  1659. /**
  1660. * @type {ReturnType<typeof makeWASocket>}
  1661. */
  1662. const self = this;
  1663. const msg = self.msg;
  1664. const contextInfo = msg?.contextInfo;
  1665. const quoted = contextInfo?.quotedMessage;
  1666. if (!msg || !contextInfo || !quoted) return null;
  1667. const type = Object.keys(quoted)[0];
  1668. const q = quoted[type];
  1669. const text = typeof q === 'string' ? q : q.text;
  1670. return Object.defineProperties(JSON.parse(JSON.stringify(typeof q === 'string' ? {text: q} : q)), {
  1671. mtype: {
  1672. get() {
  1673. return type;
  1674. },
  1675. enumerable: true,
  1676. },
  1677. mediaMessage: {
  1678. get() {
  1679. const Message = ((q.url || q.directPath) ? {...quoted} : extractMessageContent(quoted)) || null;
  1680. if (!Message) return null;
  1681. const mtype = Object.keys(Message)[0];
  1682. return MediaType.includes(mtype) ? Message : null;
  1683. },
  1684. enumerable: true,
  1685. },
  1686. mediaType: {
  1687. get() {
  1688. let message;
  1689. if (!(message = this.mediaMessage)) return null;
  1690. return Object.keys(message)[0];
  1691. },
  1692. enumerable: true,
  1693. },
  1694. id: {
  1695. get() {
  1696. return contextInfo.stanzaId;
  1697. },
  1698. enumerable: true,
  1699. },
  1700. chat: {
  1701. get() {
  1702. return contextInfo.remoteJid || self.chat;
  1703. },
  1704. enumerable: true,
  1705. },
  1706. isBaileys: {
  1707. get() {
  1708. return (this?.fromMe || areJidsSameUser(this.conn?.user.id, this.sender)) && this.id.startsWith('3EB0') && (this.id.length === 20 || this.id.length === 22 || this.id.length === 12) || false
  1709. },
  1710. enumerable: true,
  1711. },
  1712. sender: {
  1713. get() {
  1714. return (contextInfo.participant || this.chat || '').decodeJid();
  1715. },
  1716. enumerable: true,
  1717. },
  1718. fromMe: {
  1719. get() {
  1720. return areJidsSameUser(this.sender, self.conn?.user.jid);
  1721. },
  1722. enumerable: true,
  1723. },
  1724. text: {
  1725. get() {
  1726. return text || this.caption || this.contentText || this.selectedDisplayText || '';
  1727. },
  1728. enumerable: true,
  1729. },
  1730. mentionedJid: {
  1731. get() {
  1732. return q.contextInfo?.mentionedJid || self.getQuotedObj()?.mentionedJid || [];
  1733. },
  1734. enumerable: true,
  1735. },
  1736. name: {
  1737. get() {
  1738. const sender = this.sender;
  1739. return sender ? self.conn?.getName(sender) : null;
  1740. },
  1741. enumerable: true,
  1742. },
  1743. vM: {
  1744. get() {
  1745. return proto.WebMessageInfo.fromObject({
  1746. key: {
  1747. fromMe: this.fromMe,
  1748. remoteJid: this.chat,
  1749. id: this.id,
  1750. },
  1751. message: quoted,
  1752. ...(self.isGroup ? {participant: this.sender} : {}),
  1753. });
  1754. },
  1755. },
  1756. fakeObj: {
  1757. get() {
  1758. return this.vM;
  1759. },
  1760. },
  1761. download: {
  1762. value(saveToFile = false) {
  1763. const mtype = this.mediaType;
  1764. return self.conn?.downloadM(this.mediaMessage[mtype], mtype.replace(/message/i, ''), saveToFile);
  1765. },
  1766. enumerable: true,
  1767. configurable: true,
  1768. },
  1769. reply: {
  1770. /**
  1771. * Reply to quoted message
  1772. * @param {String|Object} text
  1773. * @param {String|false} chatId
  1774. * @param {Object} options
  1775. */
  1776. value(text, chatId, options) {
  1777. return self.conn?.reply(chatId ? chatId : this.chat, text, this.vM, options);
  1778. },
  1779. enumerable: true,
  1780. },
  1781. copy: {
  1782. /**
  1783. * Copy quoted message
  1784. */
  1785. value() {
  1786. const M = proto.WebMessageInfo;
  1787. return smsg(conn, M.fromObject(M.toObject(this.vM)));
  1788. },
  1789. enumerable: true,
  1790. },
  1791. forward: {
  1792. /**
  1793. * Forward quoted message
  1794. * @param {String} jid
  1795. * @param {Boolean} forceForward
  1796. */
  1797. value(jid, force = false, options) {
  1798. return self.conn?.sendMessage(jid, {
  1799. forward: this.vM, force, ...options,
  1800. }, {...options});
  1801. },
  1802. enumerable: true,
  1803. },
  1804. copyNForward: {
  1805. /**
  1806. * Exact Forward quoted message
  1807. * @param {String} jid
  1808. * @param {Boolean|Number} forceForward
  1809. * @param {Object} options
  1810. */
  1811. value(jid, forceForward = false, options) {
  1812. return self.conn?.copyNForward(jid, this.vM, forceForward, options);
  1813. },
  1814. enumerable: true,
  1815. },
  1816. cMod: {
  1817. /**
  1818. * Modify quoted Message
  1819. * @param {String} jid
  1820. * @param {String} text
  1821. * @param {String} sender
  1822. * @param {Object} options
  1823. */
  1824. value(jid, text = '', sender = this.sender, options = {}) {
  1825. return self.conn?.cMod(jid, this.vM, text, sender, options)
  1826. },
  1827. enumerable: true,
  1828. },
  1829. delete: {
  1830. /**
  1831. * Delete quoted message
  1832. */
  1833. value() {
  1834. return self.conn?.sendMessage(this.chat, { delete: this.vM.key })
  1835. },
  1836. enumerable: true,
  1837. },
  1838. //react
  1839. react: {
  1840. value(text) {
  1841. return self.conn?.sendMessage(this.chat, {
  1842. react: {
  1843. text,
  1844. key: this.vM.key
  1845. }
  1846. })
  1847. },
  1848. enumerable: true,
  1849. }
  1850. //
  1851. })
  1852. },
  1853. enumerable: true
  1854. },
  1855. _text: {
  1856. value: null,
  1857. writable: true,
  1858. },
  1859. text: {
  1860. get() {
  1861. const msg = this.msg
  1862. const text = (typeof msg === 'string' ? msg : msg?.text) || msg?.caption || msg?.contentText || ''
  1863. return typeof this._text === 'string' ? this._text : '' || (typeof text === 'string' ? text : (
  1864. text?.selectedDisplayText ||
  1865. text?.hydratedTemplate?.hydratedContentText ||
  1866. text
  1867. )) || ''
  1868. },
  1869. set(str) {
  1870. return this._text = str
  1871. },
  1872. enumerable: true
  1873. },
  1874. mentionedJid: {
  1875. get() {
  1876. return this.msg?.contextInfo?.mentionedJid?.length && this.msg.contextInfo.mentionedJid || []
  1877. },
  1878. enumerable: true
  1879. },
  1880. name: {
  1881. get() {
  1882. return !nullish(this.pushName) && this.pushName || this.conn?.getName(this.sender)
  1883. },
  1884. enumerable: true
  1885. },
  1886. download: {
  1887. value(saveToFile = false) {
  1888. const mtype = this.mediaType
  1889. return this.conn?.downloadM(this.mediaMessage[mtype], mtype.replace(/message/i, ''), saveToFile)
  1890. },
  1891. enumerable: true,
  1892. configurable: true
  1893. },
  1894. reply: {
  1895. value(text, chatId, options) {
  1896. return this.conn?.reply(chatId ? chatId : this.chat, text, this, options)
  1897. }
  1898. },
  1899. copy: {
  1900. value() {
  1901. const M = proto.WebMessageInfo
  1902. return smsg(this.conn, M.fromObject(M.toObject(this)))
  1903. },
  1904. enumerable: true
  1905. },
  1906. forward: {
  1907. value(jid, force = false, options = {}) {
  1908. return this.conn?.sendMessage(jid, {
  1909. forward: this, force, ...options
  1910. }, { ...options })
  1911. },
  1912. enumerable: true
  1913. },
  1914. copyNForward: {
  1915. value(jid, forceForward = false, options = {}) {
  1916. return this.conn?.copyNForward(jid, this, forceForward, options)
  1917. },
  1918. enumerable: true
  1919. },
  1920. cMod: {
  1921. value(jid, text = '', sender = this.sender, options = {}) {
  1922. return this.conn?.cMod(jid, this, text, sender, options)
  1923. },
  1924. enumerable: true
  1925. },
  1926. getQuotedObj: {
  1927. value() {
  1928. if (!this.quoted.id) return null
  1929. const q = proto.WebMessageInfo.fromObject(this.conn?.loadMessage(this.quoted.id) || this.quoted.vM)
  1930. return smsg(this.conn, q)
  1931. },
  1932. enumerable: true
  1933. },
  1934. getQuotedMessage: {
  1935. get() {
  1936. return this.getQuotedObj
  1937. }
  1938. },
  1939. delete: {
  1940. value() {
  1941. return this.conn?.sendMessage(this.chat, { delete: this.key })
  1942. },
  1943. enumerable: true
  1944. },
  1945. //react
  1946. react: {
  1947. value(text) {
  1948. return this.conn?.sendMessage(this.chat, {
  1949. react: {
  1950. text,
  1951. key: this.key
  1952. }
  1953. })
  1954. },
  1955. enumerable: true
  1956. }
  1957. //
  1958. })
  1959. }
  1960. export function logic(check, inp, out) {
  1961. if (inp.length !== out.length) throw new Error('Input and Output must have same length');
  1962. for (const i in inp) if (util.isDeepStrictEqual(check, inp[i])) return out[i];
  1963. return null;
  1964. }
  1965. export function protoType() {
  1966. Buffer.prototype.toArrayBuffer = function toArrayBufferV2() {
  1967. const ab = new ArrayBuffer(this.length);
  1968. const view = new Uint8Array(ab);
  1969. for (let i = 0; i < this.length; ++i) {
  1970. view[i] = this[i];
  1971. }
  1972. return ab;
  1973. };
  1974. /**
  1975. * @return {ArrayBuffer}
  1976. */
  1977. Buffer.prototype.toArrayBufferV2 = function toArrayBuffer() {
  1978. return this.buffer.slice(this.byteOffset, this.byteOffset + this.byteLength);
  1979. };
  1980. /**
  1981. * @return {Buffer}
  1982. */
  1983. ArrayBuffer.prototype.toBuffer = function toBuffer() {
  1984. return Buffer.from(new Uint8Array(this));
  1985. };
  1986. // /**
  1987. // * @returns {String}
  1988. // */
  1989. // Buffer.prototype.toUtilFormat = ArrayBuffer.prototype.toUtilFormat = Object.prototype.toUtilFormat = Array.prototype.toUtilFormat = function toUtilFormat() {
  1990. // return util.format(this)
  1991. // }
  1992. Uint8Array.prototype.getFileType = ArrayBuffer.prototype.getFileType = Buffer.prototype.getFileType = async function getFileType() {
  1993. return await fileTypeFromBuffer(this);
  1994. };
  1995. /**
  1996. * @returns {Boolean}
  1997. */
  1998. String.prototype.isNumber = Number.prototype.isNumber = isNumber;
  1999. /**
  2000. *
  2001. * @return {String}
  2002. */
  2003. String.prototype.capitalize = function capitalize() {
  2004. return this.charAt(0).toUpperCase() + this.slice(1, this.length);
  2005. };
  2006. /**
  2007. * @return {String}
  2008. */
  2009. String.prototype.capitalizeV2 = function capitalizeV2() {
  2010. const str = this.split(' ');
  2011. return str.map((v) => v.capitalize()).join(' ');
  2012. };
  2013. String.prototype.decodeJid = function decodeJid() {
  2014. if (/:\d+@/gi.test(this)) {
  2015. const decode = jidDecode(this) || {};
  2016. return (decode.user && decode.server && decode.user + '@' + decode.server || this).trim();
  2017. } else return this.trim();
  2018. };
  2019. /**
  2020. * number must be milliseconds
  2021. * @return {string}
  2022. */
  2023. Number.prototype.toTimeString = function toTimeString() {
  2024. // const milliseconds = this % 1000
  2025. const seconds = Math.floor((this / 1000) % 60);
  2026. const minutes = Math.floor((this / (60 * 1000)) % 60);
  2027. const hours = Math.floor((this / (60 * 60 * 1000)) % 24);
  2028. const days = Math.floor((this / (24 * 60 * 60 * 1000)));
  2029. return (
  2030. (days ? `${days} day(s) ` : '') +
  2031. (hours ? `${hours} hour(s) ` : '') +
  2032. (minutes ? `${minutes} minute(s) ` : '') +
  2033. (seconds ? `${seconds} second(s)` : '')
  2034. ).trim();
  2035. };
  2036. Number.prototype.getRandom = String.prototype.getRandom = Array.prototype.getRandom = getRandom;
  2037. }
  2038. function isNumber() {
  2039. const int = parseInt(this);
  2040. return typeof int === 'number' && !isNaN(int);
  2041. }
  2042. function getRandom() {
  2043. if (Array.isArray(this) || this instanceof String) return this[Math.floor(Math.random() * this.length)];
  2044. return Math.floor(Math.random() * this);
  2045. }
  2046. /**
  2047. * ??
  2048. * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
  2049. * @return {boolean}
  2050. */
  2051. function nullish(args) {
  2052. return !(args !== null && args !== undefined);
  2053. }