UNPKG

innovators-bot2

Version:
1,098 lines (999 loc) • 97.8 kB
const { WhatsAppClient, STATUS_BACKGROUNDS, STATUS_FONTS, renderLatexToPng, uploadUnencryptedToWA, RichSubMessageType } = require('./index') const qrcode = require('qrcode-terminal') const fs = require('fs'); const readline = require('readline'); const path = require('path'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); String.prototype.toTitleCase = function () { return this.split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(' '); }; const question = (text) => new Promise((resolve) => rl.question(text, resolve)); async function start() { const sessionDir = ".Sessions"; const hasSession = fs.existsSync(path.join(sessionDir, 'creds.json')); let authMethod = 'qr'; let pairingPhoneNumber = null; if (!hasSession) { console.log('\nšŸ“± WhatsApp Bot Setup'); console.log('-------------------'); console.log('1. QR Code'); console.log('2. Pairing Code'); const choice = await question('\nChoose authentication method (1 or 2): '); authMethod = choice === '2' ? 'pairing' : 'qr'; if (authMethod === 'pairing') { pairingPhoneNumber = await question('Enter phone number for pairing (e.g. 923224559543): '); if (!pairingPhoneNumber) { console.log('āŒ Phone number is required for pairing method.'); process.exit(1); } } } else { console.log('\nšŸ”„ Existing session found! Skipping setup...'); } rl.close(); const client = new WhatsAppClient({ sessionName: sessionDir, authmethod: authMethod, pairingPhoneNumber: pairingPhoneNumber, ai: true, // Enable/Disable AI flag for outgoing messages (default: true) // Message store persistence configuration messageStoreFilePath: path.join(sessionDir, 'message-store.json'), autoSaveInterval: 5 * 60 * 1000, // Auto-save every 5 minutes maxMessagesPerChat: 1000, // Keep last 1000 messages per chat messageTTL: 24 * 60 * 60 * 1000 // Messages expire after 24 hours }); console.log(`\nšŸš€ Initializing with ${authMethod} method...`); // Handle QR Code client.on('qr', qr => { console.log('\nāœ… QR Code received. Scan it with WhatsApp:') qrcode.generate(qr, { small: true }) }) client.on('pairing-code', (code) => { console.log(`\nāœ… Pairing code for ${pairingPhoneNumber}: ${code}`) }) // Handle connection events client.on('connecting', (message) => { console.log('ā³ Client status:', message) }) client.on('connected', (user) => { console.log('\n✨ Client is ready!') console.log('User:', user.name) console.log('Phone:', user.phone) console.log('Plateform:', user.platform) console.log('isOnline:', user.isOnline) }) // Handle LID mapping updates client.on('lid-mapping-update', (update) => { console.log('šŸ“¦ New LID/PN mappings received') }) // Handle Contact Events client.on('contacts-received', (contacts) => { console.log(`\nšŸ‘„ History Sync: Received ${contacts.length} contacts`); }) client.on('contacts-upsert', (contacts) => { console.log(`\nšŸ‘„ New Contacts: ${contacts.length} contacts added/updated`); }) client.on('contacts-update', (updates) => { console.log(`\nšŸ‘„ Contact Updates: ${updates.length} contacts modified`); }) // Handle Anti-Delete system client.on('message-deleted', async (data) => { console.log(`\nšŸ›”ļø Message from ${data.jid} was deleted!`) await client.sendMessage(data.jid, 'āš ļø I saw you deleted that message! I have it saved in my memory. šŸ˜‰', { quoted: data.originalMessage }); }) // Example of listening to the new events client.on('message-stored', (messages) => { //console.log(`${messages.length} messages were just cached in the store.`); }); client.on('store-loaded', (info) => { console.log(`\nšŸ’¾ Message store loaded: ${info.messageCount} messages restored from file`); }); client.on('store-cleared', () => { console.log('Main message store has been purged.'); }); // Handle message reactions client.on('message-reaction', async (reaction) => { console.log('\nšŸ‘ Message Reaction Received!') console.log('Chat:', reaction.from) console.log('Sender:', reaction.sender) console.log('Emoji:', reaction.emoji || '(removed)') console.log('Is Removed:', reaction.isRemoved) console.log('Message ID:', reaction.messageKey.id) }) client.on('poll-votes-update', async (data) => { console.log('\nšŸ“Š Poll Votes Updated!'); console.log('Chat:', data.jid); console.log('Voter:', data.voter); // 1. Extract Poll Creation Message (Question, Options, etc.) const pollCreation = data.pollCreationMessage; if (pollCreation && pollCreation.message) { const pollMessage = pollCreation.message.pollCreationMessage || pollCreation.message.pollCreationMessageV2 || pollCreation.message.pollCreationMessageV3; if (pollMessage) { console.log('\nšŸ“ Poll Creation Details:'); console.log('Question:', pollMessage.name); console.log('Options:', pollMessage.options?.map(o => o.optionName) || []); } } // 2. Extract voters array from pollUpdate console.log('\nšŸ—³ļø Vote Breakdown:'); let totalVotesCount = 0; data.pollUpdate.forEach((option) => { console.log(`--> ${option.name}: ${option.voters.length} vote(s) ${JSON.stringify(option.voters)}`); totalVotesCount += option.voters.length; }); console.log(`--> Total Votes Cast: ${totalVotesCount}`); const winner = data.pollUpdate.reduce((prev, current) => prev.voters.length > current.voters.length ? prev : current); console.log(`--> The Winner Is ${winner.name} With ${winner.voters.length} votes`); }); client.on('call', (call) => { const callData = call[0]; // Get the first call object from the array if (callData.status !== 'offer') return; console.log('\nšŸ“ž Call Received!') console.log('Chat ID:', callData.chatId) console.log('From:', callData.from) console.log('Call ID:', callData.id) console.log('Date:', callData.date) console.log('Offline:', callData.offline) console.log('Status:', callData.status) console.log('Is Video:', callData.isVideo) console.log('Is Group:', callData.isGroup) console.log('Phone Number:', callData.phoneNumber) }) client.on('disconnected', (error) => { console.log('āŒ Client disconnected') }) client.on('group-left', (info) => { console.log(`Left group ${info.id}: ${info.reason}`); }); // Connect to WhatsApp client.connect() client.on('status', async status => { console.log('Status Received'); console.log('Number:', status.from); console.log('Sender:', status.raw.pushName); console.log('Message:', status.body); console.log('Has Media:', status.hasMedia); // Mark status as read using the complete message key //await client.readMessage(status.key); //Reply With Emoji //await status.reply('Liked Your Status! ā¤ļø'); await status.like('ā¤ļø'); console.log('Status Seen! and Replied With Emoji') }); // Listen for incoming messages let lastOutgoingCallId = null; let lastOutgoingCallJid = null; let autoCancelCallTimer = null; client.on('message', async msg => { if (msg.body === '') { return } console.log('Message Received'); isGroupMsg = msg.isGroup if (isGroupMsg) { msgFrom = msg.from } else { msgFrom = msg.sender } console.log('Msg From:', msg.from); console.log('Msg Sender:', msg.sender); console.log('Sender Name:', msg.raw.pushName); console.log('Message:', msg.body); console.log('Is Group:', msg.isGroup); // Mark the message as read await client.readMessage(msg.raw.key) const command = msg.body.split(' ')[0].toLowerCase() const args = msg.body.split(' ').slice(1).join(' ') switch (command) { case '!ping': await client.sendMessage(msgFrom, 'Hello Pong! šŸŽŠ') break case '!poll': await client.sendMessage(msgFrom, '', { poll: { name: 'Which programming language do you like most?', options: ['JavaScript', 'Python', 'C++', 'Java'], selectableOptionsCount: 1, messageId: 'poll1' } }); break case '!echo': if (args) { await client.sendMessage(msgFrom, args) } else { await client.sendMessage(msgFrom, 'Please provide text to echo') } break case '!mention': const number = msg.sender.split('@')[0] await client.sendMessage(msgFrom, { type: 'text', text: `Hey @${number}! How are you?`, mentions: [number] }) break case '!mentionall': if (!isGroupMsg) { await client.sendMessage(msgFrom, 'This command is only for groups') return } await client.sendMessage(msgFrom, { type: 'text', text: `Hey @all! How are you?`, mentions: ['@all'] }) break case '!reply': await msg.reply('This is a reply message') break case '!location': await client.sendMessage(msgFrom, { type: 'location', latitude: 24.121231, longitude: 55.1121221 }) break case '!contact': await client.sendMessage(msgFrom, { type: 'contact', fullName: 'John Doe', organization: 'Example Corp', phoneNumber: '1234567890' }) break case '!react': await client.sendMessage( msgFrom, { type: 'reaction', emoji: 'šŸ’–', message: { key: msg.raw.key } } ) break case '!media': if (fs.existsSync('./example.jpg')) { await client.sendMedia(msgFrom, './example.jpg', { caption: 'Check out this image!' }) } else { await client.sendMessage(msgFrom, 'Example image not found') } break case '!urlimage': try { const integrationFormula = '\\dpi{900}\\int\\frac{1}{x}dx=\\ln\\left|x\\right|+C'; const mediaurl = `https://latex.codecogs.com/png.image?${encodeURIComponent(integrationFormula)}`; await client.sendMedia(msgFrom, mediaurl, { caption: 'Check out this image!' }) } catch (error) { await client.sendMessage(msgFrom, `Failed to send image from URL: ${error.message}`) } break case '!doc': if (fs.existsSync('./example.pdf')) { await client.sendDocument(msgFrom, './example.pdf', 'Check out this document!') } else { await client.sendMessage(msgFrom, 'Example document not found') } break case '!list': await client.SendList(msgFrom, { text: 'Please select an option from the list below:', title: 'Comprehensive Menu', buttonText: 'View All Options', footer: 'Scroll to see more options', sections: [ { title: 'Main Options', rows: [ { title: 'Account Settings', id: 'account_settings', description: 'Manage your account preferences' }, { title: 'Profile', id: 'profile', description: 'View and edit your profile' }, { title: 'Notifications', id: 'notifications', description: 'Configure notification settings' }, { title: 'Privacy', id: 'privacy', description: 'Privacy and security settings' }, { title: 'Security', id: 'security', description: 'Security and login options' }, { title: 'Payments', id: 'payments', description: 'Manage payment methods' }, { title: 'Subscriptions', id: 'subscriptions', description: 'View your subscriptions' }, ] }, { title: 'More Options', rows: [ { title: 'Themes', id: 'themes', description: 'Change app appearance' }, { title: 'Font Size', id: 'font_size', description: 'Adjust text size' }, { title: 'Dark Mode', id: 'dark_mode', description: 'Toggle dark theme' }, { title: 'Offline Mode', id: 'offline', description: 'Use without internet' }, { title: 'Data Saver', id: 'data_saver', description: 'Reduce data usage' }, { title: 'Storage', id: 'storage', description: 'Manage local storage' }, { title: 'Cache', id: 'cache', description: 'Clear cached data' }, ] } ] }) break case '!buttons': // Example: Send a text interactive message (modern Baileys format) await client.sendButtons(msgFrom, { text: 'Do you like this bot?', title: 'Feedback', subtitle: 'Let us know!', footer: 'Powered by Baileys', interactiveButtons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'āœ… Yes', id: 'text_yes' }) }, { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'āŒ No', id: 'text_no' }) } ] }); // Example: Send an image interactive message (modern Baileys format) await client.sendButtons(msgFrom, { imagePath: './example.jpg', caption: 'here is captions of image\nwith linebreaks', // Keep it short and concise title: 'Image Title', // Max 24 chars subtitle: 'Image Subtitle (but optional)', // Optional, appears below title footer: 'Image Footer', interactiveButtons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'šŸ‘ Like', id: 'img_like' }) }, { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'šŸ‘Ž Dislike', id: 'img_dislike' }) }, { name: 'cta_call', buttonParamsJson: JSON.stringify({ display_text: 'šŸ“ž Call Us', phone_number: '+1234567890' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: '🌐 Visit Website', url: 'https://example.com', merchant_url: 'https://example.com' }) }, { name: 'cta_copy', buttonParamsJson: JSON.stringify({ display_text: 'šŸ”— Copy Link', copy_code: 'https://example.com/copied' }) } ] }); break case '!quickreplyv2': await client.sendQuickReplyV2(msgFrom, 'Please select an option below:', [ { id: 'btn-1', displayText: 'āœ… Accept' }, { id: 'btn-2', displayText: 'āŒ Reject' }, { id: 'btn-3', displayText: 'šŸ“ž Contact Support' } ], { footer: 'Powered by Innovators Soft' }); break case '!urlbuttonv2': await client.sendUrlButtonV2(msgFrom, 'Visit our website for more info', [ { displayText: '🌐 Open Website', url: 'https://example.com' } ], { title: 'Product Info', footer: 'Click to open' }); break case '!copycodev2': await client.sendCopyCodeV2(msgFrom, 'Your OTP Code is:', '123456', 'šŸ“‹ Copy Code'); break case '!combinedv2': await client.sendCombinedButtonsV2(msgFrom, 'Choose an action:', [ { type: 'reply', displayText: 'šŸ›’ Order Now', id: 'order' }, { type: 'url', displayText: '🌐 Website', url: 'https://example.com' }, { type: 'call', displayText: 'šŸ“ž Phone', phoneNumber: '+923224559543' }, { type: 'copy', displayText: 'šŸ“‹ Copy Promo', copyCode: 'PROMO2024' } ], { title: 'Main Menu', footer: 'Innovators Soft' }); break case '!listv2': await client.sendListV2(msgFrom, { title: 'šŸ“‹ Product Menu', buttonText: 'View Menu', description: 'Please select a product', footer: 'Powered by Innovators Soft', sections: [ { title: 'Food', rows: [ { rowId: 'nasi-goreng', title: 'Fried Rice', description: '$2.50' }, { rowId: 'mie-goreng', title: 'Fried Noodles', description: '$2.00' } ] }, { title: 'Beverages', rows: [ { rowId: 'es-teh', title: 'Ice Tea', description: '$0.50' }, { rowId: 'kopi', title: 'Coffee', description: '$1.00' } ] } ] }); break case '!cards': if (fs.existsSync('./example.jpg')) { const imageBuffer = fs.readFileSync('./example.jpg'); const videoBuffer = fs.readFileSync('./example.mp4'); await client.sendcards(msgFrom, { text: 'Body Message', title: 'Title Message', subtile: 'Subtitle Message', footer: 'Footer Message', cards: [ { image: imageBuffer, // use local buffer title: 'Title Cards 1', body: 'Body Cards 1', footer: 'Footer Cards 1', buttons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Display Button', id: 'ID' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Display Button', url: 'https://www.example.com' }) } ] }, { video: { url: 'https://files.inqscribe.com/samples/IS_Intro.mp4' },//videoBuffer, // use same local buffer for second card title: 'Title Cards 2', body: 'Body Cards 2', footer: 'Video URL', buttons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Display Button', id: 'ID2' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Display Button', url: 'https://www.example.com' }) } ] }, { video: videoBuffer, // use same local buffer for second card title: 'Title Cards 3', body: 'Body Cards 3', footer: 'Video Buffer', buttons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Display Button', id: 'ID3' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Display Button', url: 'https://www.example.com' }) } ] } ] }); } else { await client.sendMessage(msgFrom, 'Example image (example.jpg) not found for cards demonstration.'); } break case '!call': try { if (autoCancelCallTimer) { clearTimeout(autoCancelCallTimer); autoCancelCallTimer = null; } const result = await client.initiateCall(msgFrom); lastOutgoingCallId = result?.callId || null; lastOutgoingCallJid = msgFrom; await client.sendMessage(msgFrom, `Calling... CallId: ${lastOutgoingCallId || 'unknown'}`); if (lastOutgoingCallId) { autoCancelCallTimer = setTimeout(async () => { try { await client.cancelCall(lastOutgoingCallId, lastOutgoingCallJid); } catch (error) { console.error('Error auto-canceling call:', error); } finally { lastOutgoingCallId = null; lastOutgoingCallJid = null; autoCancelCallTimer = null; } }, 10000); } } catch (error) { console.error('Error initiating voice call:', error); await client.sendMessage(msgFrom, 'Failed to initiate call'); } break case '!videocall': try { if (autoCancelCallTimer) { clearTimeout(autoCancelCallTimer); autoCancelCallTimer = null; } const result = await client.initiateCall(msgFrom, { isVideo: true }); lastOutgoingCallId = result?.callId || null; lastOutgoingCallJid = msgFrom; await client.sendMessage(msgFrom, `Video calling... CallId: ${lastOutgoingCallId || 'unknown'}`); if (lastOutgoingCallId) { autoCancelCallTimer = setTimeout(async () => { try { await client.cancelCall(lastOutgoingCallId, lastOutgoingCallJid); } catch (error) { console.error('Error auto-canceling video call:', error); } finally { lastOutgoingCallId = null; lastOutgoingCallJid = null; autoCancelCallTimer = null; } }, 10000); } } catch (error) { console.error('Error initiating video call:', error); await client.sendMessage(msgFrom, 'Failed to initiate video call'); } break case '!cancelcall': try { if (autoCancelCallTimer) { clearTimeout(autoCancelCallTimer); autoCancelCallTimer = null; } if (!lastOutgoingCallId) { await client.sendMessage(msgFrom, 'No outgoing call to cancel'); break; } await client.cancelCall(lastOutgoingCallId, msgFrom); await client.sendMessage(msgFrom, `Canceled call: ${lastOutgoingCallId}`); lastOutgoingCallId = null; lastOutgoingCallJid = null; } catch (error) { console.error('Error canceling call:', error); await client.sendMessage(msgFrom, 'Failed to cancel call'); } break case '!help': const help = `*šŸ“‹ Available Commands List*\n\n` + `*šŸ”¹ Basic Commands*\n` + `• !ping - Check if bot is alive\n` + `• !echo <text> - Echo back your text\n` + `• !help - Show this command list\n\n` + `*šŸ’¬ Messaging*\n` + `• !mention - Mention you in a message\n` + `• !reply - Reply to your message\n` + `• !react - React to your message with ā¤ļø\n` + ` (Note: Reactions are auto-detected!)\n` + `*šŸ–¼ļø Media & Content*\n` + `• !media - Send an example image\n` + `• !doc - Send an example document\n` + `• !location - Send a location\n` + `• !contact - Send a contact card\n` + `• !sticker - Send an example sticker\n\n` + `*šŸ‘„ Group Management*\n` + `• !groups - List all your groups\n` + `• !add <number> - Add participant\n` + `• !invite <number> - Send group invite link\n` + `• !remove <number> - Remove participant\n` + `• !promote <number> - Make admin\n` + `• !demote <number> - Remove admin\n` + `• !creategroup <name> - Create a new group\n` + `• !groupsubject <name> - Change group name\n` + `• !groupdesc <text> - Change group description\n` + `• !groupsetting <setting> - Change group settings\n` + `• !invitecode - Get group invite code\n` + `• !revokeinvite - Revoke group invite code\n` + `• !leavegroup - Leave the group\n` + `• !joingroup <code> - Join group by invite code\n` + `• !groupinfo [jid|code] - Full group details with participants\n` + `• !joinrequests - List pending join requests\n` + `• !approvejoin <number> - Approve join request\n` + `• !rejectjoin <number> - Reject join request\n` + `• !ephemeral <seconds> - Toggle disappearing msgs\n` + `• !addmode <mode> - Change who can add members\n\n` + `*šŸ”’ Privacy*\n` + `• !block <number> - Block a user\n` + `• !unblock <number> - Unblock a user\n` + `• !privacy - Get privacy settings\n` + `• !blocklist - Get blocked contacts\n` + `• !lastseenprivacy <value> - Update last seen\n` + `• !onlineprivacy <value> - Update online status\n` + `• !pfpprivacy <value> - Update profile pic privacy\n` + `• !statusprivacy <value> - Update status privacy\n` + `• !readreceiptprivacy <value> - Update read receipts\n` + `• !groupaddprivacy <value> - Who can add to groups\n` + `• !disappearing <seconds> - Default disappearing mode\n` + `• !updatestatus <text> - Update profile status\n` + `• !updatename <text> - Update profile name\n\n` + `*šŸ¤– Rich AI Messaging*\n` + `• !table - Send a formatted table\n` + `• !richlist - Send a bulleted list\n` + `• !codeblock - Send a syntax-highlighted code snippet\n` + `• !latex - Send LaTeX text\n` + `• !lateximage - Send LaTeX image\n` + `• !latexinlineimage - Send LaTeX inline image\n` + `• !rich - Send demo rich message\n` + `• !markdown - Send native markdown message\n` + `• !richresponse - Send rich text with code block\n\n` + `*šŸŽ›ļø Templates & Buttons*\n` + `• !buttons - Button template\n` + `• !list - Scrollable list\n\n` + `• !quickreplyv2 - Quick reply buttons V2\n` + `• !urlbuttonv2 - URL button V2\n` + `• !copycodev2 - Copy code button V2\n` + `• !combinedv2 - Mixed buttons V2\n` + `• !listv2 - Interactive list V2\n` + `• !cards - Interactive cards message\n\n` + `*🟢 Status*\n` + `• !statustext - Post a text status\n` + `• !statusimage - Post an image status\n` + `• !statusvideo - Post a video status\n` + `• !statusvoice - Post a voice note status\n` + `• !groupstatus - Post a status directly inside a group (@g.us)\n\n` + `*šŸ“ž Calls*\n` + `• !call - Initiate a voice call\n` + `• !videocall - Initiate a video call\n` + `• !cancelcall - Cancel last outgoing call\n\n` + `*ļæ½ Message Store*\n` + `• !messages - Get stored messages for this chat\n` + `• !allmessages - Get statistics for all stored chats\n` + `• !message - Get a specific message by ID\n` + `• !stats - Get store capacity statistics\n\n` + `*ļæ½šŸ” LID/PN/JID Management*\n` + `• !lid - Get your LID\n` + `• !pn <lid> - Get PN from LID\n` + `• !parse <jid> - Parse JID info\n` + `• !normalize <phone> - Normalize to JID\n\n` + `*šŸ›”ļø Protection*\n` + `• Anti-Delete: Automatically active\n\n` + `*āš™ļø Admin Commands*\n` + `• !read - Mark as read\n` + `• !typing - Show typing indicator\n` + `• !recording - Show recording indicator\n` + `• !paused - Clear typing or recording indicator\n` + `• !typing_simulate - Simulate typing for 5s then send msg\n` + `• !typing_start - Start typing with auto-pause\n` + `• !typing_stop - Stop typing indicator\n` + `• !recording_start - Start recording indicator\n` + `• !logout - End session\n\n` + `*šŸ“ Note*:\nReplace <number> with phone number\n(without + or spaces)` await client.sendMessage(msgFrom, help) break case '!table': await client.sendTable( msgFrom, 'Price List', ['Item', 'Qty', 'Price'], [ ['Apple', '3', '$1.50'], ['Banana', '6', '$0.90'], ['Cherry', '1', '$3.00'] ], msg.raw, { headerText: 'Here is your order summary:', footer: 'Thank you!' } ); break; case '!richlist': await client.sendRichList( msgFrom, 'Available Commands', ['!help', '!ping', '!menu', '!info'], msg.raw, { headerText: 'Bot commands:', footer: 'Type any command to use it.' } ); break; case '!codeblock': await client.sendCodeBlock( msgFrom, `async function fetchData(url) {\n const res = await fetch(url)\n return res.json()\n}`, msg.raw, { title: 'šŸ“¦ Example – fetch helper', language: 'javascript', footer: 'Copy and paste into your project.' } ); break; case '!latex': await client.sendLatex( msgFrom, { text: 'Quadratic formula:', expressions: [{ latexExpression: 'x=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}' }] } ); break; case '!lateximage': try { await client.sendLatexImage( msgFrom, { formula: 'E=mc^2', caption: 'Mass-Energy Equivalence (DPI 600)' } ); } catch (error) { return (error) } break; case '!latexinlineimage': try { await client.sendLatexInlineImage( msgFrom, { expressions: [ { latexExpression: 'e^{i\\pi} + 1 = 0' }, { latexExpression: '\\int_a^b x^2 \\, dx = \\frac{b^3 - a^3}{3}' }, { latexExpression: 'f(x) = \\sum_{n=0}^{\\infty} \\frac{f^{(n)}(a)}{n!} (x-a)^n' } ], caption: true // Use each LaTeX expression as the caption for its respective image in the album } ); } catch (error) { return (error) } break; case '!rich': const richLatexExpr = 'E = mc^2'; const richPngBuf = await renderLatexToPng(richLatexExpr); const richImageUrl = (await uploadUnencryptedToWA(richPngBuf.buffer, client.sock.waUploadToServer)).url; await client.sendRichMessage(msgFrom, [ { messageType: RichSubMessageType.TEXT, messageText: '# H1\n## H2\n### H3\n#### H4\n##### H5\n###### H6\n\n___\n\n> To use a horizontal line, you need to have two "\\n" above and below the "___"\n==Highlighted text==\n# By the way, ^you^ can _mix_ ==multiple markdowns== for a **richer response**\n###### Try different combinations...' }, { messageType: RichSubMessageType.TABLE, tableMetadata: { title: 'Product Prices', rows: [ { items: ['Product', 'Price', 'Stock'], isHeading: true }, { items: ['Innovators Baileys Pro', '$49.99', 'In Stock'] }, { items: ['Rust WASM Plugin', '$19.99', 'Low Stock'] } ] } }, { messageType: RichSubMessageType.TEXT, messageText: 'LaTeX Formula:' }, { messageType: RichSubMessageType.INLINE_IMAGE, imageMetadata: { imageUrl: { imagePreviewUrl: richImageUrl, imageHighResUrl: richImageUrl }, imageText: richLatexExpr, alignment: 2 } }, { messageType: RichSubMessageType.CODE, codeMetadata: { codeLanguage: 'javascript', codeBlocks: [ { highlightType: 1, codeContent: 'const ' }, { highlightType: 0, codeContent: 'price = ' }, { highlightType: 4, codeContent: '49.99' }, { highlightType: 0, codeContent: ';\n' }, { highlightType: 1, codeContent: 'if ' }, { highlightType: 0, codeContent: '(price > ' }, { highlightType: 4, codeContent: '20' }, { highlightType: 0, codeContent: ') {\n console.log(' }, { highlightType: 3, codeContent: '"Premium tier"' }, { highlightType: 0, codeContent: ');\n}' } ] } } ], null, { useMarkdown: true }); break; case '!markdown': await client.sendMarkdown( msgFrom, '# Markdown Demo\n## Headers work\n==Highlighted text==\n_Italics_ and **Bold** are supported!', msg.raw ); break; case '!richresponse': // Demonstrate that sendMessage can now natively accept an array of rich submessages await client.sendMessage(msgFrom, { richResponse: [ { messageType: 2, messageText: '# H1\n## H2\n### H3\n#### H4\n##### H5\n###### H6\n\n___\n\n> To use a horizontal line, you need to have two "\\n" above and below the "___"\n==Highlighted text==\n# By the way, ^you^ can _mix_ ==multiple markdowns== for a **richer response**\n###### Try different combinations...' }, { messageType: 2, messageText: 'And here is a syntax-highlighted code block natively passed:' }, { messageType: 5, codeMetadata: { codeLanguage: 'javascript', codeBlocks: [ { highlightType: 1, codeContent: 'const ' }, { highlightType: 0, codeContent: 'greet = (name) => {\n console.log(' }, { highlightType: 3, codeContent: '"Hello, "' }, { highlightType: 0, codeContent: ' + name)\n}\n' }, { highlightType: 0, codeContent: 'greet(' }, { highlightType: 3, codeContent: '"World"' }, { highlightType: 0, codeContent: ')' } ] } } ] }, { markdown: true }); break; case '!groups': try { const groups = await client.getAllGroups() if (groups && groups.length > 0) { let groupList = '*Your Groups:*\n\n' groups.forEach((group, index) => { groupList += `${index + 1}. *${group.subject}*\n` groupList += ` ID: ${group.id}\n` if (group.notify) groupList += ` Notify: ${group.notify}\n` groupList += ` Members: ${group.participants.length}\n` if (group.desc) groupList += ` Description: ${group.desc}\n` groupList += '\n' }) await client.sendMessage(msgFrom, groupList) } else { await client.sendMessage(msgFrom, 'You are not in any groups') } } catch (error) { console.error('Error fetching groups:', error) await client.sendMessage(msgFrom, 'Failed to fetch groups') } break case '!groupinfo': try { // Use provided group JID or current group const groupJid = args.trim() || msg.raw.key.remoteJid if (!groupJid || !groupJid.endsWith('@g.us')) { await client.sendMessage(msgFrom, 'āŒ Please provide a group JID or use this command in a group.\nUsage: !groupinfo <groupJid>') break } const groupInfo = await client.getGroupMetadata(groupJid) if (groupInfo) { let groupList = `*Group Info:*\n\n` + `ID: ${groupInfo.id}\n` + `Notify: ${groupInfo.notify || 'N/A'}\n` + `Subject: ${groupInfo.subject}\n` + `Owner: ${groupInfo.owner || 'N/A'}\n` + `Created: ${new Date(groupInfo.creation * 1000).toLocaleString()}\n` + `Members: ${groupInfo.participants.length}\n` + `Description: ${groupInfo.desc || 'N/A'}\n\n` + `*šŸ‘„ Participants:*\n\n` groupInfo.participants.forEach((p, i) => { const role = p.admin === 'superadmin' ? 'šŸ‘‘ Super Admin' : p.admin === 'admin' ? 'šŸ›”ļø Admin' : 'šŸ‘¤ Member' groupList += `${i + 1}. ${p.id}\n` groupList += ` Role: ${role}\n` if (p.notify) groupList += ` Name: ${p.notify}\n` groupList += '\n' }) await client.sendMessage(msgFrom, groupList) } else { await client.sendMessage(msgFrom, 'Group not found') } } catch (error) { console.error('Error fetching group info:', error) await client.sendMessage(msgFrom, 'Failed to fetch group info') } break case '!logout': // Ask for confirmation before logging out await client.sendButtons(msgFrom, { text: 'Are you sure you want to logout?', title: 'Logout Confirmation', footer: 'Choose Yes to logout or No to cancel', interactiveButtons: [ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Yes', id: 'logout_yes' }) }, { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'No', id: 'logout_no' }) } ] }); break; // Handle logout confirmation case 'Yes': case 'yes': case 'logout_yes': await client.sendMessage(msgFrom, 'You have been logged out.'); await client.logout(); break; case 'No': case 'no': case 'logout_no': await client.sendMessage(msgFrom, 'Logout cancelled.'); break; case '!lid': // Get LID for the user's phone number try { const lid = await client.getLIDForPN(msgFrom); if (lid) { await client.sendMessage(msgFrom, `Your LID: ${lid}\nYour PN: ${msgFrom}`); } else { await client.sendMessage(msgFrom, `No LID found for ${msgFrom}. You might be using a PN-only session.`); } } catch (error) { console.error('Error getting LID:', error); await client.sendMessage(msgFrom, 'Failed to get LID.'); } break; case '!pn': // Get PN from LID try { const lidToCheck = args.trim(); if (!lidToCheck) { await client.sendMessage(msgFrom, 'Please provide a LID. Example: !pn 123456@lid'); break; } const pn = await client.getPNForLID(lidToCheck); if (pn) { await client.sendMessage(msgFrom, `Phone Number for ${lidToCheck}: ${pn}`); } else { await client.sendMessage(msgFrom, `No phone number found for LID: ${lidToCheck}`); } } catch (error) { console.error('Error getting PN from LID:', error); await client.sendMessage(msgFrom, 'Failed to get phone number.'); } break; case '!ad': await client.sendAdReply( ms