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 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 Messages** - Swipeable card carousels with VIDEO support! 🎬
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.9",
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",
@@ -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
- // WhatsApp Carousel mit Video & Image Support
241
- const results = [];
240
+ const fs = await import('fs');
241
+ const { prepareWAMessageMedia, generateWAMessageFromContent } = await import('@whiskeysockets/baileys');
242
242
 
243
- for (let i = 0; i < cards.length; i++) {
244
- const card = cards[i];
245
-
246
- // Build card text
247
- let cardText = `🎴 **${i + 1}/${cards.length}: ${card.title}**\n`;
248
- if (card.subtitle) cardText += `${card.subtitle}\n\n`;
249
- if (card.body) cardText += `${card.body}`;
250
- if (card.footer) cardText += `\n\n_${card.footer}_`;
251
-
252
- // Add buttons as text
253
- if (card.buttons && card.buttons.length > 0) {
254
- cardText += `\n\n**Options:**\n`;
255
- card.buttons.forEach((btn, btnIndex) => {
256
- cardText += `${btnIndex + 1}. ${btn.text || btn.title}\n`;
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
- // Send with appropriate media type
261
- let result;
264
+ // Prepare media if exists
262
265
  if (card.video) {
263
- // Video card
264
- result = await this.socket.sendMessage(this.msg.from, {
265
- video: { url: card.video },
266
- caption: cardText,
267
- gifPlayback: card.gifPlayback || false
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
- // Image card
271
- result = await this.socket.sendMessage(this.msg.from, {
272
- image: { url: card.image },
273
- caption: cardText
274
- });
275
- } else {
276
- // Text-only card
277
- result = await this.msg.reply(cardText);
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
- results.push(result);
281
-
282
- // Small delay between cards
283
- if (i < cards.length - 1) {
284
- await new Promise(resolve => setTimeout(resolve, 500));
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
- return results;
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 Message fehlgeschlagen:', error);
291
- // Fallback: Sende Cards als Text
292
- const results = [];
293
- for (const card of cards) {
294
- try {
295
- let cardText = `🎴 **${card.title}**\n`;
296
- if (card.subtitle) cardText += `${card.subtitle}\n\n`;
297
- cardText += card.body;
298
- if (card.footer) cardText += `\n\n_${card.footer}_`;
299
-
300
- const result = await this.msg.reply(cardText);
301
- results.push(result);
302
- } catch (cardError) {
303
- console.error('❌ Card fehlgeschlagen:', cardError);
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: this.options.logLevel }),
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: this.options.logLevel }),
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 || msg.key.fromMe) return;
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);
@@ -6,88 +6,91 @@ export class UIComponents {
6
6
  // ===== CAROUSEL MESSAGES =====
7
7
 
8
8
  /**
9
- * Send carousel message with multiple cards
10
- * Supports: images, videos, and text-only cards
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
- // WhatsApp doesn't support native carousels, so we create a rich media alternative
15
- let carouselText = `🎠 **${options.title || 'Carousel'}**\n\n`;
16
-
17
- cards.forEach((card, index) => {
18
- carouselText += `**${index + 1}. ${card.title}**\n`;
19
- if (card.subtitle) carouselText += `${card.subtitle}\n`;
20
- if (card.body) carouselText += `${card.body}\n`;
21
- if (card.price) carouselText += `💰 ${card.price}\n`;
22
-
23
- // Add buttons as text options
24
- if (card.buttons && card.buttons.length > 0) {
25
- carouselText += `Options: `;
26
- card.buttons.forEach((btn, btnIndex) => {
27
- carouselText += `[${btnIndex + 1}] ${btn.title} `;
28
- });
29
- carouselText += `\n`;
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 each card with its media (image or video)
40
- for (let i = 0; i < cards.length; i++) {
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: 'carousel',
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 error:', error);
102
+ console.error('❌ Interactive Carousel failed, trying fallback:', error);
100
103
 
101
- // Fallback to simple text
102
- const fallbackText = `📋 **${options.title || 'Options'}**\n\n` +
103
- cards.map((card, i) => `${i + 1}. ${card.title}`).join('\n');
104
-
105
- await this.client.socket.sendMessage(chatId, { text: fallbackText });
106
- return { success: true, type: 'fallback', cards: cards.length };
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