Spaces:
Paused
Paused
| import { | |
| getContentType, | |
| jidDecode, | |
| downloadMediaMessage, | |
| downloadContentFromMessage, | |
| generateWAMessage, | |
| areJidsSameUser, | |
| generateForwardMessageContent, | |
| makeInMemoryStore | |
| } from "@whiskeysockets/baileys"; | |
| import { fileTypeFromBuffer } from 'file-type'; | |
| import fs from 'fs'; | |
| import pino from 'pino'; | |
| import path from 'path'; | |
| import PhoneNumber from 'awesome-phonenumber'; | |
| import config from '../config.cjs'; | |
| import { imageToWebp, videoToWebp, writeExifImg, writeExifVid } from '../lib/exif.cjs'; | |
| import { getBuffer, getSizeMedia } from '../lib/myfunc.cjs' | |
| import baileys from "@whiskeysockets/baileys"; | |
| const proto = baileys.proto; | |
| const store = makeInMemoryStore({ logger: pino().child({ level: 'silent', stream: 'store' }) }) | |
| const __filename = new URL(import.meta.url).pathname; | |
| const __dirname = path.dirname(__filename); | |
| function decodeJid(jid) { | |
| const { user, server } = jidDecode(jid) || {}; | |
| return user && server ? `${user}@${server}`.trim() : jid; | |
| } | |
| const downloadMedia = async message => { | |
| let type = Object.keys(message)[0]; | |
| let m = message[type]; | |
| if (type === "buttonsMessage" || type === "viewOnceMessageV2") { | |
| if (type === "viewOnceMessageV2") { | |
| m = message.viewOnceMessageV2?.message; | |
| type = Object.keys(m || {})[0]; | |
| } else type = Object.keys(m || {})[1]; | |
| m = m[type]; | |
| } | |
| const stream = await downloadContentFromMessage( | |
| m, | |
| type.replace("Message", "") | |
| ); | |
| let buffer = Buffer.from([]); | |
| for await (const chunk of stream) { | |
| buffer = Buffer.concat([buffer, chunk]); | |
| } | |
| return buffer; | |
| }; | |
| function serialize(m, sock, logger) { | |
| // downloadFile function | |
| async function downloadFile(m) { | |
| try { | |
| const buffer = await downloadMediaMessage( | |
| m, | |
| "buffer", | |
| {}, | |
| { logger, reuploadRequest: sock.updateMediaMessage } | |
| ); | |
| return buffer; | |
| } catch (error) { | |
| console.error('Error downloading media:', error); | |
| return null; // or throw the error if you want to propagate it | |
| } | |
| } | |
| // React function | |
| async function React(emoji) { | |
| let reactm = { | |
| react: { | |
| text: emoji, | |
| key: m.key, | |
| }, | |
| }; | |
| await sock.sendMessage(m.from, reactm); | |
| } | |
| // Define the decodeJid function | |
| sock.decodeJid = (jid) => { | |
| if (!jid) return jid; | |
| if (/:\d+@/gi.test(jid)) { | |
| let decode = jidDecode(jid) || {}; | |
| return decode.user && decode.server && decode.user + '@' + decode.server || jid; | |
| } else { | |
| return jid; | |
| } | |
| }; | |
| // Define event listener for contacts update | |
| sock.ev.on('contacts.update', update => { | |
| for (let contact of update) { | |
| let id = sock.decodeJid(contact.id); | |
| if (store && store.contacts) { | |
| store.contacts[id] = { id, name: contact.notify }; | |
| } | |
| } | |
| }); | |
| // Define the getName function | |
| sock.getName = (jid, withoutContact = false) => { | |
| jid = sock.decodeJid(jid); | |
| withoutContact = sock.withoutContact || withoutContact; | |
| let v; | |
| if (jid.endsWith("@g.us")) { | |
| return new Promise(async (resolve) => { | |
| v = store.contacts[jid] || {}; | |
| if (!(v.name || v.subject)) v = await sock.groupMetadata(jid) || {}; | |
| resolve(v.name || v.subject || PhoneNumber('+' + jid.replace('@s.whatsapp.net', '')).getNumber('international')); | |
| }); | |
| } else { | |
| v = jid === '0@s.whatsapp.net' ? { | |
| id: jid, | |
| name: 'WhatsApp' | |
| } : jid === sock.decodeJid(sock.user.id) ? | |
| sock.user : | |
| (store.contacts[jid] || {}); | |
| return (withoutContact ? '' : v.name) || v.subject || v.verifiedName || PhoneNumber('+' + jid.replace('@s.whatsapp.net', '')).getNumber('international'); | |
| } | |
| }; | |
| // Define the sendContact function | |
| sock.sendContact = async (jid, kon, quoted = '', opts = {}) => { | |
| let list = []; | |
| for (let i of kon) { | |
| let name = config.OWNER_NAME; | |
| list.push({ | |
| displayName: name, | |
| vcard: `BEGIN:VCARD\nVERSION:3.0\nN:${await sock.getName(i + "@s.whatsapp.net")}\nFN:${name}\nitem1.TEL;waid=${i}:${i}\nitem1.X-ABLabel:Click here to chat\nEND:VCARD` | |
| }); | |
| } | |
| sock.sendMessage(jid, { contacts: { displayName: `${list.length} Kontak`, contacts: list }, ...opts }, { quoted }); | |
| }; | |
| /** | |
| * | |
| * @param {*} jid | |
| * @param {*} path | |
| * @param {*} quoted | |
| * @param {*} options | |
| * @returns | |
| */ | |
| sock.sendImageAsSticker = async (jid, path, quoted, options = {}) => { | |
| let buff = Buffer.isBuffer(path) ? path : /^data:.*?\/.*?;base64,/i.test(path) ? Buffer.from(path.split`,`[1], 'base64') : /^https?:\/\//.test(path) ? await (await getBuffer(path)) : fs.existsSync(path) ? fs.readFileSync(path) : Buffer.alloc(0) | |
| let buffer | |
| if (options && (options.packname || options.author)) { | |
| buffer = await writeExifImg(buff, options) | |
| } else { | |
| buffer = await imageToWebp(buff) | |
| } | |
| await sock.sendMessage(jid, { sticker: { url: buffer }, ...options }, { quoted }) | |
| return buffer | |
| } | |
| /** | |
| * | |
| * @param {*} jid | |
| * @param {*} path | |
| * @param {*} quoted | |
| * @param {*} options | |
| * @returns | |
| */ | |
| sock.sendVideoAsSticker = async (jid, path, quoted, options = {}) => { | |
| let buff = Buffer.isBuffer(path) ? path : /^data:.*?\/.*?;base64,/i.test(path) ? Buffer.from(path.split`,`[1], 'base64') : /^https?:\/\//.test(path) ? await (await getBuffer(path)) : fs.existsSync(path) ? fs.readFileSync(path) : Buffer.alloc(0) | |
| let buffer | |
| if (options && (options.packname || options.author)) { | |
| buffer = await writeExifVid(buff, options) | |
| } else { | |
| buffer = await videoToWebp(buff) | |
| } | |
| await sock.sendMessage(jid, { sticker: { url: buffer }, ...options }, { quoted }) | |
| return buffer | |
| } | |
| /** | |
| * | |
| * @param {*} jid | |
| * @param {*} name | |
| * @param {*} values | |
| * @returns | |
| */ | |
| sock.sendPoll = (jid, name = '', values = [], selectableCount = 1) => { return sock.sendMessage(jid, { poll: { name, values, selectableCount } }) } | |
| /** | |
| * | |
| * @param {*} jid | |
| * @param {*} path | |
| * @param {*} filename | |
| * @param {*} caption | |
| * @param {*} quoted | |
| * @param {*} options | |
| * @returns | |
| */ | |
| sock.sendMedia = async (jid, path, fileName = '', caption = '', quoted = '', options = {}) => { | |
| let types = await sock.getFile(path, true) | |
| let { mime, ext, res, data, filename } = types | |
| if (res && res.status !== 200 || file.length <= 65536) { | |
| try { throw { json: JSON.parse(file.toString()) } } | |
| catch (e) { if (e.json) throw e.json } | |
| } | |
| let type = '', mimetype = mime, pathFile = filename | |
| if (options.asDocument) type = 'document' | |
| if (options.asSticker || /webp/.test(mime)) { | |
| let { writeExif } = require('./lib/exif') | |
| let media = { mimetype: mime, data } | |
| pathFile = await writeExif(media, { packname: options.packname ? options.packname : global.packname, author: options.author ? options.author : global.author, categories: options.categories ? options.categories : [] }) | |
| await fs.promises.unlink(filename) | |
| type = 'sticker' | |
| mimetype = 'image/webp' | |
| } | |
| else if (/image/.test(mime)) type = 'image' | |
| else if (/video/.test(mime)) type = 'video' | |
| else if (/audio/.test(mime)) type = 'audio' | |
| else type = 'document' | |
| await sock.sendMessage(jid, { [type]: { url: pathFile }, caption, mimetype, fileName, ...options }, { quoted, ...options }) | |
| return fs.promises.unlink(pathFile) | |
| } | |
| /** | |
| * | |
| * @param {*} message | |
| * @param {*} filename | |
| * @param {*} attachExtension | |
| * @returns | |
| */ | |
| sock.getFile = async (PATH, save) => { | |
| let res, filename | |
| let data = Buffer.isBuffer(PATH) ? PATH : /^data:.*?\/.*?;base64,/i.test(PATH) ? Buffer.from(PATH.split`,`[1], 'base64') : /^https?:\/\//.test(PATH) ? (res = await getBuffer(PATH)) : fs.existsSync(PATH) ? (filename = PATH, fs.readFileSync(PATH)) : typeof PATH === 'string' ? PATH : Buffer.alloc(0) | |
| if (!Buffer.isBuffer(data)) throw new TypeError('Result is not a buffer') | |
| let type = await fileTypeFromBuffer(data) || { | |
| mime: 'application/octet-stream', | |
| ext: '.bin' | |
| } | |
| if (data && save && !filename) (filename = path.join(__dirname, './' + new Date * 1 + '.' + type.ext), await fs.promises.writeFile(filename, data)) | |
| return { | |
| res, | |
| filename, | |
| size: await getSizeMedia(data), | |
| ...type, | |
| data | |
| } | |
| } | |
| /** | |
| * | |
| * @param {*} message | |
| * @param {*} filename | |
| * @param {*} attachExtension | |
| * @returns | |
| */ | |
| sock.downloadAndSaveMediaMessage = async (message, filename, attachExtension = true) => { | |
| let quoted = message.msg ? message.msg : message; | |
| let mime = (message.msg || message).mimetype || ''; | |
| let messageType = message.mtype ? message.mtype.replace(/Message/gi, '') : mime.split('/')[0]; | |
| const stream = await downloadContentFromMessage(quoted, messageType); | |
| let buffer = Buffer.from([]); | |
| for await (const chunk of stream) { | |
| buffer = Buffer.concat([buffer, chunk]); | |
| } | |
| const type = await fileTypeFromBuffer(buffer); | |
| const trueFileName = attachExtension ? `${filename}.${type.ext}` : filename; | |
| // save to file | |
| await fs.promises.writeFile(trueFileName, buffer); | |
| return trueFileName; | |
| } | |
| sock.downloadMediaMessage = async (message) => { | |
| let mime = (message.msg || message).mimetype || ''; | |
| let messageType = message.mtype ? message.mtype.replace(/Message/gi, '') : mime.split('/')[0]; | |
| const stream = await downloadContentFromMessage(message, messageType); | |
| let buffer = Buffer.from([]); | |
| for await (const chunk of stream) { | |
| buffer = Buffer.concat([buffer, chunk]); | |
| } | |
| return buffer; | |
| } | |
| /** | |
| * | |
| * @param {*} jid | |
| * @param {*} message | |
| * @param {*} forceForward | |
| * @param {*} options | |
| * @returns | |
| */ | |
| sock.copyNForward = async (jid, message, forceForward = false, options = {}) => { | |
| let vtype | |
| if (options.readViewOnce) { | |
| message.message = message.message && message.message.ephemeralMessage && message.message.ephemeralMessage.message ? message.message.ephemeralMessage.message : (message.message || undefined) | |
| vtype = Object.keys(message.message.viewOnceMessage.message)[0] | |
| delete(message.message && message.message.ignore ? message.message.ignore : (message.message || undefined)) | |
| delete message.message.viewOnceMessage.message[vtype].viewOnce | |
| message.message = { | |
| ...message.message.viewOnceMessage.message | |
| } | |
| } | |
| let mtype = Object.keys(message.message)[0] | |
| let content = await generateForwardMessageContent(message, forceForward) | |
| let ctype = Object.keys(content)[0] | |
| let context = {} | |
| if (mtype != "conversation") context = message.message[mtype].contextInfo | |
| content[ctype].contextInfo = { | |
| ...context, | |
| ...content[ctype].contextInfo | |
| } | |
| const waMessage = await generateWAMessageFromContent(jid, content, options ? { | |
| ...content[ctype], | |
| ...options, | |
| ...(options.contextInfo ? { | |
| contextInfo: { | |
| ...content[ctype].contextInfo, | |
| ...options.contextInfo | |
| } | |
| } : {}) | |
| } : {}) | |
| await sock.relayMessage(jid, waMessage.message, { messageId: waMessage.key.id }) | |
| return waMessage | |
| } | |
| sock.cMod = (jid, copy, text = '', sender = sock.user.id, options = {}) => { | |
| //let copy = message.toJSON() | |
| let mtype = Object.keys(copy.message)[0] | |
| let isEphemeral = mtype === 'ephemeralMessage' | |
| if (isEphemeral) { | |
| mtype = Object.keys(copy.message.ephemeralMessage.message)[0] | |
| } | |
| let msg = isEphemeral ? copy.message.ephemeralMessage.message : copy.message | |
| let content = msg[mtype] | |
| if (typeof content === 'string') msg[mtype] = text || content | |
| else if (content.caption) content.caption = text || content.caption | |
| else if (content.text) content.text = text || content.text | |
| if (typeof content !== 'string') msg[mtype] = { | |
| ...content, | |
| ...options | |
| } | |
| if (copy.key.participant) sender = copy.key.participant = sender || copy.key.participant | |
| else if (copy.key.participant) sender = copy.key.participant = sender || copy.key.participant | |
| if (copy.key.remoteJid.includes('@s.whatsapp.net')) sender = sender || copy.key.remoteJid | |
| else if (copy.key.remoteJid.includes('@broadcast')) sender = sender || copy.key.remoteJid | |
| copy.key.remoteJid = jid | |
| copy.key.fromMe = sender === sock.user.id | |
| return proto.WebMessageInfo.fromObject(copy) | |
| } | |
| if (m.key) { | |
| m.id = m.key.id; | |
| m.isSelf = m.key.fromMe; | |
| m.from = decodeJid(m.key.remoteJid); | |
| m.isGroup = m.from.endsWith("@g.us"); | |
| m.sender = m.isGroup | |
| ? decodeJid(m.key.participant) | |
| : m.isSelf | |
| ? decodeJid(sock.user.id) | |
| : m.from; | |
| } | |
| if (m.message) { | |
| m.type = getContentType(m.message); | |
| if (m.type === "ephemeralMessage") { | |
| m.message = m.message[m.type].message; | |
| const tipe = Object.keys(m.message)[0]; | |
| m.type = tipe; | |
| if (tipe === "viewOnceMessageV2") { | |
| m.message = m.message[m.type].message; | |
| m.type = getContentType(m.message); | |
| } | |
| } | |
| if (m.type === "viewOnceMessageV2") { | |
| m.message = m.message[m.type].message; | |
| m.type = getContentType(m.message); | |
| } | |
| m.messageTypes = type => | |
| ["videoMessage", "imageMessage"].includes(type); | |
| try { | |
| const quoted = m.message[m.type]?.contextInfo; | |
| if (quoted.quotedMessage["ephemeralMessage"]) { | |
| const tipe = Object.keys( | |
| quoted.quotedMessage.ephemeralMessage.message | |
| )[0]; | |
| if (tipe === "viewOnceMessageV2") { | |
| m.quoted = { | |
| type: "view_once", | |
| stanzaId: quoted.stanzaId, | |
| participant: decodeJid(quoted.participant), | |
| message: | |
| quoted.quotedMessage.ephemeralMessage.message | |
| .viewOnceMessageV2.message | |
| }; | |
| } else { | |
| m.quoted = { | |
| type: "ephemeral", | |
| stanzaId: quoted.stanzaId, | |
| participant: decodeJid(quoted.participant), | |
| message: quoted.quotedMessage.ephemeralMessage.message | |
| }; | |
| } | |
| } else if (quoted.quotedMessage["viewOnceMessageV2"]) { | |
| m.quoted = { | |
| type: "view_once", | |
| stanzaId: quoted.stanzaId, | |
| participant: decodeJid(quoted.participant), | |
| message: quoted.quotedMessage.viewOnceMessageV2.message | |
| }; | |
| } else { | |
| m.quoted = { | |
| type: "normal", | |
| stanzaId: quoted.stanzaId, | |
| participant: decodeJid(quoted.participant), | |
| message: quoted.quotedMessage | |
| }; | |
| } | |
| m.quoted.isSelf = | |
| m.quoted.participant === decodeJid(sock.user.id); | |
| m.quoted.mtype = Object.keys(m.quoted.message).filter( | |
| v => v.includes("Message") || v.includes("conversation") | |
| )[0]; | |
| m.quoted.text = | |
| m.quoted.message[m.quoted.mtype]?.text || | |
| m.quoted.message[m.quoted.mtype]?.description || | |
| m.quoted.message[m.quoted.mtype]?.caption || | |
| m.quoted.message[m.quoted.mtype]?.hydratedTemplate | |
| ?.hydratedContentText || | |
| m.quoted.message[m.quoted.mtype] || | |
| ""; | |
| m.quoted.key = { | |
| id: m.quoted.stanzaId, | |
| fromMe: m.quoted.isSelf, | |
| remoteJid: m.from | |
| }; | |
| m.quoted.download = () => downloadMedia(m.quoted.message); | |
| } catch { | |
| m.quoted = null; | |
| } | |
| m.body = | |
| m.message?.conversation || | |
| m.message?.[m.type]?.text || | |
| m.message?.[m.type]?.caption || | |
| (m.type === "listResponseMessage" && | |
| m.message?.[m.type]?.singleSelectReply?.selectedRowId) || | |
| (m.type === "buttonsResponseMessage" && | |
| m.message?.[m.type]?.selectedButtonId) || | |
| (m.type === "templateButtonReplyMessage" && | |
| m.message?.[m.type]?.selectedId) || | |
| ""; | |
| m.reply = text => sock.sendMessage(m.from, { text }, { quoted: m }); | |
| m.mentions = []; | |
| if (m.quoted?.participant) m.mentions.push(m.quoted.participant); | |
| const array = m?.message?.[m.type]?.contextInfo?.mentionedJid || []; | |
| m.mentions.push(...array.filter(Boolean)); | |
| m.download = () => downloadMedia(m.message); | |
| m.downloadFile = () => downloadFile(m); | |
| m.React = (emoji) => React(emoji); | |
| } | |
| // New getQuotedObj function | |
| m.getQuotedObj = async () => { | |
| if (!m.quoted) return null; | |
| let qKey = m.message.extendedTextMessage.contextInfo.stanzaId; | |
| let qMsg = store.loadMessage(m.from, qKey, sock); | |
| return serialize(qMsg, sock, logger); | |
| }; | |
| /** | |
| * Copy this message | |
| */ | |
| m.copy = () => exports.smsg(sock, M.fromObject(M.toObject(m))) | |
| /** | |
| * | |
| * @param {*} jid | |
| * @param {*} forceForward | |
| * @param {*} options | |
| * @returns | |
| */ | |
| m.copyNForward = (jid = m.from, forceForward = false, options = {}) => sock.copyNForward(jid, m, forceForward, options) | |
| sock.appenTextMessage = async(text, chatUpdate) => { | |
| let messages = await generateWAMessage(m.from, { text: text, mentions: m.mentionedJid }, { | |
| userJid: sock.user.id, | |
| quoted: m.quoted && m.quoted.fakeObj | |
| }) | |
| messages.key.fromMe = areJidsSameUser(m.sender, sock.user.id) | |
| messages.key.id = m.key.id | |
| messages.pushName = m.pushName | |
| if (m.isGroup) messages.participant = m.sender | |
| let msg = { | |
| ...chatUpdate, | |
| messages: [proto.WebMessageInfo.fromObject(messages)], | |
| type: 'append' | |
| } | |
| sock.ev.emit('messages.upsert', msg) | |
| } | |
| return m; | |
| } | |
| export { decodeJid, serialize }; | |