waengine 1.1.2 → 1.7.3

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/src/client.js CHANGED
@@ -9,6 +9,7 @@ import { AIIntegration } from "./ai-integration.js";
9
9
  import { HTTPClient } from "./http-client.js";
10
10
  import { Scheduler } from "./scheduler.js";
11
11
  import { PluginManager } from "./plugin-manager-fixed.js";
12
+ import { AdvancedGroup, AdvancedPrivacy, AdvancedAnalytics, AdvancedStatus, AdvancedBusiness, AdvancedSystem } from "./advanced-features.js";
12
13
 
13
14
  export class WhatsAppClient {
14
15
  constructor(options = {}) {
@@ -20,15 +21,43 @@ export class WhatsAppClient {
20
21
  autoCleanup: options.autoCleanup !== false, // Auto-Cleanup bei Logout
21
22
  autoRestart: options.autoRestart !== false, // Auto-Restart nach Logout
22
23
  restartDelay: options.restartDelay || 5000, // 5 Sekunden Wartezeit
24
+
25
+ // QR-SPAM PREVENTION - NEU!
26
+ qrSpamPrevention: options.qrSpamPrevention !== false, // Anti-Spam aktiviert
27
+ qrDisplayInterval: options.qrDisplayInterval || 30000, // 30 Sekunden zwischen QR-Anzeigen
28
+ qrMaxDisplays: options.qrMaxDisplays || 5, // Max 5 QR-Anzeigen im Terminal
29
+ clearTerminalOnQR: options.clearTerminalOnQR !== false, // Terminal bei QR leeren
30
+
31
+ // ROBUSTE CONNECTION SETTINGS - NEU!
32
+ maxReconnectAttempts: options.maxReconnectAttempts || 50, // Viele Versuche
33
+ reconnectInterval: options.reconnectInterval || 3000, // 3 Sekunden zwischen Versuchen
34
+ exponentialBackoff: options.exponentialBackoff !== false, // Exponential backoff
35
+ maxBackoffDelay: options.maxBackoffDelay || 60000, // Max 1 Minute Wartezeit
36
+ heartbeatInterval: options.heartbeatInterval || 30000, // 30 Sekunden Heartbeat
37
+ connectionTimeout: options.connectionTimeout || 120000, // 2 Minuten Timeout (war 60s)
38
+ keepAlive: options.keepAlive !== false, // Keep-Alive aktiviert
39
+ quietHeartbeat: options.quietHeartbeat !== false, // Heartbeat-Logging deaktivieren
23
40
  ...options
24
41
  };
25
42
 
26
43
  // Clean initialization
27
-
28
44
  this.socket = null;
29
45
  this.isConnected = false;
30
46
  this.eventHandlers = new Map();
31
47
 
48
+ // ROBUSTE CONNECTION TRACKING - NEU!
49
+ this.reconnectAttempts = 0;
50
+ this.lastConnectionTime = null;
51
+ this.heartbeatTimer = null;
52
+ this.connectionWatchdog = null;
53
+ this.isReconnecting = false;
54
+ this.connectionHealth = {
55
+ lastPing: null,
56
+ pingCount: 0,
57
+ failedPings: 0,
58
+ avgResponseTime: 0
59
+ };
60
+
32
61
  // Session Manager
33
62
  this.sessionManager = new SessionManager(this.options.authDir);
34
63
 
@@ -55,6 +84,13 @@ export class WhatsAppClient {
55
84
  // Plugin System
56
85
  this.plugins = new PluginManager(this);
57
86
 
87
+ // Offline Message Ignore System - NEU!
88
+ this.ignoreOfflineMessages = false;
89
+ this.lastOnlineTimestamp = Date.now();
90
+ this.connectionStartTime = null;
91
+ this.ignoredMessagesCount = 0; // Counter für ignorierte Messages
92
+ this.offlineMessageTimer = null; // Timer für finale Zusammenfassung
93
+
58
94
  // Load API für Plugins
59
95
  this.load = {
60
96
  Plugins: async (pluginName) => {
@@ -69,12 +105,84 @@ export class WhatsAppClient {
69
105
  }
70
106
  };
71
107
 
108
+ // Ignore API für Offline Messages - DEINE COOLE API!
109
+ this.ignore = {
110
+ message: {
111
+ offline: (enabled = true) => {
112
+ this.ignoreOfflineMessages = enabled;
113
+ console.log(`📵 Offline Message Ignore: ${enabled ? 'AKTIVIERT' : 'DEAKTIVIERT'}`);
114
+ return this;
115
+ }
116
+ }
117
+ };
118
+
72
119
  // Deine eigenen API-Objekte
73
120
  this.get = new GetAPI(this);
74
121
  this.add = new AddAPI(this);
75
122
  this.kick = new KickAPI(this);
76
123
  this.promote = new PromoteAPI(this);
77
124
  this.demote = new DemoteAPI(this);
125
+
126
+ // ===== ADVANCED FEATURES INTEGRATION - NEU! =====
127
+ this.advancedGroup = new AdvancedGroup(this);
128
+ this.advancedPrivacy = new AdvancedPrivacy(this);
129
+ this.advancedAnalytics = new AdvancedAnalytics(this);
130
+ this.advancedStatus = new AdvancedStatus(this);
131
+ this.advancedBusiness = new AdvancedBusiness(this);
132
+ this.advancedSystem = new AdvancedSystem(this);
133
+
134
+ // Convenience Methods für Advanced Features
135
+ this.group = {
136
+ setSettings: this.advancedGroup.setGroupSettings.bind(this.advancedGroup),
137
+ setDescription: this.advancedGroup.setGroupDescription.bind(this.advancedGroup),
138
+ setSubject: this.advancedGroup.setGroupSubject.bind(this.advancedGroup),
139
+ getInviteLink: this.advancedGroup.getGroupInviteLink.bind(this.advancedGroup),
140
+ revokeInviteLink: this.advancedGroup.revokeGroupInviteLink.bind(this.advancedGroup),
141
+ join: this.advancedGroup.joinGroupViaLink.bind(this.advancedGroup),
142
+ leave: this.advancedGroup.leaveGroup.bind(this.advancedGroup),
143
+ updatePicture: this.advancedGroup.updateGroupPicture.bind(this.advancedGroup)
144
+ };
145
+
146
+ this.privacy = {
147
+ block: this.advancedPrivacy.blockUser.bind(this.advancedPrivacy),
148
+ unblock: this.advancedPrivacy.unblockUser.bind(this.advancedPrivacy),
149
+ setSettings: this.advancedPrivacy.setPrivacySettings.bind(this.advancedPrivacy),
150
+ markRead: this.advancedPrivacy.markAsRead.bind(this.advancedPrivacy),
151
+ markUnread: this.advancedPrivacy.markAsUnread.bind(this.advancedPrivacy)
152
+ };
153
+
154
+ this.analytics = {
155
+ getDeliveryStatus: this.advancedAnalytics.getDeliveryStatus.bind(this.advancedAnalytics),
156
+ isOnline: this.advancedAnalytics.isUserOnline.bind(this.advancedAnalytics),
157
+ getLastSeen: this.advancedAnalytics.getLastSeen.bind(this.advancedAnalytics),
158
+ archiveChat: this.advancedAnalytics.archiveChat.bind(this.advancedAnalytics),
159
+ unarchiveChat: this.advancedAnalytics.unarchiveChat.bind(this.advancedAnalytics),
160
+ muteChat: this.advancedAnalytics.muteChat.bind(this.advancedAnalytics),
161
+ unmuteChat: this.advancedAnalytics.unmuteChat.bind(this.advancedAnalytics)
162
+ };
163
+
164
+ this.status = {
165
+ send: this.advancedStatus.sendStatusUpdate.bind(this.advancedStatus),
166
+ getViews: this.advancedStatus.getStatusViews.bind(this.advancedStatus),
167
+ getUserStatus: this.advancedStatus.getUserStatus.bind(this.advancedStatus)
168
+ };
169
+
170
+ this.business = {
171
+ setProfile: this.advancedBusiness.setBusinessProfile.bind(this.advancedBusiness),
172
+ sendProduct: this.advancedBusiness.sendProductMessage.bind(this.advancedBusiness),
173
+ createProduct: this.advancedBusiness.createProduct.bind(this.advancedBusiness),
174
+ requestPayment: this.advancedBusiness.sendPaymentRequest.bind(this.advancedBusiness)
175
+ };
176
+
177
+ this.system = {
178
+ backup: this.advancedSystem.createBackup.bind(this.advancedSystem),
179
+ restore: this.advancedSystem.restoreFromBackup.bind(this.advancedSystem),
180
+ exportChat: this.advancedSystem.exportChat.bind(this.advancedSystem),
181
+ importContacts: this.advancedSystem.importContacts.bind(this.advancedSystem),
182
+ sync: this.advancedSystem.syncWithPhone.bind(this.advancedSystem),
183
+ getDevices: this.advancedSystem.getLinkedDevices.bind(this.advancedSystem),
184
+ unlinkDevice: this.advancedSystem.unlinkDevice.bind(this.advancedSystem)
185
+ };
78
186
  }
79
187
 
80
188
  // ===== CONNECTION METHODS =====
@@ -154,6 +262,7 @@ export class WhatsAppClient {
154
262
 
155
263
  // QR-Code Browser nur öffnen wenn nicht eingeloggt
156
264
  if (!this.options.printQR && !isLoggedIn) {
265
+ console.log("🌍 Starte universelles QR-System...");
157
266
  await generateQRCode();
158
267
  }
159
268
 
@@ -164,16 +273,22 @@ export class WhatsAppClient {
164
273
  this.socket.ev.on("connection.update", async ({ connection, lastDisconnect, qr }) => {
165
274
  if (qr) {
166
275
  if (this.options.printQR) {
167
- // Terminal QR
168
- console.log("\n📱 QR-CODE IM TERMINAL:");
169
- console.log("─".repeat(50));
276
+ // Terminal QR (mit Anti-Spam)
277
+ if (this.options.clearTerminalOnQR) {
278
+ console.clear();
279
+ }
280
+ console.log("\n" + "=".repeat(60));
281
+ console.log("📱 TERMINAL QR-CODE - SAUBER UND SPAM-FREI");
282
+ console.log("=".repeat(60));
170
283
  const qrcode = await import("qrcode-terminal");
171
284
  qrcode.default.generate(qr, { small: true });
172
- console.log("".repeat(50));
285
+ console.log("=".repeat(60));
173
286
  console.log("📲 Scanne den QR-Code mit WhatsApp!");
287
+ console.log("💡 QR wird nur einmal angezeigt - kein Spam!");
288
+ console.log("=".repeat(60));
174
289
  } else {
175
- // Browser QR
176
- console.log("📱 QR-Code im Browser angezeigt");
290
+ // Cross-Platform Browser QR (mit Anti-Spam)
291
+ console.log("🌍 QR-Code wird intelligent angezeigt (Anti-Spam aktiv)...");
177
292
  await generateQRCode(qr);
178
293
  }
179
294
  }
@@ -186,15 +301,22 @@ export class WhatsAppClient {
186
301
  const statusCode = lastDisconnect?.error?.output?.statusCode;
187
302
  const shouldReconnect = statusCode !== DisconnectReason.loggedOut;
188
303
 
304
+ // Cleanup timers
305
+ this.stopHeartbeat();
306
+ this.stopConnectionWatchdog();
307
+
189
308
  if (shouldReconnect) {
190
- console.log("🔄 Wiederverbindung...");
309
+ console.log(`🔄 Verbindung verloren (Code: ${statusCode}) - Starte robuste Wiederverbindung...`);
191
310
  this.isConnected = false;
192
311
  this.socket = null;
193
- setTimeout(() => this.connect().then(resolve).catch(reject), 3000);
312
+
313
+ // Robuste Wiederverbindung mit exponential backoff
314
+ this.startRobustReconnection(resolve, reject);
194
315
  } else {
195
316
  console.log("👋 Ausgeloggt - bereinige Session...");
196
317
  this.isConnected = false;
197
318
  this.socket = null;
319
+ this.reconnectAttempts = 0;
198
320
 
199
321
  // Auto-Cleanup bei Logout
200
322
  if (this.options.autoCleanup) {
@@ -205,31 +327,13 @@ export class WhatsAppClient {
205
327
  await closeBrowser();
206
328
  this.emit('disconnected', { reason: 'logged_out', cleaned: this.options.autoCleanup });
207
329
 
208
- // Auto-Restart Feature
330
+ // Auto-Restart Feature mit robuster Logik
209
331
  if (this.options.autoRestart) {
210
332
  console.log(`🔄 Auto-Restart in ${this.options.restartDelay / 1000} Sekunden...`);
211
333
  console.log("📱 Neuer QR-Code wird generiert...");
212
334
 
213
335
  setTimeout(async () => {
214
- try {
215
- console.log("🚀 Starte neue Session...");
216
- await this.connect();
217
- console.log("✅ Auto-Restart erfolgreich!");
218
- } catch (restartError) {
219
- console.error("❌ Auto-Restart fehlgeschlagen:", restartError.message);
220
- console.log("🔄 Versuche erneut in 10 Sekunden...");
221
-
222
- // Retry nach 10 Sekunden
223
- setTimeout(async () => {
224
- try {
225
- await this.connect();
226
- console.log("✅ Auto-Restart Retry erfolgreich!");
227
- } catch (retryError) {
228
- console.error("❌ Auto-Restart Retry fehlgeschlagen:", retryError.message);
229
- console.log("⚠️ Manuelle Neustart erforderlich");
230
- }
231
- }, 10000);
232
- }
336
+ await this.startRobustRestart(resolve, reject);
233
337
  }, this.options.restartDelay);
234
338
 
235
339
  // Nicht rejecten bei Auto-Restart
@@ -241,7 +345,22 @@ export class WhatsAppClient {
241
345
  } else if (connection === "open") {
242
346
  console.log("✅ WhatsApp verbunden!");
243
347
  this.isConnected = true;
348
+ this.lastConnectionTime = Date.now();
349
+ this.reconnectAttempts = 0; // Reset counter bei erfolgreicher Verbindung
350
+
351
+ // Connection Start Time für Offline Message Ignore setzen
352
+ this.connectionStartTime = Date.now();
353
+ if (this.ignoreOfflineMessages) {
354
+ console.log(`📵 Offline Messages werden ignoriert (seit ${new Date(this.connectionStartTime).toLocaleString()})`);
355
+ }
356
+
244
357
  await closeBrowser(); // QR Browser schließen
358
+
359
+ // ROBUSTE CONNECTION FEATURES - NEU!
360
+ this.startHeartbeat(); // Heartbeat starten
361
+ this.startConnectionWatchdog(); // Connection Watchdog starten
362
+
363
+ console.log("💪 Robuste Verbindung etabliert - 24/7 bereit!");
245
364
  this.emit('connected');
246
365
 
247
366
  // 🔌 Plugins werden NICHT automatisch geladen
@@ -253,16 +372,26 @@ export class WhatsAppClient {
253
372
 
254
373
  this.socket.ev.on("creds.update", saveCreds);
255
374
 
375
+ // ROBUSTES TIMEOUT SYSTEM - NEU!
256
376
  setTimeout(() => {
257
377
  if (!this.isConnected) {
258
- console.log("⏰ Verbindungs-Timeout");
259
- reject(new Error("Connection timeout"));
378
+ console.log(`⏰ Verbindungs-Timeout nach ${this.options.connectionTimeout / 1000} Sekunden`);
379
+ console.log("🔄 Starte robuste Wiederverbindung...");
380
+
381
+ // Nicht sofort rejecten, sondern robuste Wiederverbindung versuchen
382
+ this.startRobustReconnection(resolve, reject);
260
383
  }
261
- }, 60000);
384
+ }, this.options.connectionTimeout); // Längeres Timeout (2 Minuten statt 1)
262
385
  });
263
386
  }
264
387
 
265
388
  async disconnect() {
389
+ console.log("🔌 Trenne Verbindung...");
390
+
391
+ // Cleanup timers
392
+ this.stopHeartbeat();
393
+ this.stopConnectionWatchdog();
394
+
266
395
  if (this.socket) {
267
396
  this.socket.end();
268
397
  this.socket = null;
@@ -272,6 +401,218 @@ export class WhatsAppClient {
272
401
  }
273
402
  }
274
403
 
404
+ // ===== ROBUSTE CONNECTION METHODS - NEU! =====
405
+
406
+ startHeartbeat() {
407
+ if (this.heartbeatTimer) {
408
+ clearInterval(this.heartbeatTimer);
409
+ }
410
+
411
+ this.heartbeatTimer = setInterval(async () => {
412
+ if (this.isConnected && this.socket) {
413
+ try {
414
+ const startTime = Date.now();
415
+
416
+ // Ping WhatsApp Server
417
+ await this.socket.query({
418
+ tag: 'iq',
419
+ attrs: { type: 'get', xmlns: 'w:p', id: 'ping' + Date.now() },
420
+ content: [{ tag: 'ping' }]
421
+ });
422
+
423
+ const responseTime = Date.now() - startTime;
424
+ this.connectionHealth.lastPing = Date.now();
425
+ this.connectionHealth.pingCount++;
426
+ this.connectionHealth.avgResponseTime =
427
+ (this.connectionHealth.avgResponseTime + responseTime) / 2;
428
+
429
+ // Nur bei Debug-Modus, langsamen Pings oder wenn quietHeartbeat deaktiviert ist
430
+ if (!this.options.quietHeartbeat || this.options.logLevel === 'debug' || responseTime > 5000) {
431
+ console.log(`💓 Heartbeat OK (${responseTime}ms)`);
432
+ }
433
+
434
+ } catch (error) {
435
+ this.connectionHealth.failedPings++;
436
+
437
+ // Nur bei mehreren Fehlern, Debug-Modus oder wenn quietHeartbeat deaktiviert ist
438
+ if (!this.options.quietHeartbeat || this.options.logLevel === 'debug' || this.connectionHealth.failedPings >= 2) {
439
+ console.log(`💔 Heartbeat failed (${this.connectionHealth.failedPings} failures)`);
440
+ }
441
+
442
+ // Bei 3 fehlgeschlagenen Pings Wiederverbindung
443
+ if (this.connectionHealth.failedPings >= 3) {
444
+ console.log("🚨 Verbindung instabil - starte Wiederverbindung...");
445
+ this.forceReconnect();
446
+ }
447
+ }
448
+ }
449
+ }, this.options.heartbeatInterval);
450
+ }
451
+
452
+ stopHeartbeat() {
453
+ if (this.heartbeatTimer) {
454
+ clearInterval(this.heartbeatTimer);
455
+ this.heartbeatTimer = null;
456
+ }
457
+ }
458
+
459
+ startConnectionWatchdog() {
460
+ if (this.connectionWatchdog) {
461
+ clearInterval(this.connectionWatchdog);
462
+ }
463
+
464
+ this.connectionWatchdog = setInterval(() => {
465
+ if (this.isConnected) {
466
+ const timeSinceLastPing = Date.now() - (this.connectionHealth.lastPing || 0);
467
+
468
+ // Wenn länger als 2 Minuten kein Ping, Verbindung prüfen
469
+ if (timeSinceLastPing > 120000) {
470
+ console.log("🔍 Connection Watchdog: Verbindung prüfen...");
471
+ this.checkConnectionHealth();
472
+ }
473
+ }
474
+ }, 60000); // Jede Minute prüfen
475
+ }
476
+
477
+ stopConnectionWatchdog() {
478
+ if (this.connectionWatchdog) {
479
+ clearInterval(this.connectionWatchdog);
480
+ this.connectionWatchdog = null;
481
+ }
482
+ }
483
+
484
+ async checkConnectionHealth() {
485
+ try {
486
+ if (!this.socket || !this.isConnected) {
487
+ throw new Error("Socket not connected");
488
+ }
489
+
490
+ // Test-Query senden
491
+ await this.socket.query({
492
+ tag: 'iq',
493
+ attrs: { type: 'get', xmlns: 'w:p', id: 'health' + Date.now() },
494
+ content: [{ tag: 'ping' }]
495
+ });
496
+
497
+ console.log("✅ Connection Health Check OK");
498
+ this.connectionHealth.failedPings = 0; // Reset failures
499
+
500
+ } catch (error) {
501
+ console.log("❌ Connection Health Check failed - starte Wiederverbindung...");
502
+ this.forceReconnect();
503
+ }
504
+ }
505
+
506
+ async forceReconnect() {
507
+ if (this.isReconnecting) {
508
+ console.log("🔄 Wiederverbindung bereits aktiv...");
509
+ return;
510
+ }
511
+
512
+ console.log("🔄 Erzwinge Wiederverbindung...");
513
+ this.isReconnecting = true;
514
+ this.isConnected = false;
515
+
516
+ // Socket schließen
517
+ if (this.socket) {
518
+ try {
519
+ this.socket.end();
520
+ } catch (error) {
521
+ // Ignoriere Fehler beim Schließen
522
+ }
523
+ this.socket = null;
524
+ }
525
+
526
+ // Robuste Wiederverbindung starten
527
+ setTimeout(async () => {
528
+ try {
529
+ await this.connect();
530
+ console.log("✅ Erzwungene Wiederverbindung erfolgreich!");
531
+ } catch (error) {
532
+ console.error("❌ Erzwungene Wiederverbindung fehlgeschlagen:", error.message);
533
+ this.startRobustReconnection();
534
+ } finally {
535
+ this.isReconnecting = false;
536
+ }
537
+ }, 2000);
538
+ }
539
+
540
+ async startRobustReconnection(resolve = null, reject = null) {
541
+ if (this.isReconnecting) {
542
+ console.log("🔄 Robuste Wiederverbindung bereits aktiv...");
543
+ return;
544
+ }
545
+
546
+ this.isReconnecting = true;
547
+
548
+ const attemptReconnection = async () => {
549
+ if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {
550
+ console.error(`❌ Maximale Wiederverbindungsversuche erreicht (${this.options.maxReconnectAttempts})`);
551
+ this.isReconnecting = false;
552
+ if (reject) reject(new Error('Max reconnection attempts reached'));
553
+ return;
554
+ }
555
+
556
+ this.reconnectAttempts++;
557
+
558
+ // Exponential backoff berechnen
559
+ let delay = this.options.reconnectInterval;
560
+ if (this.options.exponentialBackoff) {
561
+ delay = Math.min(
562
+ this.options.reconnectInterval * Math.pow(2, this.reconnectAttempts - 1),
563
+ this.options.maxBackoffDelay
564
+ );
565
+ }
566
+
567
+ console.log(`🔄 Wiederverbindungsversuch ${this.reconnectAttempts}/${this.options.maxReconnectAttempts} in ${delay / 1000}s...`);
568
+
569
+ setTimeout(async () => {
570
+ try {
571
+ await this.connect();
572
+ console.log(`✅ Robuste Wiederverbindung erfolgreich nach ${this.reconnectAttempts} Versuchen!`);
573
+ this.isReconnecting = false;
574
+ if (resolve) resolve(this);
575
+ } catch (error) {
576
+ console.log(`❌ Wiederverbindungsversuch ${this.reconnectAttempts} fehlgeschlagen: ${error.message}`);
577
+ attemptReconnection(); // Nächster Versuch
578
+ }
579
+ }, delay);
580
+ };
581
+
582
+ attemptReconnection();
583
+ }
584
+
585
+ async startRobustRestart(resolve = null, reject = null) {
586
+ const maxRestartAttempts = 5;
587
+ let restartAttempts = 0;
588
+
589
+ const attemptRestart = async () => {
590
+ if (restartAttempts >= maxRestartAttempts) {
591
+ console.error(`❌ Maximale Restart-Versuche erreicht (${maxRestartAttempts})`);
592
+ if (reject) reject(new Error('Max restart attempts reached'));
593
+ return;
594
+ }
595
+
596
+ restartAttempts++;
597
+ console.log(`🚀 Restart-Versuch ${restartAttempts}/${maxRestartAttempts}...`);
598
+
599
+ try {
600
+ await this.connect();
601
+ console.log(`✅ Robuster Restart erfolgreich nach ${restartAttempts} Versuchen!`);
602
+ if (resolve) resolve(this);
603
+ } catch (restartError) {
604
+ console.error(`❌ Restart-Versuch ${restartAttempts} fehlgeschlagen:`, restartError.message);
605
+
606
+ const delay = 10000 * restartAttempts; // Längere Wartezeit bei jedem Versuch
607
+ console.log(`🔄 Nächster Restart-Versuch in ${delay / 1000} Sekunden...`);
608
+
609
+ setTimeout(attemptRestart, delay);
610
+ }
611
+ };
612
+
613
+ attemptRestart();
614
+ }
615
+
275
616
  // ===== AUTO-RESTART SYSTEM =====
276
617
 
277
618
  enableAutoRestart(enabled = true, delay = 5000) {
@@ -378,6 +719,38 @@ export class WhatsAppClient {
378
719
  // Bessere Message-Validierung
379
720
  if (!msg.message || msg.key.fromMe) return;
380
721
 
722
+ // OFFLINE MESSAGE IGNORE - DEINE NEUE FUNKTION!
723
+ if (this.ignoreOfflineMessages && this.connectionStartTime) {
724
+ const messageTimestamp = msg.messageTimestamp * 1000; // Convert to milliseconds
725
+
726
+ // Ignoriere Messages die vor der Verbindung gesendet wurden
727
+ if (messageTimestamp < this.connectionStartTime) {
728
+ this.ignoredMessagesCount++;
729
+
730
+ // Nur alle 10 Messages oder bei der ersten Message loggen
731
+ if (this.ignoredMessagesCount === 1) {
732
+ console.log(`📵 Offline Messages werden ignoriert...`);
733
+ } else if (this.ignoredMessagesCount % 10 === 0) {
734
+ console.log(`📵 ${this.ignoredMessagesCount} Offline Messages ignoriert...`);
735
+ }
736
+
737
+ // Timer für finale Zusammenfassung zurücksetzen
738
+ if (this.offlineMessageTimer) {
739
+ clearTimeout(this.offlineMessageTimer);
740
+ }
741
+
742
+ // Nach 3 Sekunden ohne neue Offline Messages finale Zusammenfassung
743
+ this.offlineMessageTimer = setTimeout(() => {
744
+ if (this.ignoredMessagesCount > 0) {
745
+ console.log(`✅ Insgesamt ${this.ignoredMessagesCount} Offline Messages ignoriert`);
746
+ this.ignoredMessagesCount = 0; // Reset counter
747
+ }
748
+ }, 3000);
749
+
750
+ return;
751
+ }
752
+ }
753
+
381
754
  // Ignoriere System-Messages (protocolMessage, etc.)
382
755
  if (msg.message.protocolMessage ||
383
756
  msg.message.reactionMessage ||
@@ -630,6 +1003,16 @@ class GetAPI {
630
1003
  const participants = await this.GroupParticipants(groupId);
631
1004
  return participants.filter(p => p.admin === 'admin' || p.admin === 'superadmin');
632
1005
  }
1006
+
1007
+ // ===== PROFILE PICTURE API - NEU! =====
1008
+
1009
+ async ProfilePicture(jid) {
1010
+ try {
1011
+ return await this.client.socket.profilePictureUrl(jid, 'image');
1012
+ } catch (error) {
1013
+ return null; // Kein Profilbild verfügbar
1014
+ }
1015
+ }
633
1016
  }
634
1017
 
635
1018
  class AddAPI {
@@ -117,18 +117,43 @@ export class DeviceManager {
117
117
  }
118
118
 
119
119
  async connectAll() {
120
- console.log(`🚀 Verbinde alle ${this.devices.size} Devices...`);
120
+ console.log(`🚀 Sequenzielle Verbindung aller ${this.devices.size} Devices...`);
121
+ console.log("📱 QR-Codes werden nacheinander angezeigt!");
121
122
 
122
- const promises = Array.from(this.devices.keys()).map(deviceId =>
123
- this.connectDevice(deviceId).catch(error => {
124
- console.error(`❌ Device '${deviceId}' Verbindung fehlgeschlagen:`, error.message);
125
- return null;
126
- })
127
- );
128
-
129
- const results = await Promise.allSettled(promises);
130
- const connected = results.filter(r => r.status === 'fulfilled' && r.value).length;
123
+ const deviceIds = Array.from(this.devices.keys());
124
+ const results = [];
125
+ let connected = 0;
126
+
127
+ for (let i = 0; i < deviceIds.length; i++) {
128
+ const deviceId = deviceIds[i];
129
+
130
+ try {
131
+ console.log(`\n📱 Device ${i + 1}/${deviceIds.length}: '${deviceId}'`);
132
+ console.log("⏳ Scanne den QR-Code für dieses Device...");
133
+
134
+ await this.connectDevice(deviceId);
135
+ connected++;
136
+ results.push({ deviceId, status: 'connected' });
137
+
138
+ console.log(`✅ Device '${deviceId}' verbunden! Weiter zum nächsten...`);
139
+
140
+ // Kurze Pause zwischen Devices
141
+ if (i < deviceIds.length - 1) {
142
+ console.log("⏸️ 3 Sekunden Pause...");
143
+ await new Promise(resolve => setTimeout(resolve, 3000));
144
+ }
145
+
146
+ } catch (error) {
147
+ console.error(`❌ Device '${deviceId}' fehlgeschlagen:`, error.message);
148
+ results.push({ deviceId, status: 'failed', error: error.message });
149
+
150
+ // Weiter mit nächstem Device
151
+ console.log("➡️ Weiter mit nächstem Device...");
152
+ await new Promise(resolve => setTimeout(resolve, 2000));
153
+ }
154
+ }
131
155
 
156
+ console.log(`\n🎉 Alle Devices verarbeitet!`);
132
157
  console.log(`✅ ${connected}/${this.devices.size} Devices erfolgreich verbunden`);
133
158
 
134
159
  if (connected === 0) {