Compare commits
16 Commits
8b733b9365
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
| f8f2fce606 | |||
| 642c2b5841 | |||
| 9a7b19f938 | |||
| 3207c84296 | |||
| deedec1283 | |||
| 8e9297be06 | |||
|
|
c8f6454512 | ||
|
|
176b51ec9a | ||
|
|
dcf46cde9c | ||
|
|
d5d7d0e9fb | ||
|
|
0a272da620 | ||
|
|
d39e56525d | ||
|
|
483e4461e1 | ||
|
|
b0b83f6587 | ||
|
|
8c904fe703 | ||
|
|
936deb39bc |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1 +1,6 @@
|
|||||||
node_modules
|
node_modules
|
||||||
|
removed.rm
|
||||||
|
|
||||||
|
fromwindows.json
|
||||||
|
fromandroid.json
|
||||||
|
fromnodered.json
|
||||||
@@ -1 +1,2 @@
|
|||||||
node_modules
|
node_modules
|
||||||
|
removed.rm
|
||||||
66
README.md
66
README.md
@@ -1,6 +1,7 @@
|
|||||||
# Whatsapp Link :iphone:
|
# Whatsapp Link :iphone:
|
||||||
|
|
||||||
Simple node for connecting Node-Red to Whatsapp :iphone:
|
Simple node for connecting Node-Red to Whatsapp :iphone:
|
||||||
|
Send and Receive Whatsapp Image/Text.
|
||||||
|
|
||||||
Currently in developing mode, Continous updated may encounter. :sweat_smile:
|
Currently in developing mode, Continous updated may encounter. :sweat_smile:
|
||||||
|
|
||||||
@@ -65,12 +66,12 @@ Admin Node generate QR Code just below the node for easy connection with whatsap
|
|||||||
|
|
||||||
|
|
||||||
3. **Chats / Group Out** : As simple as mention on name, node will send `msg.payload` recived at input to the number mentioned in node.
|
3. **Chats / Group Out** : As simple as mention on name, node will send `msg.payload` recived at input to the number mentioned in node.
|
||||||
`A-reply-to-All.json` example is avilable in examples to import.
|
`ImageMessage.json` example is avilable in examples to import.
|
||||||
|
|
||||||
MultiMedia Message: Requirments-
|
MultiMedia Message: Requirments-
|
||||||
| Input | Description |
|
| Input | Description |
|
||||||
|--------|-------------|
|
|--------|-------------|
|
||||||
| `msg.image` | Base64 (encoded image) |
|
| `msg.image` | Base64 (encoded image), [`image-tool`](https://flows.nodered.org/node/node-red-contrib-image-tools) node work fine for incoding base64|
|
||||||
| `msg.payload` | Image Caption |
|
| `msg.payload` | Image Caption |
|
||||||
| `msg.toNumber` | Reciver number (if number not provided in node) |
|
| `msg.toNumber` | Reciver number (if number not provided in node) |
|
||||||
|
|
||||||
@@ -85,65 +86,7 @@ Admin Node generate QR Code just below the node for easy connection with whatsap
|
|||||||
|
|
||||||
The node will send recived `msg.payload` to a group chat.
|
The node will send recived `msg.payload` to a group chat.
|
||||||
|
|
||||||
## Button, List and TemplateButton
|
`A-reply-to-All.json` example is avilable in examples to import.
|
||||||
Supported in Whatsapp-Lite only, `TODO for Whatsapp-Web`.
|
|
||||||
A Complete Button-Bot example is avilable in Node examples.
|
|
||||||
|
|
||||||
* <b>Simple Button </b>For simple 3 Bottons your `msg.paylod` should be...
|
|
||||||
|
|
||||||
```js
|
|
||||||
msg.payload = {
|
|
||||||
text: "Hi it's button message", //String
|
|
||||||
footer: 'Hello World', //String
|
|
||||||
headerType: 1, //keep it "1" only.
|
|
||||||
buttons: [ // Array of buttons.
|
|
||||||
{buttonId: 'id1', buttonText: {displayText: 'Button 1'}, type: 1},
|
|
||||||
{buttonId: 'id2', buttonText: {displayText: 'Button 2'}, type: 1},
|
|
||||||
{buttonId: 'id3', buttonText: {displayText: 'Button 3'}, type: 1}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* <b>TemplateButton</b> combination of <b>link button</b>, <b>Call button</b> and Normal buttons. Your `msg.paylod` should look similar to--
|
|
||||||
|
|
||||||
```js
|
|
||||||
msg.payload = {
|
|
||||||
text: "Hi it's a template message by Node-RED 👍 to Test",
|
|
||||||
footer: 'Hello I am footer of message.',
|
|
||||||
templateButtons: [
|
|
||||||
{index: 1, urlButton: {displayText: '⭐ Vist Node-RED', url: 'https://nodered.org/'}},
|
|
||||||
{index: 2, callButton: {displayText: 'Call me!', phoneNumber: '+1 (234) 5678-901'}},
|
|
||||||
{index: 3, quickReplyButton: {displayText: 'Click me I am Button', id: 'I-am-button-id-without-space'}},
|
|
||||||
{index: 4, quickReplyButton: {displayText: '🖱️ Sample Button 2', id: 'button-2-was-clicked'}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
* <b>List Message</b> combination of <b>link button</b>, <b>List button</b> and Selectors. Your `msg.paylod` should look similar to--
|
|
||||||
|
|
||||||
```js
|
|
||||||
msg.payload = {
|
|
||||||
text: "This is a list",
|
|
||||||
footer: "nice footer, link: https://google.com",
|
|
||||||
title: "Amazing boldfaced list title",
|
|
||||||
buttonText: "Required, Tap to see List",
|
|
||||||
sections : [{
|
|
||||||
title: "Section 1",
|
|
||||||
rows: [
|
|
||||||
{title: "Option 1", rowId: "option1"},
|
|
||||||
{title: "Option 2", rowId: "option2", description: "This is a description"}
|
|
||||||
]},
|
|
||||||
{
|
|
||||||
title: "Section 2",
|
|
||||||
rows: [
|
|
||||||
{title: "Option 3", rowId: "option3"},
|
|
||||||
{title: "Option 4", rowId: "option4", description: "This is a description V2"}
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
Yes its lot require for buttons, A node will come soon to minimize these effors.
|
|
||||||
You may direct import these test buttons from the Node Examples.
|
|
||||||
|
|
||||||
|
|
||||||
5. **Reply Node** : In Beta mode. (Chats-out Node can be used instead of reply node)
|
5. **Reply Node** : In Beta mode. (Chats-out Node can be used instead of reply node)
|
||||||
|
|
||||||
@@ -163,6 +106,7 @@ Issues and Suggestions are welcome [here.](https://github.com/raweee/node-red-co
|
|||||||
* `Ver-0.1.34` : Multiple Events reading options are added in Chats-In Node.
|
* `Ver-0.1.34` : Multiple Events reading options are added in Chats-In Node.
|
||||||
* `Ver-0.1.36` : Check box added to show status as `Online/Offline` in Whatsapp-Link Node, to get push notifications. Ping-Interval added to keep whatsapp alive for long time. Multiple examples added.
|
* `Ver-0.1.36` : Check box added to show status as `Online/Offline` in Whatsapp-Link Node, to get push notifications. Ping-Interval added to keep whatsapp alive for long time. Multiple examples added.
|
||||||
* `Ver-0.1.37` : Changes for correction of send message with images and use Chromium profiles in Puppeteer.
|
* `Ver-0.1.37` : Changes for correction of send message with images and use Chromium profiles in Puppeteer.
|
||||||
|
* `Ver-0.1.39B` : Broken "Whatsapp-Web & Lite" fixed. Able to `Send/Receive` whatsapp `Image/Text` in both Whatsapp-Lite & Web. working on easy to use nodes.
|
||||||
|
|
||||||
## Future Nodes
|
## Future Nodes
|
||||||
Currently working on more Whatsapp Node and will be avilable soon -
|
Currently working on more Whatsapp Node and will be avilable soon -
|
||||||
|
|||||||
29
admin.js
29
admin.js
@@ -72,7 +72,7 @@ module.exports = function(RED) {
|
|||||||
msg.type = notification.type;
|
msg.type = notification.type;
|
||||||
msg.notification = notification;
|
msg.notification = notification;
|
||||||
node.send(msg);
|
node.send(msg);
|
||||||
notification.reply('!Node-Red joined');
|
// notification.reply('!Node-Red joined');
|
||||||
});
|
});
|
||||||
|
|
||||||
node.client.on('group_leave', async (notification)=>{
|
node.client.on('group_leave', async (notification)=>{
|
||||||
@@ -126,16 +126,21 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
if(node.client.clientType === "waSocketClient"){
|
if(node.client.clientType === "waSocketClient"){
|
||||||
var client = null
|
var client = null
|
||||||
|
|
||||||
|
|
||||||
async function clientFromWhatsappLite(){
|
async function clientFromWhatsappLite(){
|
||||||
client = await node.client;
|
client = await node.client;
|
||||||
client.ev.on('connection.update', (updates)=>{
|
client.ev.on('connection.update', (updates)=>{
|
||||||
|
function printQrCode(urlQr) {
|
||||||
|
var qrImageWithID = {};
|
||||||
|
qrImageWithID.id = node.id;
|
||||||
|
qrImageWithID.image = urlQr;
|
||||||
|
RED.comms.publish("whatsappLinkQrCode", qrImageWithID);
|
||||||
|
}
|
||||||
|
|
||||||
if(updates.qr){
|
if(updates.qr){
|
||||||
QRCode.toDataURL(updates.qr, function(err, url){
|
QRCode.toDataURL(updates.qr, function(err, url){
|
||||||
var qrImageWithID = {};
|
printQrCode(url);
|
||||||
qrImageWithID.id = node.id;
|
|
||||||
qrImageWithID.image = url;
|
|
||||||
RED.comms.publish("whatsappLinkQrCode", qrImageWithID);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
QRCode.toString(updates.qr, {type : 'terminal', small:true }, function(err, QRTerminal){
|
QRCode.toString(updates.qr, {type : 'terminal', small:true }, function(err, QRTerminal){
|
||||||
@@ -144,20 +149,16 @@ module.exports = function(RED) {
|
|||||||
console.log(QRTerminal);
|
console.log(QRTerminal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (connection === 'open') {
|
|
||||||
var qrImageWithID = {};
|
|
||||||
qrImageWithID.id = node.id;
|
|
||||||
qrImageWithID.image = null;
|
|
||||||
RED.comms.publish("whatsappLinkQrCode", qrImageWithID);
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log(updates);
|
|
||||||
var {connection} = updates
|
|
||||||
//Setting conncetion status indication
|
//Setting conncetion status indication
|
||||||
|
var {connection} = updates
|
||||||
if(connection === 'open'){
|
if(connection === 'open'){
|
||||||
|
printQrCode(null);
|
||||||
SetStatus("Connected", "green");
|
SetStatus("Connected", "green");
|
||||||
}
|
}
|
||||||
else if(updates.isOnline){
|
else if(updates.isOnline){
|
||||||
|
printQrCode(null);
|
||||||
SetStatus("Connected", "green");
|
SetStatus("Connected", "green");
|
||||||
}
|
}
|
||||||
else if(connection === 'close'){
|
else if(connection === 'close'){
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
defaults: {
|
defaults: {
|
||||||
name: {value:"Chats Out"},
|
name: {value:"Chats Out"},
|
||||||
whatsappLink: {value:"whatsapp-web", type:'whatsappLink'},
|
whatsappLink: {value:"whatsapp-web", type:'whatsappLink'},
|
||||||
number: {value: ""}
|
recipient: {value:"", type:'number-recipient', required:false}
|
||||||
},
|
},
|
||||||
outputs:0,
|
outputs:0,
|
||||||
inputs:1,
|
inputs:1,
|
||||||
@@ -27,17 +27,14 @@
|
|||||||
<input type="text" id="node-input-whatsappLink" placeholder="Name">
|
<input type="text" id="node-input-whatsappLink" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-number"><i class="fa fa-address-card-o"></i> Number</label>
|
<label for="node-input-recipient"><i class="fa fa-user"></i> Recipient</label>
|
||||||
<input type="text" id="node-input-number" placeholder="Mobile or Group Number..">
|
<input type="text" id="node-input-recipient" placeholder="Select or add recipient">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-tips">
|
<div class="form-tips">
|
||||||
<p>Don't forget to mention international dialing code befor your number.
|
<p><b>Recipient:</b> Select a reusable Number Recipient configuration (optional).</p>
|
||||||
Number must be in format like <b>+11 99999 99999</b> without any space.</p>
|
<p><b>Override at runtime:</b> Provide <code>msg.toNumber</code> to override the configured recipient.</p>
|
||||||
<P><b>OR</b></P>
|
<p>Number format: <b>+11 99999 99999</b> (international dialing code, no spaces).</p>
|
||||||
<P>Leave the Number blank here and provide the number along with msg.paylod
|
<p>For multiple contacts, pass an array: <code>msg.toNumber = ["+1199999999", "+12990000099"]</code></p>
|
||||||
at `msg.toNumber` with international code.</P>
|
|
||||||
<p>To send message on multiple contacts an Arrar of number can be passed
|
|
||||||
on `msg.toNumber` like `msg.toNumber = ["+1199999999", "+12990000099", "+1311111111"].</p>
|
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
95
chats-out.js
95
chats-out.js
@@ -1,50 +1,49 @@
|
|||||||
|
const { formatChatNumber, formatChatNumberSocket } = require('./whatsapp-utils');
|
||||||
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
function WhatsappOut(config) {
|
function WhatsappOut(config) {
|
||||||
RED.nodes.createNode(this,config);
|
RED.nodes.createNode(this,config);
|
||||||
var node = this;
|
var node = this;
|
||||||
node.number = config.number;
|
|
||||||
|
// Get number from recipient config node if configured
|
||||||
|
var recipientNode = RED.nodes.getNode(config.recipient);
|
||||||
|
node.number = recipientNode ? recipientNode.number : null;
|
||||||
|
|
||||||
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
|
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
|
||||||
node.waClient = whatsappLinkNode.client;
|
node.waClient = whatsappLinkNode.client;
|
||||||
const { MessageMedia, Buttons } = require('whatsapp-web.js')
|
const { MessageMedia, Buttons } = require('whatsapp-web.js');
|
||||||
|
const {Mimetype} = require(`@whiskeysockets/baileys`);
|
||||||
|
|
||||||
let SetStatus = function(WAStatus, color){
|
let SetStatus = function(WAStatus, color){
|
||||||
node.status({fill:color,shape:"dot",text:WAStatus});
|
node.status({fill:color,shape:"dot",text:WAStatus});
|
||||||
};
|
};
|
||||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
async function webNubmerSeteing(numb){
|
|
||||||
numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
|
|
||||||
// numb = `${numb}@c.us`;
|
|
||||||
var numbID = await node.waClient.getNumberId(numb);
|
|
||||||
if(numbID) {
|
|
||||||
return `${numbID.user}@${numbID.server}`;
|
|
||||||
} else {
|
|
||||||
return `${numb}@g.us`
|
|
||||||
}
|
|
||||||
// return numb
|
|
||||||
}
|
|
||||||
|
|
||||||
async function socNubmerSeteing(numb){
|
|
||||||
if (numb.remoteJid){
|
|
||||||
return numb.remoteJid;
|
|
||||||
}
|
|
||||||
numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
|
|
||||||
const [result] = await (await node.waClient).onWhatsApp(numb)
|
|
||||||
if (result?.exists){
|
|
||||||
return result.jid
|
|
||||||
}
|
|
||||||
return numb = `${numb}@g.us`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function whatsappMessage(numb , inputMessage){
|
async function whatsappMessage(numb , inputMessage){
|
||||||
|
// Validate message
|
||||||
|
if (!inputMessage) {
|
||||||
|
node.error('Error Sending Msg: Message payload is empty or undefined');
|
||||||
|
SetStatus("Message empty", "red");
|
||||||
|
setTimeout(() => SetStatus('Connected','green'), 3000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (node.waClient.clientType === "waWebClient"){
|
if (node.waClient.clientType === "waWebClient"){
|
||||||
try {
|
try {
|
||||||
numb = await webNubmerSeteing(numb);
|
numb = await formatChatNumber(numb, node.waClient, node);
|
||||||
if(typeof inputMessage === "object"){
|
|
||||||
|
// Ensure message is a string for simple messages
|
||||||
|
if(typeof inputMessage === "object" && inputMessage.buttons){
|
||||||
inputMessage = new Buttons(inputMessage.text, inputMessage.buttons, "text" ,inputMessage.footer);
|
inputMessage = new Buttons(inputMessage.text, inputMessage.buttons, "text" ,inputMessage.footer);
|
||||||
node.waClient.sendMessage(numb, inputMessage);
|
await node.waClient.sendMessage(numb, inputMessage);
|
||||||
|
} else if (typeof inputMessage === "object") {
|
||||||
|
// If it's an object without buttons, convert to string or handle appropriately
|
||||||
|
const messageText = inputMessage.text || JSON.stringify(inputMessage);
|
||||||
|
await node.waClient.sendMessage(numb, messageText);
|
||||||
|
} else {
|
||||||
|
// Convert to string to ensure valid message
|
||||||
|
await node.waClient.sendMessage(numb, String(inputMessage));
|
||||||
}
|
}
|
||||||
node.waClient.sendMessage(numb, inputMessage);
|
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(e){
|
||||||
node.error(`Error Sending Msg: ${e}`);
|
node.error(`Error Sending Msg: ${e}`);
|
||||||
@@ -53,18 +52,24 @@ module.exports = function(RED) {
|
|||||||
else if (node.waClient.clientType === "waSocketClient"){
|
else if (node.waClient.clientType === "waSocketClient"){
|
||||||
try {
|
try {
|
||||||
let client = await node.waClient;
|
let client = await node.waClient;
|
||||||
numb = await socNubmerSeteing(numb)
|
numb = await formatChatNumberSocket(numb, node.waClient, node);
|
||||||
if (typeof inputMessage ==="string"){
|
|
||||||
|
// Format message for socket client
|
||||||
|
if (typeof inputMessage === "string"){
|
||||||
inputMessage = {text : inputMessage};
|
inputMessage = {text : inputMessage};
|
||||||
|
} else if (typeof inputMessage === "object" && !inputMessage.text) {
|
||||||
|
// If object doesn't have text property, convert to string
|
||||||
|
inputMessage = {text : JSON.stringify(inputMessage)};
|
||||||
}
|
}
|
||||||
const msgStatus = await client.sendMessage(numb, inputMessage);
|
|
||||||
|
await client.sendMessage(numb, inputMessage);
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
node.error(`Error Sending Msg:: ${e}`);
|
node.error(`Error Sending Msg: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.error(`Error Sending Msg: ${e}`)
|
node.error(`Error Sending Msg: Unknown client type`)
|
||||||
}
|
}
|
||||||
SetStatus("Message Send.", "green");
|
SetStatus("Message Send.", "green");
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
@@ -77,18 +82,20 @@ module.exports = function(RED) {
|
|||||||
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
|
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
|
||||||
try {
|
try {
|
||||||
if (node.waClient.clientType === "waWebClient"){
|
if (node.waClient.clientType === "waWebClient"){
|
||||||
numb = await webNubmerSeteing(numb)
|
numb = await formatChatNumber(numb, node.waClient, node);
|
||||||
var myMessage = new MessageMedia('image/png', whatsappImageBase64, null, null);
|
var myMessage = new MessageMedia('image/png', whatsappImageBase64, null, null);
|
||||||
node.waClient.sendMessage(numb, myMessage, {caption : whatsappCaption });
|
await node.waClient.sendMessage(numb, myMessage, {caption : whatsappCaption });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
numb = await socNubmerSeteing(numb)
|
numb = await formatChatNumberSocket(numb, node.waClient, node);
|
||||||
const imageMessage = {
|
|
||||||
text: whatsappCaption,
|
let imageToSend = Buffer.from(whatsappImageBase64, "base64");
|
||||||
footer: null,
|
const imageMessage = {
|
||||||
templateButtons: null,
|
// image: {url : whatsappImage},
|
||||||
image: {url : whatsappImage }
|
image: imageToSend,
|
||||||
};
|
caption: whatsappCaption
|
||||||
|
}
|
||||||
|
|
||||||
let client = await node.waClient;
|
let client = await node.waClient;
|
||||||
const msgStatus = await client.sendMessage(numb, imageMessage);
|
const msgStatus = await client.sendMessage(numb, imageMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
139
examples/ImageMessage.json
Normal file
139
examples/ImageMessage.json
Normal file
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
|||||||
defaults: {
|
defaults: {
|
||||||
name: {value:"Group Message"},
|
name: {value:"Group Message"},
|
||||||
whatsappLink: {value:"whatsapp-web", type:'whatsappLink'},
|
whatsappLink: {value:"whatsapp-web", type:'whatsappLink'},
|
||||||
gID: {value: ""}
|
recipient: {value:"", type:'group-recipient', required:false}
|
||||||
},
|
},
|
||||||
outputs:0,
|
outputs:0,
|
||||||
inputs:1,
|
inputs:1,
|
||||||
@@ -27,17 +27,14 @@
|
|||||||
<input type="text" id="node-input-whatsappLink" placeholder="Name">
|
<input type="text" id="node-input-whatsappLink" placeholder="Name">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-gID"><i class="fa fa-address-card-o"></i> Group ID </label>
|
<label for="node-input-recipient"><i class="fa fa-users"></i> Group Recipient</label>
|
||||||
<input type="text" id="node-input-gID" placeholder="Group Chat ID..">
|
<input type="text" id="node-input-recipient" placeholder="Select or add group recipient">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-tips">
|
<div class="form-tips">
|
||||||
<p>Group chat IDs are numbers given to each chats in whatsapp. <br>
|
<p><b>Recipient:</b> Select a reusable Group Recipient configuration (optional).</p>
|
||||||
- For every message recived from whatsapp-chats-in Node,
|
<p><b>Override at runtime:</b> Provide <code>msg.toNumber</code> to override the configured recipient.</p>
|
||||||
Chat ID may be read at <b>msg.chatID</b>.<br>
|
<p>Group IDs are in format NUMBER-TIMESTAMP (e.g., 1234567890-1234567890).</p>
|
||||||
<b>Or</b><br>
|
<p>Find group IDs from <code>msg.chatID</code> in chats-in node or from the admin node when joining groups.</p>
|
||||||
- Chat ID of group can also be recive from whatsapp-admin Node,
|
|
||||||
whenever the new group joined, Admin Node will notifiy the same.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
99
group-out.js
99
group-out.js
@@ -1,8 +1,14 @@
|
|||||||
|
const { formatGroupId, formatGroupIdSocket } = require('./whatsapp-utils');
|
||||||
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
function WhatsappGroupOut(config) {
|
function WhatsappGroupOut(config) {
|
||||||
RED.nodes.createNode(this,config);
|
RED.nodes.createNode(this,config);
|
||||||
var node = this;
|
var node = this;
|
||||||
node.number = config.gID;
|
|
||||||
|
// Get group ID from recipient config node if configured
|
||||||
|
var recipientNode = RED.nodes.getNode(config.recipient);
|
||||||
|
node.number = recipientNode ? recipientNode.groupId : null;
|
||||||
|
|
||||||
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
|
var whatsappLinkNode = RED.nodes.getNode(config.whatsappLink);
|
||||||
node.waClient = whatsappLinkNode.client;
|
node.waClient = whatsappLinkNode.client;
|
||||||
|
|
||||||
@@ -13,41 +19,31 @@ module.exports = function(RED) {
|
|||||||
};
|
};
|
||||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
|
async function whatsappMessage(gID , inputMessage){
|
||||||
async function webNubmerSeteing(numb){
|
// Validate message
|
||||||
numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
|
if (!inputMessage) {
|
||||||
// numb = `${numb}@c.us`;
|
node.error('Error Sending Msg: Message payload is empty or undefined');
|
||||||
var numbID = await node.waClient.getNumberId(numb);
|
SetStatus("Message empty", "red");
|
||||||
if(numbID) {
|
setTimeout(() => SetStatus('Connected','green'), 3000);
|
||||||
return `${numbID.user}@${numbID.server}`;
|
return;
|
||||||
} else {
|
|
||||||
return `${numb}@g.us`
|
|
||||||
}
|
}
|
||||||
// return numb
|
|
||||||
}
|
|
||||||
|
|
||||||
async function socNubmerSeteing(numb){
|
|
||||||
if (numb.remoteJid){
|
|
||||||
return numb.remoteJid;
|
|
||||||
}
|
|
||||||
numb = typeof numb ==='number' ? numb : numb.replace(/\D/g, '');
|
|
||||||
const [result] = await (await node.waClient).onWhatsApp(numb)
|
|
||||||
if (result?.exists){
|
|
||||||
console.log(result.exists)
|
|
||||||
return result.jid
|
|
||||||
}
|
|
||||||
return numb = `${numb}@g.us`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function whatsappMessage(numb , inputMessage){
|
|
||||||
if (node.waClient.clientType === "waWebClient"){
|
if (node.waClient.clientType === "waWebClient"){
|
||||||
try {
|
try {
|
||||||
numb = await webNubmerSeteing(numb);
|
gID = await formatGroupId(gID, node.waClient, node);
|
||||||
if(typeof inputMessage === "object"){
|
|
||||||
|
// Ensure message is a string for simple messages
|
||||||
|
if(typeof inputMessage === "object" && inputMessage.buttons){
|
||||||
inputMessage = new Buttons(inputMessage.text, inputMessage.buttons, "text" ,inputMessage.footer);
|
inputMessage = new Buttons(inputMessage.text, inputMessage.buttons, "text" ,inputMessage.footer);
|
||||||
node.waClient.sendMessage(numb, inputMessage);
|
await node.waClient.sendMessage(gID, inputMessage);
|
||||||
|
} else if (typeof inputMessage === "object") {
|
||||||
|
// If it's an object without buttons, convert to string or handle appropriately
|
||||||
|
const messageText = inputMessage.text || JSON.stringify(inputMessage);
|
||||||
|
await node.waClient.sendMessage(gID, messageText);
|
||||||
|
} else {
|
||||||
|
// Convert to string to ensure valid message
|
||||||
|
await node.waClient.sendMessage(gID, String(inputMessage));
|
||||||
}
|
}
|
||||||
node.waClient.sendMessage(numb, inputMessage);
|
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(e){
|
||||||
node.error(`Error Sending Msg: ${e}`);
|
node.error(`Error Sending Msg: ${e}`);
|
||||||
@@ -56,18 +52,24 @@ module.exports = function(RED) {
|
|||||||
else if (node.waClient.clientType === "waSocketClient"){
|
else if (node.waClient.clientType === "waSocketClient"){
|
||||||
try {
|
try {
|
||||||
let client = await node.waClient;
|
let client = await node.waClient;
|
||||||
numb = await socNubmerSeteing(numb)
|
gID = await formatGroupIdSocket(gID, node.waClient, node);
|
||||||
if (typeof inputMessage ==="string"){
|
|
||||||
|
// Format message for socket client
|
||||||
|
if (typeof inputMessage === "string"){
|
||||||
inputMessage = {text : inputMessage};
|
inputMessage = {text : inputMessage};
|
||||||
|
} else if (typeof inputMessage === "object" && !inputMessage.text) {
|
||||||
|
// If object doesn't have text property, convert to string
|
||||||
|
inputMessage = {text : JSON.stringify(inputMessage)};
|
||||||
}
|
}
|
||||||
const msgStatus = await client.sendMessage(numb, inputMessage);
|
|
||||||
|
await client.sendMessage(gID, inputMessage);
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
node.error(`Error Sending Msg:: ${e}`);
|
node.error(`Error Sending Msg: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.error(`Error Sending Msg: ${e}`)
|
node.error(`Error Sending Msg: Unknown client type`)
|
||||||
}
|
}
|
||||||
SetStatus("Message Send.", "green");
|
SetStatus("Message Send.", "green");
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
@@ -75,24 +77,25 @@ module.exports = function(RED) {
|
|||||||
}, 2000)
|
}, 2000)
|
||||||
};
|
};
|
||||||
|
|
||||||
async function whatsappMultiMediaMessage(numb, whatsappImage, whatsappCaption){
|
async function whatsappMultiMediaMessage(gID, whatsappImage, whatsappCaption){
|
||||||
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
|
|
||||||
try {
|
try {
|
||||||
if (node.waClient.clientType === "waWebClient"){
|
if (node.waClient.clientType === "waWebClient"){
|
||||||
numb = await webNubmerSeteing(node.number)
|
gID = await formatGroupId(gID, node.waClient, node);
|
||||||
|
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
|
||||||
var myMessage = new MessageMedia('image/png', whatsappImageBase64, null, null);
|
var myMessage = new MessageMedia('image/png', whatsappImageBase64, null, null);
|
||||||
node.waClient.sendMessage(numb, myMessage, {caption : whatsappCaption || "Image from Node-Red"});
|
await node.waClient.sendMessage(gID, myMessage, {caption : whatsappCaption || "Image from Node-Red"});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
numb = await socNubmerSeteing(node.number)
|
gID = await formatGroupIdSocket(gID, node.waClient, node);
|
||||||
const imageMessage = {
|
var whatsappImageBase64 = whatsappImage.split(',')[1] || whatsappImage;
|
||||||
text: whatsappCaption,
|
let imageToSend = Buffer.from(whatsappImageBase64, "base64");
|
||||||
footer: null,
|
const imageMessage = {
|
||||||
templateButtons: null,
|
image: imageToSend,
|
||||||
image: {url : whatsappImage }
|
caption: whatsappCaption || "Image from Node-Red"
|
||||||
};
|
}
|
||||||
|
|
||||||
let client = await node.waClient;
|
let client = await node.waClient;
|
||||||
const msgStatus = await client.sendMessage(numb, imageMessage);
|
await client.sendMessage(gID, imageMessage);
|
||||||
}
|
}
|
||||||
SetStatus("Message Send.", "green");
|
SetStatus("Message Send.", "green");
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
|
|||||||
41
groupRecipient.html
Normal file
41
groupRecipient.html
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('group-recipient', {
|
||||||
|
category: 'config',
|
||||||
|
defaults: {
|
||||||
|
name: {value: ""},
|
||||||
|
groupId: {value: "", required: true}
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || this.groupId || "Group Recipient";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-template-name="group-recipient">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-config-input-name" placeholder="Name">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-groupId"><i class="fa fa-users"></i> Group ID</label>
|
||||||
|
<input type="text" id="node-config-input-groupId" placeholder="1234567890-1234567890">
|
||||||
|
</div>
|
||||||
|
<div class="form-tips">
|
||||||
|
<strong>Tip:</strong> Enter the WhatsApp group ID in the format NUMBER-TIMESTAMP (e.g., 1234567890-1234567890).
|
||||||
|
<br>You can find the group ID by sending a message to the group and checking the message metadata.
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-help-name="group-recipient">
|
||||||
|
<p>Configuration node for a WhatsApp group recipient.</p>
|
||||||
|
<h3>Details</h3>
|
||||||
|
<p>This configuration node stores a group ID that can be reused across multiple group output nodes.</p>
|
||||||
|
<p>The group ID can be overridden at runtime by setting <code>msg.toNumber</code> in the flow.</p>
|
||||||
|
<h3>Configuration</h3>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>Name <span class="property-type">string</span></dt>
|
||||||
|
<dd>A friendly name to identify this group (optional).</dd>
|
||||||
|
<dt>Group ID <span class="property-type">string</span></dt>
|
||||||
|
<dd>The WhatsApp group ID in the format NUMBER-TIMESTAMP (contains a hyphen).</dd>
|
||||||
|
</dl>
|
||||||
|
</script>
|
||||||
8
groupRecipient.js
Normal file
8
groupRecipient.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = function(RED) {
|
||||||
|
function GroupRecipientNode(n) {
|
||||||
|
RED.nodes.createNode(this, n);
|
||||||
|
this.groupId = n.groupId;
|
||||||
|
this.name = n.name;
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("group-recipient", GroupRecipientNode);
|
||||||
|
}
|
||||||
40
numberRecipient.html
Normal file
40
numberRecipient.html
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('number-recipient', {
|
||||||
|
category: 'config',
|
||||||
|
defaults: {
|
||||||
|
name: {value: ""},
|
||||||
|
number: {value: "", required: true}
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || this.number || "Number Recipient";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-template-name="number-recipient">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-config-input-name" placeholder="Name">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-number"><i class="fa fa-phone"></i> Phone Number</label>
|
||||||
|
<input type="text" id="node-config-input-number" placeholder="+1234567890">
|
||||||
|
</div>
|
||||||
|
<div class="form-tips">
|
||||||
|
<strong>Tip:</strong> Enter the phone number with or without country code (e.g., +1234567890 or 1234567890).
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-help-name="number-recipient">
|
||||||
|
<p>Configuration node for a WhatsApp chat recipient.</p>
|
||||||
|
<h3>Details</h3>
|
||||||
|
<p>This configuration node stores a phone number that can be reused across multiple chat output nodes.</p>
|
||||||
|
<p>The phone number can be overridden at runtime by setting <code>msg.toNumber</code> in the flow.</p>
|
||||||
|
<h3>Configuration</h3>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>Name <span class="property-type">string</span></dt>
|
||||||
|
<dd>A friendly name to identify this recipient (optional).</dd>
|
||||||
|
<dt>Phone Number <span class="property-type">string</span></dt>
|
||||||
|
<dd>The WhatsApp phone number. Can include country code with or without + prefix.</dd>
|
||||||
|
</dl>
|
||||||
|
</script>
|
||||||
8
numberRecipient.js
Normal file
8
numberRecipient.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = function(RED) {
|
||||||
|
function NumberRecipientNode(n) {
|
||||||
|
RED.nodes.createNode(this, n);
|
||||||
|
this.number = n.number;
|
||||||
|
this.name = n.name;
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("number-recipient", NumberRecipientNode);
|
||||||
|
}
|
||||||
2430
package-lock.json
generated
2430
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-contrib-whatsapp-link",
|
"name": "node-red-contrib-whatsapp-link",
|
||||||
"version": "0.1.37",
|
"version": "1.0.40-local.1",
|
||||||
"description": "Node to send and receive whatsapp messages in groups and chats. | No third party APIs",
|
"description": "Node to send and receive whatsapp messages in groups and chats. | No third party APIs",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/raweee/node-red-contrib-whatsapp-link.git"
|
"url": "git+https://gitea.delphas.dk/daniels/node-red-contrib-whatsapp-link.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/raweee/node-red-contrib-whatsapp-link/issues"
|
"url": "git+https://gitea.delphas.dk/daniels/node-red-contrib-whatsapp-link/issues"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"node-red",
|
"node-red",
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"whatsapp Group",
|
"whatsapp Group",
|
||||||
"whatsapp Chat"
|
"whatsapp Chat"
|
||||||
],
|
],
|
||||||
"author": "Ravi Mishra",
|
"author": "Daniel Gradman-Svendsen",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"node-red": {
|
"node-red": {
|
||||||
"version": ">=2.0",
|
"version": ">=2.0",
|
||||||
@@ -26,14 +26,16 @@
|
|||||||
"whatsapp chats-out": "chats-out.js",
|
"whatsapp chats-out": "chats-out.js",
|
||||||
"whatsapp group-out": "group-out.js",
|
"whatsapp group-out": "group-out.js",
|
||||||
"whatsapp reply": "whatsappReply.js",
|
"whatsapp reply": "whatsappReply.js",
|
||||||
"whatsapp Link": "whatsappLink.js"
|
"whatsapp Link": "whatsappLink.js",
|
||||||
|
"number-recipient": "numberRecipient.js",
|
||||||
|
"group-recipient": "groupRecipient.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@adiwajshing/baileys": "latest",
|
"@whiskeysockets/baileys": "latest",
|
||||||
"whatsapp-web.js": "latest",
|
"pino": "latest",
|
||||||
"qrcode": "^1.5.1",
|
"qrcode": "^1.5.1",
|
||||||
"pino": "latest"
|
"whatsapp-web.js": "^1.22.2-alpha.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.0.0"
|
"node": ">=8.0.0"
|
||||||
|
|||||||
163
whatsapp-utils.js
Normal file
163
whatsapp-utils.js
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
// Shared utility functions for WhatsApp nodes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a phone number for WhatsApp Web client (chat)
|
||||||
|
* Assumes the recipient is a chat (@c.us)
|
||||||
|
*/
|
||||||
|
async function formatChatNumber(numb, waClient, nodeLogger) {
|
||||||
|
// Validate input
|
||||||
|
if (!numb) {
|
||||||
|
throw new Error('Number is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to string if number
|
||||||
|
numb = typeof numb === 'number' ? numb.toString() : numb;
|
||||||
|
|
||||||
|
// If already formatted, return as-is
|
||||||
|
if (numb.includes('@')) {
|
||||||
|
return numb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean: remove everything except digits
|
||||||
|
numb = numb.replace(/\D/g, '');
|
||||||
|
|
||||||
|
// Validate cleaned number
|
||||||
|
if (!numb || numb.length === 0) {
|
||||||
|
throw new Error('Invalid number format');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate with getNumberId
|
||||||
|
try {
|
||||||
|
const numbID = await waClient.getNumberId(numb);
|
||||||
|
if (numbID) {
|
||||||
|
return `${numbID.user}@${numbID.server}`;
|
||||||
|
} else {
|
||||||
|
// If validation fails, assume it's a chat
|
||||||
|
nodeLogger.warn(`getNumberId returned null for ${numb}, using @c.us`);
|
||||||
|
return `${numb}@c.us`;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// If error, assume it's a chat
|
||||||
|
nodeLogger.warn(`getNumberId failed for ${numb}, using @c.us: ${e.message}`);
|
||||||
|
return `${numb}@c.us`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a group ID for WhatsApp Web client
|
||||||
|
* Assumes the recipient is a group (@g.us)
|
||||||
|
*/
|
||||||
|
async function formatGroupId(gID, waClient, nodeLogger) {
|
||||||
|
// Validate input
|
||||||
|
if (!gID) {
|
||||||
|
throw new Error('Group ID is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to string if number
|
||||||
|
gID = typeof gID === 'number' ? gID.toString() : gID;
|
||||||
|
|
||||||
|
// If already formatted, return as-is
|
||||||
|
if (gID.includes('@')) {
|
||||||
|
return gID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean: preserve hyphens (group format: NUMBER-TIMESTAMP)
|
||||||
|
gID = gID.replace(/[^\d-]/g, '');
|
||||||
|
|
||||||
|
// Validate cleaned group ID
|
||||||
|
if (!gID || gID.length === 0) {
|
||||||
|
throw new Error('Invalid group ID format');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Groups always use @g.us
|
||||||
|
return `${gID}@g.us`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a phone number for Socket client (chat)
|
||||||
|
* Assumes the recipient is a chat
|
||||||
|
*/
|
||||||
|
async function formatChatNumberSocket(numb, waClient, nodeLogger) {
|
||||||
|
// Handle message object with remoteJid
|
||||||
|
if (numb && numb.remoteJid) {
|
||||||
|
return numb.remoteJid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if (!numb) {
|
||||||
|
throw new Error('Number is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to string if number
|
||||||
|
numb = typeof numb === 'number' ? numb.toString() : numb;
|
||||||
|
|
||||||
|
// If already formatted, return as-is
|
||||||
|
if (numb.includes('@')) {
|
||||||
|
return numb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean: remove everything except digits
|
||||||
|
numb = numb.replace(/\D/g, '');
|
||||||
|
|
||||||
|
// Validate cleaned number
|
||||||
|
if (!numb || numb.length === 0) {
|
||||||
|
throw new Error('Invalid number format');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if number exists on WhatsApp
|
||||||
|
try {
|
||||||
|
const client = await waClient;
|
||||||
|
const [result] = await client.onWhatsApp(numb);
|
||||||
|
if (result?.exists) {
|
||||||
|
return result.jid;
|
||||||
|
}
|
||||||
|
// If not found, assume chat
|
||||||
|
nodeLogger.warn(`onWhatsApp returned no results for ${numb}, using @s.whatsapp.net`);
|
||||||
|
return `${numb}@s.whatsapp.net`;
|
||||||
|
} catch (e) {
|
||||||
|
nodeLogger.warn(`onWhatsApp failed for ${numb}, using @s.whatsapp.net: ${e.message}`);
|
||||||
|
return `${numb}@s.whatsapp.net`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a group ID for Socket client
|
||||||
|
* Assumes the recipient is a group (@g.us)
|
||||||
|
*/
|
||||||
|
async function formatGroupIdSocket(gID, waClient, nodeLogger) {
|
||||||
|
// Handle message object with remoteJid
|
||||||
|
if (gID && gID.remoteJid) {
|
||||||
|
return gID.remoteJid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate input
|
||||||
|
if (!gID) {
|
||||||
|
throw new Error('Group ID is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to string if number
|
||||||
|
gID = typeof gID === 'number' ? gID.toString() : gID;
|
||||||
|
|
||||||
|
// If already formatted, return as-is
|
||||||
|
if (gID.includes('@')) {
|
||||||
|
return gID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean: preserve hyphens (group format: NUMBER-TIMESTAMP)
|
||||||
|
gID = gID.replace(/[^\d-]/g, '');
|
||||||
|
|
||||||
|
// Validate cleaned group ID
|
||||||
|
if (!gID || gID.length === 0) {
|
||||||
|
throw new Error('Invalid group ID format');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Groups always use @g.us
|
||||||
|
return `${gID}@g.us`;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
formatChatNumber,
|
||||||
|
formatGroupId,
|
||||||
|
formatChatNumberSocket,
|
||||||
|
formatGroupIdSocket
|
||||||
|
};
|
||||||
@@ -29,7 +29,10 @@ module.exports = function(RED) {
|
|||||||
}),
|
}),
|
||||||
puppeteer : {
|
puppeteer : {
|
||||||
headless : true,
|
headless : true,
|
||||||
args : ['--no-sandbox', '--disable-setuid-sandbox', '--user-data-dir=' + WAnode.id]
|
args : ['--no-sandbox',
|
||||||
|
'--disable-setuid-sandbox',
|
||||||
|
'--user-data-dir=' + WAnode.id
|
||||||
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -43,8 +46,7 @@ module.exports = function(RED) {
|
|||||||
return webClient ;
|
return webClient ;
|
||||||
};
|
};
|
||||||
client = WAConnect();
|
client = WAConnect();
|
||||||
WAnode.connectionSetupID = setInterval(connectionSetup, 10000);
|
|
||||||
|
|
||||||
async function pressenceUpdate(OLS){
|
async function pressenceUpdate(OLS){
|
||||||
try {
|
try {
|
||||||
if (!OLS){
|
if (!OLS){
|
||||||
@@ -86,17 +88,19 @@ module.exports = function(RED) {
|
|||||||
WAnode.log(`Error : Waiting for Initializion...`);
|
WAnode.log(`Error : Waiting for Initializion...`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
WAnode.connectionSetupID = setInterval(connectionSetup, 10000);
|
||||||
|
|
||||||
//QR-Code on Terminal and Ready Status.
|
//QR-Code on Terminal and Ready Status.
|
||||||
client.on("qr", (qr)=>{
|
client.on(`qr`, (qr)=>{
|
||||||
clearInterval(WAnode.connectionSetupID);
|
// clearInterval(WAnode.connectionSetupID);
|
||||||
QRCode.toString(qr, {type : 'terminal', small:true }, function(err, QRTerminal){
|
QRCode.toString(qr, {type : 'terminal', small:true }, function(err, QRTerminal){
|
||||||
WAnode.log(`To Connect, Scan the QR Code through your Whatsapp Mobile App.`)
|
WAnode.log(`To Connect, Scan the QR Code through your Whatsapp Mobile App.`)
|
||||||
console.log("");
|
console.log("");
|
||||||
console.log(QRTerminal);
|
console.log(QRTerminal);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
client.on("ready", ()=>{
|
|
||||||
|
client.on(`ready`, ()=>{
|
||||||
WAnode.log(`Status : Whatsapp Connected`);
|
WAnode.log(`Status : Whatsapp Connected`);
|
||||||
pressenceUpdate(onlineStatus);
|
pressenceUpdate(onlineStatus);
|
||||||
});
|
});
|
||||||
@@ -109,7 +113,7 @@ module.exports = function(RED) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (clientType === "waSocketClient"){
|
if (clientType === "waSocketClient"){
|
||||||
const makeWASocket = require('@adiwajshing/baileys');
|
const makeWASocket = require('@whiskeysockets/baileys');
|
||||||
const { useMultiFileAuthState } = makeWASocket;
|
const { useMultiFileAuthState } = makeWASocket;
|
||||||
const pino = require('pino');
|
const pino = require('pino');
|
||||||
|
|
||||||
@@ -149,7 +153,14 @@ module.exports = function(RED) {
|
|||||||
const { connection, lastDisconnect } = update
|
const { connection, lastDisconnect } = update
|
||||||
if (connection === 'close') {
|
if (connection === 'close') {
|
||||||
// reconnect if not logged out
|
// reconnect if not logged out
|
||||||
|
|
||||||
|
// console.log(lastDisconnect, lastDisconnect?.error?.data?.content)
|
||||||
|
// if (lastDisconnect.error.output.statusCode === 401 ||
|
||||||
|
// lastDisconnect.error.output.statusCode === 440){
|
||||||
|
// console.log(`logged Out by User. StatusCode : ${lastDisconnect?.error?.output.statusCode}`)
|
||||||
|
// FS.rmSync(whatsappLinkDirSocket, {recursive : true, force: true})
|
||||||
|
// }
|
||||||
|
// connectSocketClient();
|
||||||
if (
|
if (
|
||||||
lastDisconnect &&
|
lastDisconnect &&
|
||||||
lastDisconnect.error &&
|
lastDisconnect.error &&
|
||||||
@@ -164,12 +175,13 @@ module.exports = function(RED) {
|
|||||||
lastDisconnect &&
|
lastDisconnect &&
|
||||||
lastDisconnect.error &&
|
lastDisconnect.error &&
|
||||||
lastDisconnect.error.output &&
|
lastDisconnect.error.output &&
|
||||||
lastDisconnect.error.output.statusCode === 401
|
lastDisconnect.error.output.statusCode === 401 &&
|
||||||
|
lastDisconnect.error.output.statusCode === 440
|
||||||
) {
|
) {
|
||||||
FS.rmSync(whatsappLinkDirSocket, {recursive : true, force: true})
|
FS.rmSync(whatsappLinkDirSocket, {recursive : true, force: true})
|
||||||
connectSocketClient()
|
connectSocketClient()
|
||||||
} else {
|
} else {
|
||||||
WAnode.log("Error : " + lastDisconnect?.error)
|
WAnode.log(`ErrorCode: ${lastDisconnect?.error?.output.statusCode} | ${lastDisconnect?.error}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user