|
| 1 | +const fs = require('fs') |
| 2 | +const util = require('util') |
| 3 | +const path = require('path') |
| 4 | +const FileType = require('file-type') |
| 5 | +const fetch = require('node-fetch') |
| 6 | +const { spawn } = require('child_process') |
| 7 | +const { MessageType } = require('@adiwajshing/baileys') |
| 8 | + |
| 9 | +exports.WAConnection = (_WAConnection) => { |
| 10 | + class WAConnection extends _WAConnection { |
| 11 | + constructor(...args) { |
| 12 | + super(...args) |
| 13 | + } |
| 14 | + |
| 15 | + async waitEvent(eventName) { |
| 16 | + return await (new Promise(resolve => this.once(eventName, resolve))) |
| 17 | + } |
| 18 | + |
| 19 | + async sendFile(jid, path, filename = '', caption = '', quoted, ptt = false, options = {}) { |
| 20 | + let file = Buffer.isBuffer(path) ? path : /^data:.*?\/.*?;base64,/i.test(path) ? Buffer.from(path.split`,`[1], 'base64') : /^https?:\/\//.test(path) ? await (await fetch(path)).buffer() : fs.existsSync(path) ? fs.readFileSync(path) : Buffer.alloc(0) |
| 21 | + const type = await FileType.fromBuffer(file) || { |
| 22 | + mime: 'application/octet-stream', |
| 23 | + ext: '.bin' |
| 24 | + } |
| 25 | + if (!type) { |
| 26 | + options.asDocument = true |
| 27 | + } |
| 28 | + let mtype = '' |
| 29 | + let opt = { filename, caption } |
| 30 | + if (!options.asDocument) { |
| 31 | + if (/audio/.test(type.mime)) file = await (ptt ? toPTT : toAudio)(file, type.ext) |
| 32 | + else if (/video/.test(type.mime)) file = await toVideo(file, type.ext) |
| 33 | + if (/image/.test(type.mime)) mtype = MessageType.image |
| 34 | + else if (/video/.test(type.mime)) mtype = MessageType.video |
| 35 | + else opt.caption = filename |
| 36 | + if (/audio/.test(type.mime)) { |
| 37 | + mtype = MessageType.audio |
| 38 | + opt.ptt = ptt |
| 39 | + } else if (/pdf/.test(type.ext)) mtype = MessageType.pdf |
| 40 | + else if (!mtype) { |
| 41 | + mtype = MessageType.document |
| 42 | + opt.mimetype = type.mime |
| 43 | + } |
| 44 | + delete options.asDocument |
| 45 | + } else { |
| 46 | + mtype = MessageType.document |
| 47 | + opt.mimetype = type.mime |
| 48 | + } |
| 49 | + if (quoted) opt.quoted = quoted |
| 50 | + return await this.sendMessage(jid, file, mtype, {...opt, ...options}) |
| 51 | + } |
| 52 | + |
| 53 | + reply(jid, text, quoted, options) { |
| 54 | + return this.sendMessage(jid, text, MessageType.extendedText, { quoted, ...options }) |
| 55 | + } |
| 56 | + |
| 57 | + fakeReply(jid, text = '', fakeJid = this.user.jid, fakeText = '', fakeGroupJid) { |
| 58 | + return this.reply(jid, text, { key: { fromMe: fakeJid == this.user.jid, participant: fakeJid, ...(fakeGroupJid ? { remoteJid: fakeGroupJid } : {}) }, message: { conversation: fakeText }}) |
| 59 | + } |
| 60 | + |
| 61 | + parseMention(text) { |
| 62 | + return [...text.matchAll(/@(\d{5,16})/g)].map(v => v[1] + '@s.whatsapp.net') |
| 63 | + } |
| 64 | + |
| 65 | + getName(jid) { |
| 66 | + let v = jid === this.user.jid ? this.user : this.contacts[jid] || { notify: jid.replace(/@.+/, '') } |
| 67 | + return v.name || v.vname || v.notify |
| 68 | + } |
| 69 | + |
| 70 | + async downloadM(m) { |
| 71 | + if (!m) return Buffer.alloc(0) |
| 72 | + if (!m.message) return Buffer.alloc(0) |
| 73 | + if (!m.message[Object.keys(m.message)[0]].url) await this.updateMediaMessage(m) |
| 74 | + return await this.downloadMediaMessage(m) |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + return WAConnection |
| 79 | +} |
| 80 | + |
| 81 | +exports.smsg = (conn, m, hasParent) => { |
| 82 | + if (!m) return m |
| 83 | + if (m.key) { |
| 84 | + m.id = m.key.id |
| 85 | + m.isBaileys = m.id.startsWith('3EB0') && m.id.length === 12 |
| 86 | + m.chat = m.key.remoteJid |
| 87 | + m.fromMe = m.key.fromMe |
| 88 | + m.isGroup = m.chat.endsWith('@g.us') |
| 89 | + m.sender = m.fromMe ? conn.user.jid : m.isGroup ? m.participant : m.chat |
| 90 | + } |
| 91 | + if (m.message) { |
| 92 | + m.mtype = Object.keys(m.message)[0] |
| 93 | + m.msg = m.message[m.mtype] |
| 94 | + if (m.mtype === 'ephemeralMessage') { |
| 95 | + exports.smsg(conn, m.msg) |
| 96 | + m.mtype = m.msg.mtype |
| 97 | + m.msg = m.msg.msg |
| 98 | + } |
| 99 | + m.quoted = m.msg.contextInfo ? m.msg.contextInfo.quotedMessage : null |
| 100 | + m.mentionedJid = m.msg.contextInfo ? m.msg.contextInfo.mentionedJid : [] |
| 101 | + if (m.quoted) { |
| 102 | + let type = Object.keys(m.quoted)[0] |
| 103 | + m.quoted = m.quoted[type] |
| 104 | + if (typeof m.quoted == 'string') m.quoted = { text: m.quoted } |
| 105 | + m.quoted.mtype = type |
| 106 | + m.quoted.id = m.msg.contextInfo.stanzaId |
| 107 | + m.quoted.isBaileys = m.quoted.id.startsWith('3EB0') && m.quoted.id.length === 12 |
| 108 | + m.quoted.sender = m.msg.contextInfo.participant |
| 109 | + m.quoted.fromMe = m.quoted.sender == conn.user.jid |
| 110 | + m.quoted.text = m.quoted.text || m.quoted.caption || '' |
| 111 | + m.getQuotedObj = async () => { |
| 112 | + let q |
| 113 | + await conn.findMessage(m.chat, 25, s => { |
| 114 | + q = s |
| 115 | + return s.key ? s.key.id == m.quoted.id : false |
| 116 | + }) |
| 117 | + return q && m.quoted.id == q.key.id ? exports.smsg(conn, q) : false |
| 118 | + } |
| 119 | + } |
| 120 | + m.text = m.msg.text || m.msg.caption || m.msg || '' |
| 121 | + m.reply = (text, chatId, options) => conn.reply(chatId ? chatId : m.chat, text, m, options) |
| 122 | + } |
| 123 | +} |
| 124 | + |
| 125 | +exports.logic = (check, inp, out) => { |
| 126 | + if (inp.length !== out.length) throw new Error('Input and Output must have same length') |
| 127 | + for (let i in inp) if (util.isDeepStrictEqual(check, inp[i])) return out[i] |
| 128 | + return null |
| 129 | +} |
| 130 | + |
| 131 | +function toAudio(buffer, ext) { |
| 132 | + return new Promise((resolve, reject) => { |
| 133 | + let tmp = path.join(__dirname, '../tmp', (new Date * 1) + '.' + ext) |
| 134 | + let out = tmp.replace(new RegExp(ext + '$'), 'mp3') |
| 135 | + fs.writeFileSync(tmp, buffer) |
| 136 | + spawn('ffmpeg', [ |
| 137 | + '-y', |
| 138 | + '-i',tmp, |
| 139 | + '-vn', |
| 140 | + '-c:a','aac', |
| 141 | + '-b:a','128k', |
| 142 | + '-ar','44100', |
| 143 | + '-f', 'mp3', |
| 144 | + out |
| 145 | + ]) |
| 146 | + .on('error', reject) |
| 147 | + .on('error', () => fs.unlinkSync(tmp)) |
| 148 | + .on('close', () => { |
| 149 | + resolve(fs.readFileSync(out)) |
| 150 | + fs.unlinkSync(tmp) |
| 151 | + if (fs.existsSync(out)) fs.unlinkSync(out) |
| 152 | + }) |
| 153 | + }) |
| 154 | +} |
| 155 | + |
| 156 | +function toPTT(buffer, ext) { |
| 157 | + return new Promise((resolve, reject) => { |
| 158 | + let tmp = path.join(__dirname, '../tmp', (new Date * 1) + '.' + ext) |
| 159 | + let out = tmp.replace(new RegExp(ext + '$'), 'opus') |
| 160 | + fs.writeFileSync(tmp, buffer) |
| 161 | + spawn('ffmpeg', [ |
| 162 | + '-y', |
| 163 | + '-i',tmp, |
| 164 | + '-vn', |
| 165 | + '-c:a','libopus', |
| 166 | + '-b:a','128k', |
| 167 | + '-vbr','on', |
| 168 | + '-compression_level','10', |
| 169 | + out, |
| 170 | + ]) |
| 171 | + .on('error', reject) |
| 172 | + .on('error', () => fs.unlinkSync(tmp)) |
| 173 | + .on('close', () => { |
| 174 | + resolve(fs.readFileSync(out)) |
| 175 | + fs.unlinkSync(tmp) |
| 176 | + if (fs.existsSync(out)) fs.unlinkSync(out) |
| 177 | + }) |
| 178 | + }) |
| 179 | +} |
| 180 | + |
| 181 | +function toVideo(buffer, ext) { |
| 182 | + return new Promise((resolve, reject) => { |
| 183 | + let tmp = path.join(__dirname, '../tmp', (new Date * 1) + '.' + ext) |
| 184 | + let out = tmp.replace(new RegExp(ext + '$'), 'mp4') |
| 185 | + fs.writeFileSync(tmp, buffer) |
| 186 | + spawn('ffmpeg', [ |
| 187 | + '-y', |
| 188 | + '-i',tmp, |
| 189 | + '-c:v','libx264', |
| 190 | + '-c:a','aac', |
| 191 | + '-ab','192k', |
| 192 | + '-ar','44100', |
| 193 | + out |
| 194 | + ]) |
| 195 | + .on('error', reject) |
| 196 | + .on('error', () => fs.unlinkSync(tmp)) |
| 197 | + .on('close', () => { |
| 198 | + resolve(fs.readFileSync(out)) |
| 199 | + fs.unlinkSync(tmp) |
| 200 | + if (fs.existsSync(out)) fs.unlinkSync(out) |
| 201 | + }) |
| 202 | + }) |
| 203 | +} |
0 commit comments