waengine 2.3.9 → 2.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FEATURES.md +168 -0
- package/README.md +116 -1
- package/package.json +1 -1
- package/src/advanced-features.js +151 -56
- package/src/client.js +16 -3
- package/src/message.js +9 -0
- package/src/ui-components.js +149 -80
package/FEATURES.md
CHANGED
|
@@ -1013,6 +1013,174 @@ const type = client.getMessageType(message)
|
|
|
1013
1013
|
|
|
1014
1014
|
---
|
|
1015
1015
|
|
|
1016
|
+
## 🎨 Console Renderer **NEU in v2.0.0!**
|
|
1017
|
+
|
|
1018
|
+
### **Schöne Console-Ausgabe mit Custom Prefix und Farben**
|
|
1019
|
+
|
|
1020
|
+
Verwandle deine Console in ein professionelles Dashboard mit automatischen Prefixes und Farben für alle Ausgaben!
|
|
1021
|
+
|
|
1022
|
+
```javascript
|
|
1023
|
+
import { WhatsAppClient, render } from 'waengine';
|
|
1024
|
+
|
|
1025
|
+
const client = new WhatsAppClient();
|
|
1026
|
+
|
|
1027
|
+
// Prefix und Farben konfigurieren
|
|
1028
|
+
render.consolePrefix('MyBot'); // Prefix: [MyBot]
|
|
1029
|
+
render.consolePrefixColor('cyan'); // Prefix-Farbe
|
|
1030
|
+
render.consoleColor('green'); // Standard-Farbe
|
|
1031
|
+
render.consoleError('red'); // Fehler-Farbe
|
|
1032
|
+
render.consoleWarn('yellow'); // Warn-Farbe
|
|
1033
|
+
render.consoleInfo('blue'); // Info-Farbe
|
|
1034
|
+
|
|
1035
|
+
// Jetzt haben ALLE Console-Ausgaben automatisch den Prefix!
|
|
1036
|
+
console.log('Bot gestartet!'); // [MyBot] Bot gestartet!
|
|
1037
|
+
console.error('Ein Fehler!'); // [MyBot] Ein Fehler! (rot)
|
|
1038
|
+
console.warn('Warnung!'); // [MyBot] Warnung! (gelb)
|
|
1039
|
+
console.info('Information'); // [MyBot] Information (blau)
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
### **Verfügbare Farben (30+ Farben)**
|
|
1043
|
+
|
|
1044
|
+
**Basic Colors:**
|
|
1045
|
+
- `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`
|
|
1046
|
+
|
|
1047
|
+
**Bright Colors:**
|
|
1048
|
+
- `brightRed`, `brightGreen`, `brightYellow`, `brightBlue`, `brightMagenta`, `brightCyan`, `brightWhite`
|
|
1049
|
+
|
|
1050
|
+
**Background Colors:**
|
|
1051
|
+
- `bgBlack`, `bgRed`, `bgGreen`, `bgYellow`, `bgBlue`, `bgMagenta`, `bgCyan`, `bgWhite`
|
|
1052
|
+
|
|
1053
|
+
**Bright Backgrounds:**
|
|
1054
|
+
- `bgBrightRed`, `bgBrightGreen`, `bgBrightYellow`, `bgBrightBlue`, `bgBrightMagenta`, `bgBrightCyan`, `bgBrightWhite`
|
|
1055
|
+
|
|
1056
|
+
**Styles:**
|
|
1057
|
+
- `bold`, `dim`, `italic`, `underline`, `inverse`, `strikethrough`
|
|
1058
|
+
|
|
1059
|
+
### **Direkte Print-Funktionen**
|
|
1060
|
+
```javascript
|
|
1061
|
+
// Direkt mit Farbe ausgeben (ohne Prefix)
|
|
1062
|
+
render.print('Wichtige Nachricht', 'red');
|
|
1063
|
+
render.print('Erfolg!', 'green');
|
|
1064
|
+
|
|
1065
|
+
// Success Helper (grün mit ✓)
|
|
1066
|
+
render.success('Operation erfolgreich!');
|
|
1067
|
+
|
|
1068
|
+
// Alle verfügbaren Farben anzeigen
|
|
1069
|
+
render.showColors();
|
|
1070
|
+
```
|
|
1071
|
+
|
|
1072
|
+
### **Renderer Control**
|
|
1073
|
+
```javascript
|
|
1074
|
+
// Renderer aktivieren/deaktivieren
|
|
1075
|
+
render.enable(); // Aktivieren
|
|
1076
|
+
render.disable(); // Deaktivieren
|
|
1077
|
+
|
|
1078
|
+
// Komplett zurücksetzen
|
|
1079
|
+
render.reset(); // Entfernt alle Patches
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
### **Praktische Anwendungen**
|
|
1083
|
+
```javascript
|
|
1084
|
+
// Bot mit schöner Console
|
|
1085
|
+
import { WhatsAppClient, render } from 'waengine';
|
|
1086
|
+
|
|
1087
|
+
const client = new WhatsAppClient();
|
|
1088
|
+
|
|
1089
|
+
// Setup
|
|
1090
|
+
render.consolePrefix('WABot');
|
|
1091
|
+
render.consolePrefixColor('brightCyan');
|
|
1092
|
+
render.consoleColor('white');
|
|
1093
|
+
render.consoleError('brightRed');
|
|
1094
|
+
render.consoleWarn('brightYellow');
|
|
1095
|
+
|
|
1096
|
+
client.on('message', async (msg) => {
|
|
1097
|
+
console.log(`Nachricht von ${msg.from}: ${msg.text}`);
|
|
1098
|
+
// Output: [WABot] Nachricht von 123@s.whatsapp.net: Hello
|
|
1099
|
+
});
|
|
1100
|
+
|
|
1101
|
+
client.on('error', (error) => {
|
|
1102
|
+
console.error(`Fehler: ${error.message}`);
|
|
1103
|
+
// Output: [WABot] Fehler: Connection lost (rot)
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
// Multi-Bot mit verschiedenen Farben
|
|
1107
|
+
const bot1 = new WhatsAppClient();
|
|
1108
|
+
render.consolePrefix('Bot1');
|
|
1109
|
+
render.consolePrefixColor('green');
|
|
1110
|
+
|
|
1111
|
+
const bot2 = new WhatsAppClient();
|
|
1112
|
+
render.consolePrefix('Bot2');
|
|
1113
|
+
render.consolePrefixColor('blue');
|
|
1114
|
+
```
|
|
1115
|
+
|
|
1116
|
+
### **Console Renderer Features**
|
|
1117
|
+
- ✅ **Auto-Prefix** - Automatischer Prefix vor JEDER Console-Ausgabe
|
|
1118
|
+
- ✅ **30+ Farben** - Basic, Bright, Background, Styles
|
|
1119
|
+
- ✅ **Separate Farben** - Unterschiedliche Farben für log/error/warn/info
|
|
1120
|
+
- ✅ **Prefix-Farbe** - Eigene Farbe für den Prefix
|
|
1121
|
+
- ✅ **Direct Print** - Direkte Ausgabe ohne Prefix
|
|
1122
|
+
- ✅ **Success Helper** - Grüne Success-Messages mit ✓
|
|
1123
|
+
- ✅ **Color Preview** - Alle Farben anzeigen
|
|
1124
|
+
- ✅ **Enable/Disable** - Renderer an/aus schalten
|
|
1125
|
+
- ✅ **Reset** - Komplett zurücksetzen
|
|
1126
|
+
- ✅ **Zero Config** - Funktioniert out-of-the-box
|
|
1127
|
+
|
|
1128
|
+
### **Beispiel: Multi-Bot Dashboard**
|
|
1129
|
+
```javascript
|
|
1130
|
+
import { WhatsAppClient, render } from 'waengine';
|
|
1131
|
+
|
|
1132
|
+
// Bot 1 - Grün
|
|
1133
|
+
render.consolePrefix('Support');
|
|
1134
|
+
render.consolePrefixColor('brightGreen');
|
|
1135
|
+
const supportBot = new WhatsAppClient();
|
|
1136
|
+
|
|
1137
|
+
// Bot 2 - Blau
|
|
1138
|
+
render.consolePrefix('Sales');
|
|
1139
|
+
render.consolePrefixColor('brightBlue');
|
|
1140
|
+
const salesBot = new WhatsAppClient();
|
|
1141
|
+
|
|
1142
|
+
// Bot 3 - Magenta
|
|
1143
|
+
render.consolePrefix('Admin');
|
|
1144
|
+
render.consolePrefixColor('brightMagenta');
|
|
1145
|
+
const adminBot = new WhatsAppClient();
|
|
1146
|
+
|
|
1147
|
+
// Jetzt hat jeder Bot seine eigene Farbe in der Console!
|
|
1148
|
+
// [Support] Nachricht empfangen... (grün)
|
|
1149
|
+
// [Sales] Kunde kontaktiert... (blau)
|
|
1150
|
+
// [Admin] Gruppe erstellt... (magenta)
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
---
|
|
1154
|
+
|
|
1155
|
+
## 🗑️ MessageDel API - Nachrichten von anderen Usern löschen **NEU in v2.0.0!**
|
|
1156
|
+
|
|
1157
|
+
### **Admin-Funktion zum Löschen von Nachrichten anderer User**
|
|
1158
|
+
|
|
1159
|
+
Lösche Nachrichten von anderen Usern in Gruppen (erfordert Admin-Rechte)!
|
|
1160
|
+
|
|
1161
|
+
```javascript
|
|
1162
|
+
// Nachricht von anderem User löschen
|
|
1163
|
+
const result = await msg.MessageDel(messageId, participantJid);
|
|
1164
|
+
|
|
1165
|
+
if (result.success) {
|
|
1166
|
+
console.log('✅ Nachricht gelöscht!');
|
|
1167
|
+
} else {
|
|
1168
|
+
console.log(`❌ Fehler: ${result.reason}`);
|
|
1169
|
+
}
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
### **Return Object**
|
|
1173
|
+
```javascript
|
|
1174
|
+
{
|
|
1175
|
+
success: boolean, // true wenn erfolgreich
|
|
1176
|
+
messageId: string, // ID der gelöschten Nachricht
|
|
1177
|
+
participant: string, // JID des ursprünglichen Senders
|
|
1178
|
+
wasFromBot: boolean, // true wenn Bot-Nachricht
|
|
1179
|
+
result: object, // Baileys Result Object
|
|
1180
|
+
reason: string,
|
|
1181
|
+
|
|
1182
|
+
---
|
|
1183
|
+
|
|
1016
1184
|
## 💾 Storage System
|
|
1017
1185
|
|
|
1018
1186
|
### **Einfache Storage API**
|
package/README.md
CHANGED
|
@@ -100,7 +100,7 @@ client.on('truly_connected', (data) => {
|
|
|
100
100
|
- **Button Messages** - Interactive buttons with callbacks
|
|
101
101
|
- **List Messages** - Organized lists with sections
|
|
102
102
|
- **Template Messages** - Reusable message templates
|
|
103
|
-
- **Carousel
|
|
103
|
+
- **Interactive Carousel** - REAL swipeable carousel in ONE message with VIDEO support! 🎬
|
|
104
104
|
|
|
105
105
|
### 👥 **Advanced Group Features**
|
|
106
106
|
- **Group Settings** - Control who can send messages
|
|
@@ -216,10 +216,20 @@ client.setPrefix('!');
|
|
|
216
216
|
// NEW: Ignore offline messages to prevent spam
|
|
217
217
|
client.ignore.message.offline(true);
|
|
218
218
|
|
|
219
|
+
// NEW: Control if bot ignores its own messages (default: true)
|
|
220
|
+
client.ignore.message.FromMe(true); // Bot ignores itself (prevents loops)
|
|
221
|
+
// client.ignore.message.FromMe(false); // Bot reacts to own messages
|
|
222
|
+
|
|
219
223
|
client.on('message', async (msg) => {
|
|
220
224
|
if (msg.text === 'hello') {
|
|
221
225
|
await msg.simulateTyping('Hello! How can I help?');
|
|
222
226
|
}
|
|
227
|
+
|
|
228
|
+
// Dynamically change FromMe ignore during runtime
|
|
229
|
+
if (msg.text === '/enable-echo') {
|
|
230
|
+
msg.ignore.FromMe(false); // Bot now reacts to own messages
|
|
231
|
+
await msg.reply('Echo mode enabled!');
|
|
232
|
+
}
|
|
223
233
|
});
|
|
224
234
|
|
|
225
235
|
await client.connect();
|
|
@@ -859,6 +869,111 @@ const type = client.getMessageType(message)
|
|
|
859
869
|
|
|
860
870
|
---
|
|
861
871
|
|
|
872
|
+
## 🤖 FromMe Ignore API
|
|
873
|
+
|
|
874
|
+
### **Control Bot Self-Interaction**
|
|
875
|
+
|
|
876
|
+
By default, the bot ignores its own messages to prevent infinite loops. You can control this behavior:
|
|
877
|
+
|
|
878
|
+
```javascript
|
|
879
|
+
import { WhatsAppClient } from "waengine";
|
|
880
|
+
|
|
881
|
+
const client = new WhatsAppClient();
|
|
882
|
+
|
|
883
|
+
// ✅ Default: Bot ignores its own messages (prevents loops)
|
|
884
|
+
client.ignore.message.FromMe(true);
|
|
885
|
+
|
|
886
|
+
// ❌ Bot reacts to its own messages (use with caution!)
|
|
887
|
+
client.ignore.message.FromMe(false);
|
|
888
|
+
|
|
889
|
+
client.on('message', async (msg) => {
|
|
890
|
+
if (msg.text === '/menu') {
|
|
891
|
+
// With FromMe(true): Bot sends /menu but doesn't process it ✅
|
|
892
|
+
// With FromMe(false): Bot sends /menu and processes it again ❌ (loop!)
|
|
893
|
+
await msg.reply('📋 Menu: /help, /info, /status');
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
await client.connect();
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
### **Dynamic Control During Runtime**
|
|
901
|
+
|
|
902
|
+
```javascript
|
|
903
|
+
client.on('message', async (msg) => {
|
|
904
|
+
// Enable echo mode (bot reacts to own messages)
|
|
905
|
+
if (msg.text === '/echo-on') {
|
|
906
|
+
msg.ignore.FromMe(false);
|
|
907
|
+
await msg.reply('🔊 Echo mode enabled!');
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// Disable echo mode (bot ignores own messages)
|
|
911
|
+
if (msg.text === '/echo-off') {
|
|
912
|
+
msg.ignore.FromMe(true);
|
|
913
|
+
await msg.reply('🔇 Echo mode disabled!');
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Check current status
|
|
917
|
+
if (msg.text === '/status') {
|
|
918
|
+
const status = client.ignoreFromMe ? 'ACTIVE ✅' : 'INACTIVE ❌';
|
|
919
|
+
await msg.reply(`FromMe Ignore: ${status}`);
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
### **Use Cases**
|
|
925
|
+
|
|
926
|
+
**Standard Bot (Recommended):**
|
|
927
|
+
```javascript
|
|
928
|
+
// Default behavior - bot ignores itself
|
|
929
|
+
// No configuration needed!
|
|
930
|
+
client.on('message', async (msg) => {
|
|
931
|
+
if (msg.text === '/menu') {
|
|
932
|
+
await msg.reply('Menu displayed!');
|
|
933
|
+
// ✅ No infinite loop
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
**Echo Bot:**
|
|
939
|
+
```javascript
|
|
940
|
+
// Bot reacts to own messages
|
|
941
|
+
client.ignore.message.FromMe(false);
|
|
942
|
+
|
|
943
|
+
const processedIds = new Set();
|
|
944
|
+
|
|
945
|
+
client.on('message', async (msg) => {
|
|
946
|
+
// Prevent infinite loops with message ID tracking
|
|
947
|
+
if (processedIds.has(msg.id)) return;
|
|
948
|
+
processedIds.add(msg.id);
|
|
949
|
+
|
|
950
|
+
if (!msg.text.startsWith('/')) {
|
|
951
|
+
await msg.reply(`Echo: ${msg.text}`);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
**Self-Testing Bot:**
|
|
957
|
+
```javascript
|
|
958
|
+
// Bot tests its own commands
|
|
959
|
+
client.ignore.message.FromMe(false);
|
|
960
|
+
|
|
961
|
+
client.on('message', async (msg) => {
|
|
962
|
+
if (msg.text === '/test-all') {
|
|
963
|
+
// Bot sends and processes its own commands
|
|
964
|
+
await msg.reply('/help');
|
|
965
|
+
await msg.reply('/info');
|
|
966
|
+
await msg.reply('/status');
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
⚠️ **Important:** When using `FromMe(false)`, always implement loop prevention mechanisms!
|
|
972
|
+
|
|
973
|
+
📚 **Full Documentation:** See [FROMME-IGNORE-API.md](./FROMME-IGNORE-API.md)
|
|
974
|
+
|
|
975
|
+
---
|
|
976
|
+
|
|
862
977
|
## 📚 Examples
|
|
863
978
|
|
|
864
979
|
### **EasyBot (Beginners)**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waengine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.4",
|
|
4
4
|
"description": "🚀 WAEngine - The most powerful WhatsApp Bot Library with 860+ Working Features, Complete Baileys Integration & Production-Ready Stability",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
package/src/advanced-features.js
CHANGED
|
@@ -235,75 +235,170 @@ export class AdvancedMessage {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
async sendCarouselMessage(cards) {
|
|
238
|
+
async sendCarouselMessage(cards, options = {}) {
|
|
239
239
|
try {
|
|
240
|
-
|
|
241
|
-
const
|
|
240
|
+
const fs = await import('fs');
|
|
241
|
+
const { prepareWAMessageMedia, generateWAMessageFromContent } = await import('@whiskeysockets/baileys');
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
243
|
+
// Default options
|
|
244
|
+
const carouselHeader = options.header || 'Carousel';
|
|
245
|
+
const carouselBody = options.body || 'Swipe to see all options';
|
|
246
|
+
|
|
247
|
+
// Prepare all cards with media
|
|
248
|
+
const preparedCards = [];
|
|
249
|
+
|
|
250
|
+
for (const [index, card] of cards.entries()) {
|
|
251
|
+
const carouselCard = {
|
|
252
|
+
body: card.body || '',
|
|
253
|
+
footer: card.footer || `${index + 1}/${cards.length}`,
|
|
254
|
+
header: {
|
|
255
|
+
title: card.title,
|
|
256
|
+
subtitle: card.subtitle || '',
|
|
257
|
+
hasMediaAttachment: false
|
|
258
|
+
},
|
|
259
|
+
nativeFlowMessage: {
|
|
260
|
+
buttons: []
|
|
261
|
+
}
|
|
262
|
+
};
|
|
259
263
|
|
|
260
|
-
//
|
|
261
|
-
let result;
|
|
264
|
+
// Prepare media if exists
|
|
262
265
|
if (card.video) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
266
|
+
try {
|
|
267
|
+
const videoBuffer = fs.readFileSync(card.video);
|
|
268
|
+
const preparedMedia = await prepareWAMessageMedia(
|
|
269
|
+
{ video: videoBuffer },
|
|
270
|
+
{ upload: this.socket.waUploadToServer }
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
if (preparedMedia && preparedMedia.videoMessage) {
|
|
274
|
+
carouselCard.header.hasMediaAttachment = true;
|
|
275
|
+
carouselCard.header.videoMessage = preparedMedia.videoMessage;
|
|
276
|
+
}
|
|
277
|
+
} catch (mediaError) {
|
|
278
|
+
console.error('⚠️ Video preparation failed:', mediaError.message);
|
|
279
|
+
// Continue without video
|
|
280
|
+
}
|
|
269
281
|
} else if (card.image) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
282
|
+
try {
|
|
283
|
+
const imageBuffer = fs.readFileSync(card.image);
|
|
284
|
+
const preparedMedia = await prepareWAMessageMedia(
|
|
285
|
+
{ image: imageBuffer },
|
|
286
|
+
{ upload: this.socket.waUploadToServer }
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
if (preparedMedia && preparedMedia.imageMessage) {
|
|
290
|
+
carouselCard.header.hasMediaAttachment = true;
|
|
291
|
+
carouselCard.header.imageMessage = preparedMedia.imageMessage;
|
|
292
|
+
}
|
|
293
|
+
} catch (mediaError) {
|
|
294
|
+
console.error('⚠️ Image preparation failed:', mediaError.message);
|
|
295
|
+
// Continue without image
|
|
296
|
+
}
|
|
278
297
|
}
|
|
279
298
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
299
|
+
// Add buttons
|
|
300
|
+
if (card.buttons && card.buttons.length > 0) {
|
|
301
|
+
carouselCard.nativeFlowMessage.buttons = card.buttons.map(btn => ({
|
|
302
|
+
name: 'quick_reply',
|
|
303
|
+
buttonParamsJson: JSON.stringify({
|
|
304
|
+
display_text: btn.text || btn.title,
|
|
305
|
+
id: btn.id || `btn_${index}`
|
|
306
|
+
})
|
|
307
|
+
}));
|
|
285
308
|
}
|
|
309
|
+
|
|
310
|
+
preparedCards.push(carouselCard);
|
|
286
311
|
}
|
|
287
312
|
|
|
288
|
-
|
|
313
|
+
// Create the carousel message structure
|
|
314
|
+
const message = generateWAMessageFromContent(
|
|
315
|
+
this.msg.from,
|
|
316
|
+
{
|
|
317
|
+
viewOnceMessage: {
|
|
318
|
+
message: {
|
|
319
|
+
interactiveMessage: {
|
|
320
|
+
header: {
|
|
321
|
+
title: carouselHeader,
|
|
322
|
+
hasMediaAttachment: false
|
|
323
|
+
},
|
|
324
|
+
body: {
|
|
325
|
+
text: carouselBody
|
|
326
|
+
},
|
|
327
|
+
carouselMessage: {
|
|
328
|
+
cards: preparedCards
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
{ userJid: this.socket.user.id }
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
return await this.socket.relayMessage(this.msg.from, message.message, {
|
|
338
|
+
messageId: message.key.id
|
|
339
|
+
});
|
|
340
|
+
|
|
289
341
|
} catch (error) {
|
|
290
|
-
console.error('❌ Carousel
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
342
|
+
console.error('❌ Interactive Carousel fehlgeschlagen:', error);
|
|
343
|
+
|
|
344
|
+
// Fallback: Send videos individually
|
|
345
|
+
try {
|
|
346
|
+
console.log('🔄 Fallback: Sending cards individually...');
|
|
347
|
+
const results = [];
|
|
348
|
+
const fs = await import('fs');
|
|
349
|
+
|
|
350
|
+
for (const [index, card] of cards.entries()) {
|
|
351
|
+
try {
|
|
352
|
+
const caption = `${card.title}\n\n${card.body || ''}\n\n${card.footer || ''}`;
|
|
353
|
+
|
|
354
|
+
if (card.video) {
|
|
355
|
+
// Send as video using socket directly
|
|
356
|
+
const videoBuffer = fs.readFileSync(card.video);
|
|
357
|
+
await this.socket.sendMessage(this.msg.from, {
|
|
358
|
+
video: videoBuffer,
|
|
359
|
+
caption: caption,
|
|
360
|
+
gifPlayback: card.gifPlayback || false
|
|
361
|
+
});
|
|
362
|
+
} else if (card.image) {
|
|
363
|
+
// Send as image using socket directly
|
|
364
|
+
const imageBuffer = fs.readFileSync(card.image);
|
|
365
|
+
await this.socket.sendMessage(this.msg.from, {
|
|
366
|
+
image: imageBuffer,
|
|
367
|
+
caption: caption
|
|
368
|
+
});
|
|
369
|
+
} else {
|
|
370
|
+
// Send as text
|
|
371
|
+
await this.socket.sendMessage(this.msg.from, {
|
|
372
|
+
text: caption
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
results.push({ index, success: true });
|
|
376
|
+
|
|
377
|
+
// Small delay between messages
|
|
378
|
+
if (index < cards.length - 1) {
|
|
379
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
380
|
+
}
|
|
381
|
+
} catch (cardError) {
|
|
382
|
+
console.error(`❌ Card ${index} fehlgeschlagen:`, cardError);
|
|
383
|
+
results.push({ index, success: false, error: cardError.message });
|
|
384
|
+
}
|
|
304
385
|
}
|
|
386
|
+
|
|
387
|
+
console.log('✅ Fallback completed:', results);
|
|
388
|
+
return { type: 'fallback_individual', results };
|
|
389
|
+
|
|
390
|
+
} catch (fallbackError) {
|
|
391
|
+
console.error('❌ Individual fallback fehlgeschlagen:', fallbackError);
|
|
392
|
+
|
|
393
|
+
// Final fallback: Text list
|
|
394
|
+
const fallbackText = cards.map((card, i) =>
|
|
395
|
+
`${i + 1}. **${card.title}**\n${card.body || ''}`
|
|
396
|
+
).join('\n\n');
|
|
397
|
+
|
|
398
|
+
return await this.socket.sendMessage(this.msg.from, {
|
|
399
|
+
text: fallbackText
|
|
400
|
+
});
|
|
305
401
|
}
|
|
306
|
-
return results;
|
|
307
402
|
}
|
|
308
403
|
}
|
|
309
404
|
}
|
package/src/client.js
CHANGED
|
@@ -145,6 +145,9 @@ export class WhatsAppClient {
|
|
|
145
145
|
this.ignoredMessagesCount = 0; // Counter für ignorierte Messages
|
|
146
146
|
this.offlineMessageTimer = null; // Timer für finale Zusammenfassung
|
|
147
147
|
|
|
148
|
+
// FromMe Ignore System - NEUE GLOBALE API!
|
|
149
|
+
this.ignoreFromMe = true; // Standard: Bot ignoriert sich selbst
|
|
150
|
+
|
|
148
151
|
// Log wenn automatisch aktiviert
|
|
149
152
|
if (this.ignoreOfflineMessages) {
|
|
150
153
|
console.log('\n📵 Offline Message Ignore: AUTOMATISCH AKTIVIERT');
|
|
@@ -178,6 +181,11 @@ export class WhatsAppClient {
|
|
|
178
181
|
this.ignoreOfflineMessages = enabled;
|
|
179
182
|
console.log(`📵 Offline Message Ignore: ${enabled ? 'AKTIVIERT' : 'DEAKTIVIERT'}`);
|
|
180
183
|
return this;
|
|
184
|
+
},
|
|
185
|
+
FromMe: (enabled = true) => {
|
|
186
|
+
this.ignoreFromMe = enabled;
|
|
187
|
+
console.log(`🤖 FromMe Ignore: ${enabled ? 'AKTIVIERT (Bot ignoriert sich selbst)' : 'DEAKTIVIERT (Bot reagiert auf eigene Messages)'}`);
|
|
188
|
+
return this;
|
|
181
189
|
}
|
|
182
190
|
}
|
|
183
191
|
};
|
|
@@ -373,7 +381,7 @@ export class WhatsAppClient {
|
|
|
373
381
|
this.socket = makeWASocket({
|
|
374
382
|
version,
|
|
375
383
|
auth: state,
|
|
376
|
-
logger: pino({ level:
|
|
384
|
+
logger: pino({ level: 'silent' }), // Force silent to prevent session logs
|
|
377
385
|
browser: this.options.browser,
|
|
378
386
|
generateHighQualityLinkPreview: true,
|
|
379
387
|
syncFullHistory: true, // Wichtig für Message-Empfang
|
|
@@ -394,7 +402,7 @@ export class WhatsAppClient {
|
|
|
394
402
|
} catch (versionError) {
|
|
395
403
|
this.socket = makeWASocket({
|
|
396
404
|
auth: state,
|
|
397
|
-
logger: pino({ level:
|
|
405
|
+
logger: pino({ level: 'silent' }), // Force silent to prevent session logs
|
|
398
406
|
browser: this.options.browser,
|
|
399
407
|
generateHighQualityLinkPreview: true,
|
|
400
408
|
syncFullHistory: true, // Wichtig für Message-Empfang
|
|
@@ -993,7 +1001,12 @@ export class WhatsAppClient {
|
|
|
993
1001
|
}
|
|
994
1002
|
|
|
995
1003
|
// Bessere Message-Validierung
|
|
996
|
-
if (!msg.message
|
|
1004
|
+
if (!msg.message) return;
|
|
1005
|
+
|
|
1006
|
+
// FromMe Ignore - DEINE NEUE FUNKTION!
|
|
1007
|
+
if (this.ignoreFromMe && msg.key.fromMe) {
|
|
1008
|
+
return; // Bot ignoriert seine eigenen Messages
|
|
1009
|
+
}
|
|
997
1010
|
|
|
998
1011
|
// OFFLINE MESSAGE IGNORE - DEINE NEUE FUNKTION!
|
|
999
1012
|
if (this.ignoreOfflineMessages && this.connectionStartTime) {
|
package/src/message.js
CHANGED
|
@@ -37,6 +37,15 @@ export class Message {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
|
+
|
|
41
|
+
// Ignore API - DEINE NEUE FUNKTION!
|
|
42
|
+
this.ignore = {
|
|
43
|
+
FromMe: (enabled = true) => {
|
|
44
|
+
this.client.ignoreFromMe = enabled;
|
|
45
|
+
console.log(`🤖 FromMe Ignore: ${enabled ? 'AKTIVIERT (Bot ignoriert sich selbst)' : 'DEAKTIVIERT (Bot reagiert auf eigene Messages)'}`);
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
40
49
|
|
|
41
50
|
// ===== ADVANCED FEATURES INTEGRATION - NEU! =====
|
|
42
51
|
this.advanced = new AdvancedMessage(this);
|
package/src/ui-components.js
CHANGED
|
@@ -6,88 +6,91 @@ export class UIComponents {
|
|
|
6
6
|
// ===== CAROUSEL MESSAGES =====
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Send carousel message with
|
|
10
|
-
*
|
|
9
|
+
* Send REAL carousel message with swipeable cards in ONE message
|
|
10
|
+
* Uses WhatsApp Interactive Message API
|
|
11
11
|
*/
|
|
12
12
|
async sendCarousel(chatId, cards, options = {}) {
|
|
13
13
|
try {
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
// Build proper WhatsApp Interactive Carousel Message
|
|
15
|
+
const carouselMessage = {
|
|
16
|
+
interactiveMessage: {
|
|
17
|
+
header: {
|
|
18
|
+
title: options.title || 'Carousel',
|
|
19
|
+
hasMediaAttachment: false
|
|
20
|
+
},
|
|
21
|
+
body: {
|
|
22
|
+
text: options.body || 'Swipe to see all options'
|
|
23
|
+
},
|
|
24
|
+
footer: {
|
|
25
|
+
text: options.footer || ''
|
|
26
|
+
},
|
|
27
|
+
carouselMessage: {
|
|
28
|
+
cards: cards.map((card, index) => {
|
|
29
|
+
const carouselCard = {
|
|
30
|
+
body: {
|
|
31
|
+
text: card.body || card.description || ''
|
|
32
|
+
},
|
|
33
|
+
footer: {
|
|
34
|
+
text: card.footer || `${index + 1}/${cards.length}`
|
|
35
|
+
},
|
|
36
|
+
nativeFlowMessage: {
|
|
37
|
+
buttons: []
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Add header with media
|
|
42
|
+
if (card.video) {
|
|
43
|
+
carouselCard.header = {
|
|
44
|
+
title: card.title,
|
|
45
|
+
subtitle: card.subtitle || '',
|
|
46
|
+
hasMediaAttachment: true,
|
|
47
|
+
videoMessage: {
|
|
48
|
+
url: card.video,
|
|
49
|
+
gifPlayback: card.gifPlayback || false
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
} else if (card.image) {
|
|
53
|
+
carouselCard.header = {
|
|
54
|
+
title: card.title,
|
|
55
|
+
subtitle: card.subtitle || '',
|
|
56
|
+
hasMediaAttachment: true,
|
|
57
|
+
imageMessage: {
|
|
58
|
+
url: card.image
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
} else {
|
|
62
|
+
carouselCard.header = {
|
|
63
|
+
title: card.title,
|
|
64
|
+
subtitle: card.subtitle || '',
|
|
65
|
+
hasMediaAttachment: false
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Add buttons
|
|
70
|
+
if (card.buttons && card.buttons.length > 0) {
|
|
71
|
+
carouselCard.nativeFlowMessage.buttons = card.buttons.map(btn => ({
|
|
72
|
+
name: 'quick_reply',
|
|
73
|
+
buttonParamsJson: JSON.stringify({
|
|
74
|
+
display_text: btn.title || btn.text,
|
|
75
|
+
id: btn.id || `btn_${index}_${btn.title}`
|
|
76
|
+
})
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return carouselCard;
|
|
81
|
+
})
|
|
82
|
+
}
|
|
30
83
|
}
|
|
31
|
-
|
|
32
|
-
carouselText += `\n`;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
if (options.footer) {
|
|
36
|
-
carouselText += `\n_${options.footer}_`;
|
|
37
|
-
}
|
|
84
|
+
};
|
|
38
85
|
|
|
39
|
-
// Send
|
|
40
|
-
|
|
41
|
-
const card = cards[i];
|
|
42
|
-
|
|
43
|
-
// Build card text
|
|
44
|
-
let cardText = `**${i + 1}/${cards.length}: ${card.title}**\n`;
|
|
45
|
-
if (card.subtitle) cardText += `${card.subtitle}\n`;
|
|
46
|
-
if (card.body) cardText += `${card.body}\n`;
|
|
47
|
-
if (card.price) cardText += `💰 ${card.price}\n`;
|
|
48
|
-
|
|
49
|
-
if (card.buttons && card.buttons.length > 0) {
|
|
50
|
-
cardText += `\nOptions: `;
|
|
51
|
-
card.buttons.forEach((btn, btnIndex) => {
|
|
52
|
-
cardText += `[${btnIndex + 1}] ${btn.title} `;
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (options.footer) {
|
|
57
|
-
cardText += `\n\n_${options.footer}_`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Send with appropriate media type
|
|
61
|
-
if (card.video) {
|
|
62
|
-
// Video card
|
|
63
|
-
await this.client.socket.sendMessage(chatId, {
|
|
64
|
-
video: { url: card.video },
|
|
65
|
-
caption: cardText,
|
|
66
|
-
gifPlayback: card.gifPlayback || false
|
|
67
|
-
});
|
|
68
|
-
} else if (card.image) {
|
|
69
|
-
// Image card
|
|
70
|
-
await this.client.socket.sendMessage(chatId, {
|
|
71
|
-
image: { url: card.image },
|
|
72
|
-
caption: cardText
|
|
73
|
-
});
|
|
74
|
-
} else {
|
|
75
|
-
// Text-only card
|
|
76
|
-
await this.client.socket.sendMessage(chatId, {
|
|
77
|
-
text: cardText
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Small delay between cards to prevent spam
|
|
82
|
-
if (i < cards.length - 1) {
|
|
83
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
+
// Send the carousel
|
|
87
|
+
const result = await this.client.socket.sendMessage(chatId, carouselMessage);
|
|
86
88
|
|
|
87
89
|
return {
|
|
88
90
|
success: true,
|
|
89
|
-
type: '
|
|
91
|
+
type: 'interactive_carousel',
|
|
90
92
|
cards: cards.length,
|
|
93
|
+
messageId: result.key.id,
|
|
91
94
|
mediaTypes: {
|
|
92
95
|
videos: cards.filter(c => c.video).length,
|
|
93
96
|
images: cards.filter(c => c.image).length,
|
|
@@ -96,14 +99,80 @@ export class UIComponents {
|
|
|
96
99
|
};
|
|
97
100
|
|
|
98
101
|
} catch (error) {
|
|
99
|
-
console.error('❌ Carousel
|
|
102
|
+
console.error('❌ Interactive Carousel failed, trying fallback:', error);
|
|
100
103
|
|
|
101
|
-
// Fallback
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
// Fallback 1: Try native carousel format
|
|
105
|
+
try {
|
|
106
|
+
const nativeCarousel = {
|
|
107
|
+
viewOnceMessage: {
|
|
108
|
+
message: {
|
|
109
|
+
messageContextInfo: {
|
|
110
|
+
deviceListMetadata: {},
|
|
111
|
+
deviceListMetadataVersion: 2
|
|
112
|
+
},
|
|
113
|
+
interactiveMessage: {
|
|
114
|
+
nativeFlowMessage: {
|
|
115
|
+
buttons: cards.map((card, i) => ({
|
|
116
|
+
name: 'single_select',
|
|
117
|
+
buttonParamsJson: JSON.stringify({
|
|
118
|
+
title: card.title,
|
|
119
|
+
sections: [{
|
|
120
|
+
title: card.subtitle || '',
|
|
121
|
+
rows: [{
|
|
122
|
+
title: card.title,
|
|
123
|
+
description: card.body,
|
|
124
|
+
id: `card_${i}`
|
|
125
|
+
}]
|
|
126
|
+
}]
|
|
127
|
+
})
|
|
128
|
+
}))
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const result = await this.client.socket.sendMessage(chatId, nativeCarousel);
|
|
136
|
+
return { success: true, type: 'native_carousel', cards: cards.length };
|
|
137
|
+
|
|
138
|
+
} catch (nativeError) {
|
|
139
|
+
console.error('❌ Native carousel also failed, using list fallback:', nativeError);
|
|
140
|
+
|
|
141
|
+
// Fallback 2: Use List Message (closest to carousel)
|
|
142
|
+
try {
|
|
143
|
+
const listMessage = {
|
|
144
|
+
text: options.title || 'Select an option',
|
|
145
|
+
footer: options.footer || `${cards.length} options available`,
|
|
146
|
+
title: options.title || 'Carousel',
|
|
147
|
+
buttonText: 'View Options',
|
|
148
|
+
sections: [{
|
|
149
|
+
title: 'All Options',
|
|
150
|
+
rows: cards.map((card, i) => ({
|
|
151
|
+
title: card.title,
|
|
152
|
+
description: card.body || card.subtitle || '',
|
|
153
|
+
rowId: `carousel_${i}`
|
|
154
|
+
}))
|
|
155
|
+
}]
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const result = await this.client.socket.sendMessage(chatId, listMessage);
|
|
159
|
+
return { success: true, type: 'list_fallback', cards: cards.length };
|
|
160
|
+
|
|
161
|
+
} catch (listError) {
|
|
162
|
+
console.error('❌ List fallback failed, using text:', listError);
|
|
163
|
+
|
|
164
|
+
// Fallback 3: Simple text with emojis
|
|
165
|
+
const fallbackText = `🎠 **${options.title || 'Carousel'}**\n\n` +
|
|
166
|
+
cards.map((card, i) =>
|
|
167
|
+
`${i + 1}️⃣ **${card.title}**\n` +
|
|
168
|
+
`${card.subtitle ? ` ${card.subtitle}\n` : ''}` +
|
|
169
|
+
` ${card.body || ''}\n`
|
|
170
|
+
).join('\n');
|
|
171
|
+
|
|
172
|
+
await this.client.socket.sendMessage(chatId, { text: fallbackText });
|
|
173
|
+
return { success: true, type: 'text_fallback', cards: cards.length };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
107
176
|
}
|
|
108
177
|
}
|
|
109
178
|
|