@deathnaitsa/wa-api 2.0.7 → 2.0.9

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/socket.js CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  sendText,
5
5
  sendAudio,
6
6
  sendDocument,
7
+ sendImage,
7
8
  sendLocation,
8
9
  sendContact,
9
10
  sendReaction,
@@ -39,13 +40,44 @@ import {
39
40
  countReceivedMessage
40
41
  } from '@deathnaitsa/wa-api';
41
42
 
43
+ import https from 'https';
44
+ import http from 'http';
45
+ import { URL } from 'url';
46
+
42
47
  // Start sessions
43
48
  await startSession('bot');
44
- await startSession('bot2');
45
49
 
46
50
  // Command lock to prevent duplicate execution
47
51
  const commandLocks = new Map();
48
52
 
53
+ // Helper: download a URL to a Buffer (follows redirects)
54
+ async function fetchBuffer(url) {
55
+ return new Promise((resolve, reject) => {
56
+ try {
57
+ const parsed = new URL(url);
58
+ const lib = parsed.protocol === 'https:' ? https : http;
59
+ const req = lib.get(url, (res) => {
60
+ // follow redirects
61
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
62
+ return resolve(fetchBuffer(res.headers.location));
63
+ }
64
+ if (res.statusCode !== 200) {
65
+ return reject(new Error(`Failed to fetch ${url}, status ${res.statusCode}`));
66
+ }
67
+ const chunks = [];
68
+ res.on('data', (c) => chunks.push(c));
69
+ res.on('end', () => resolve(Buffer.concat(chunks)));
70
+ });
71
+ req.on('error', reject);
72
+ req.setTimeout(15000, () => {
73
+ req.destroy(new Error('Request timeout'));
74
+ });
75
+ } catch (err) {
76
+ reject(err);
77
+ }
78
+ });
79
+ }
80
+
49
81
  async function acquireLock(key, timeoutMs = 5000) {
50
82
  const now = Date.now();
51
83
  const existing = commandLocks.get(key);
@@ -184,9 +216,23 @@ console.log(' !zuweisungen - Alle Chat-Zuweisungen anzeigen\n');
184
216
 
185
217
  // WhatsApp message handler
186
218
  onMessage(async (msg) => {
187
- // Ignore own messages
188
- if (msg.fromMe) return;
219
+ // If a raw message object is present, normalize it using client's _parseMessage
220
+ try {
221
+ if (msg && msg.raw && client && typeof client._parseMessage === 'function') {
222
+ const normalized = client._parseMessage(msg.sessionId || 'bot', msg.raw);
223
+ if (normalized) {
224
+ // preserve original raw for debugging
225
+ normalized.raw = msg.raw;
226
+ msg = normalized;
227
+ }
228
+ }
229
+ } catch (e) {
230
+ console.error('[DEBUG] _parseMessage normalization failed:', e);
231
+ }
189
232
 
233
+ // Ignore own messages
234
+ if (!msg.fromMe) return;
235
+ console.log('[DEBUG] Eingehende Nachricht:', msg);
190
236
  // Check if this message is assigned to this session
191
237
  if (!isAssignedToSession(msg.from, msg.sessionId)) {
192
238
  const assignedTo = getChatAssignment(msg.from);
@@ -200,23 +246,97 @@ onMessage(async (msg) => {
200
246
  // Mark when we received and started processing this message
201
247
  const messageProcessingStart = Date.now();
202
248
 
203
- const [cmd, ...args] = msg.message.trim().split(' ');
249
+ // Parse command allowing a space after the bang, e.g. "! me" or variations in case
250
+ const rawText = (msg.message || '').trim();
251
+ let cmd = '';
252
+ let args = [];
253
+ const cmdMatch = rawText.match(/^!\s*([^\s]+)(?:\s+([\s\S]+))?$/i);
254
+ if (cmdMatch) {
255
+ cmd = '!' + cmdMatch[1];
256
+ args = cmdMatch[2] ? cmdMatch[2].trim().split(/\s+/) : [];
257
+ } else {
258
+ // fallback to simple split
259
+ [cmd, ...args] = rawText.split(/\s+/);
260
+ }
261
+
262
+ // Normalize command for case/spacing (e.g. !Me, ! me => !me)
263
+ const cmdNormalized = cmd.replace(/\s+/g, '').toLowerCase();
204
264
  const targetSession = args[0];
205
265
 
206
- // Helper to safely send messages
207
- const safeSend = async (text) => {
266
+ // Helper to safely send messages. Accepts string or payload objects.
267
+ const safeSend = async (payload) => {
208
268
  try {
209
269
  const sessions = client.getAllSessions();
210
- if (sessions.includes(msg.sessionId)) {
211
- await sendText(msg.sessionId, msg.from, text);
270
+ if (!sessions.includes(msg.sessionId)) return;
271
+
272
+ // If payload is a simple string, send as text
273
+ if (typeof payload === 'string') {
274
+ await sendText(msg.sessionId, msg.from, payload);
275
+ return;
276
+ }
277
+
278
+ // If payload is an object with an image Buffer or URL
279
+ if (payload && typeof payload === 'object') {
280
+ // image field
281
+ if (payload.image) {
282
+ const img = payload.image;
283
+ const caption = payload.caption || '';
284
+ try {
285
+ await sendImage(msg.sessionId, msg.from, img, caption);
286
+ return;
287
+ } catch (e) {
288
+ // fallback to sendDocument using API signature: (sessionId, to, document, filename, mimetype, caption)
289
+ try {
290
+ const filename = payload.filename || 'image.jpg';
291
+ const mimetype = payload.mimetype || 'image/jpeg';
292
+ await sendDocument(msg.sessionId, msg.from, img, filename, mimetype, caption);
293
+ return;
294
+ } catch (err) {
295
+ throw err;
296
+ }
297
+ }
298
+ }
299
+
300
+ // document field
301
+ if (payload.document) {
302
+ // payload.document can be Buffer or an object { data, filename, mimetype, caption }
303
+ const doc = payload.document;
304
+ if (Buffer.isBuffer(doc)) {
305
+ await sendDocument(msg.sessionId, msg.from, doc);
306
+ } else if (doc && typeof doc === 'object') {
307
+ const data = doc.data || doc;
308
+ const filename = doc.filename || payload.filename || 'file.bin';
309
+ const mimetype = doc.mimetype || 'application/octet-stream';
310
+ const caption = doc.caption || payload.caption || '';
311
+ await sendDocument(msg.sessionId, msg.from, data, filename, mimetype, caption);
312
+ } else {
313
+ await sendDocument(msg.sessionId, msg.from, doc);
314
+ }
315
+ return;
316
+ }
317
+
318
+ // generic buffer with caption
319
+ if (Buffer.isBuffer(payload)) {
320
+ try {
321
+ await sendImage(msg.sessionId, msg.from, payload, payload.caption || '');
322
+ return;
323
+ } catch (e) {
324
+ // fallback to sendDocument with filename
325
+ await sendDocument(msg.sessionId, msg.from, payload, 'file.jpg', 'image/jpeg', payload.caption || '');
326
+ return;
327
+ }
328
+ }
212
329
  }
330
+
331
+ // Unsupported payload type
332
+ console.error('safeSend: Unsupported payload type', typeof payload);
213
333
  } catch (e) {
214
334
  console.error('Could not send message:', e.message);
215
335
  }
216
336
  };
217
337
 
218
338
  try {
219
- switch (cmd) {
339
+ switch (cmdNormalized) {
220
340
  case '!ping':
221
341
  if (targetSession === 'all') {
222
342
  // Test all sessions
@@ -581,62 +701,170 @@ onMessage(async (msg) => {
581
701
 
582
702
  case '!profilbild':
583
703
  try {
584
- // Get sender's JID (use participant if in group)
585
- const senderJid = msg.isGroup ? msg.participant : msg.from;
586
- const url = await getProfilePicture(msg.sessionId, senderJid);
587
-
588
- if (url) {
589
- await safeSend(`🖼️ *Profilbild:*\n\n${url}`);
590
- } else {
591
- await safeSend('❌ Kein Profilbild vorhanden');
704
+ const targets = new Set();
705
+
706
+ // args 'me' refers to the sender (participant in group or from in private)
707
+ if (args[0] && args[0].toLowerCase() === 'me') {
708
+ // Use msg.sender when available (explicit sender of the message),
709
+ // otherwise fall back to participant (group) or from (private)
710
+ targets.add(msg.sender || (msg.isGroup ? msg.participant : msg.from));
711
+ }
712
+
713
+ // mentions: support several possible shapes coming from parser
714
+ const mentionList = new Set();
715
+ const ctxMentioned = msg.raw?.message?.extendedTextMessage?.contextInfo?.mentionedJid;
716
+ if (Array.isArray(ctxMentioned)) for (const m of ctxMentioned) mentionList.add(m);
717
+ // older/other parsers may expose msg.mentionedJid or msg.mentions
718
+ if (msg.mentionedJid) {
719
+ if (Array.isArray(msg.mentionedJid)) for (const m of msg.mentionedJid) mentionList.add(m);
720
+ else if (typeof msg.mentionedJid === 'string' && msg.mentionedJid) mentionList.add(msg.mentionedJid);
721
+ }
722
+ if (msg.mentions) {
723
+ if (Array.isArray(msg.mentions)) for (const m of msg.mentions) mentionList.add(m);
724
+ else if (typeof msg.mentions === 'string' && msg.mentions) mentionList.add(msg.mentions);
725
+ }
726
+ // also include msg.mentions parsed earlier (single string) if present
727
+ if (msg.mentions && typeof msg.mentions === 'string' && msg.mentions.includes('@')) mentionList.add(msg.mentions);
728
+ for (const m of mentionList) targets.add(m);
729
+
730
+ // quoted participant
731
+ if (msg.quoted && msg.quoted.participant) targets.add(msg.quoted.participant);
732
+
733
+ // if an explicit phone/JID was provided as arg (e.g. !profilbild 49123...)
734
+ if (args && args.length && !args[0].toLowerCase().startsWith('me')) {
735
+ const maybe = args[0].replace(/[^0-9@.]/g, '');
736
+ if (maybe.includes('@')) targets.add(maybe);
737
+ else if (maybe) targets.add(`${maybe}@s.whatsapp.net`);
738
+ }
739
+
740
+ if (targets.size === 0) {
741
+ targets.add(msg.isGroup ? msg.participant : msg.from);
742
+ }
743
+
744
+ for (const t of targets) {
745
+ try {
746
+ const mentionJid = (msg.isGroup && t === msg.from) ? msg.participant : t;
747
+ const shortName = mentionJid.split('@')[0];
748
+
749
+ const pic = await getProfilePicture(msg.sessionId, t);
750
+ let buf = null;
751
+
752
+ if (!pic) {
753
+ // no profile picture
754
+ await client.sendMessage(msg.sessionId, msg.from, { text: `❌ Kein Profilbild für ${shortName} gefunden` });
755
+ continue;
756
+ }
757
+
758
+ if (Buffer.isBuffer(pic)) buf = pic;
759
+ else if (typeof pic === 'string') {
760
+ try {
761
+ buf = await fetchBuffer(pic);
762
+ } catch (e) {
763
+ console.error('[DEBUG] Fehler beim Herunterladen des Profilbildes:', e.message);
764
+ }
765
+ }
766
+
767
+ if (buf) {
768
+ const caption = `🖼️ Profilbild von ${shortName}`;
769
+ try {
770
+ await sendImage(msg.sessionId, msg.from, buf, caption);
771
+ } catch (e) {
772
+ console.error('[DEBUG] sendImage failed:', e.message);
773
+ // fallback to sendDocument
774
+ try {
775
+ await sendDocument(msg.sessionId, msg.from, buf, `${shortName}.jpg`, 'image/jpeg', caption);
776
+ } catch (err) {
777
+ console.error('[DEBUG] sendDocument fallback failed:', err.message);
778
+ }
779
+ }
780
+
781
+ // send a tagged text so the user is mentioned (sendText doesn't support mentions)
782
+ try {
783
+ await client.sendMessage(msg.sessionId, msg.from, { text: `🖼️ Profilbild von @${shortName}`, mentions: [mentionJid] });
784
+ } catch (_) {
785
+ try { await sendText(msg.sessionId, msg.from, `🖼️ Profilbild von ${shortName}`); } catch(_){}
786
+ }
787
+ } else if (typeof pic === 'string') {
788
+ // couldn't download buffer, send link and mention
789
+ try {
790
+ await client.sendMessage(msg.sessionId, msg.from, { text: `🖼️ Profilbild von @${shortName}:\n${pic}`, mentions: [mentionJid] });
791
+ } catch (_) {
792
+ await sendText(msg.sessionId, msg.from, `🖼️ Profilbild von ${shortName}:\n${pic}`);
793
+ }
794
+ }
795
+ } catch (e) {
796
+ console.error('[DEBUG] Fehler beim Abrufen Profilbild:', e);
797
+ try { await sendText(msg.sessionId, msg.from, `❌ Fehler beim Abrufen von ${t.split('@')[0]}: ${e.message}`); } catch(_){}
798
+ }
592
799
  }
593
800
  } catch (e) {
594
- await safeSend(`❌ Fehler: ${e.message}`);
801
+ try { await sendText(msg.sessionId, msg.from, `❌ Fehler: ${e.message}`); } catch(_){}
595
802
  }
596
803
  break;
597
804
 
598
805
  case '!status':
599
806
  try {
600
807
  const senderJid = msg.isGroup ? msg.participant : msg.from;
601
- const status = await getStatus(msg.sessionId, senderJid);
602
-
603
- if (status?.status) {
604
- await safeSend(`💬 *Status:*\n\n${status.status}`);
808
+ console.log(`[DEBUG] getStatus aufgerufen für Session: ${msg.sessionId}, JID: ${senderJid}`);
809
+ let status = await getStatus(msg.sessionId, senderJid);
810
+ console.log('[DEBUG] getStatus Rückgabe:', status);
811
+
812
+ // Manche Implementierungen liefern ein Array von Status-Objekten
813
+ if (Array.isArray(status) && status.length > 0) {
814
+ // Nimm das erste Element (neuester Status)
815
+ status = status[0];
816
+ }
817
+
818
+ // Falls das Objekt innerhalb eines Wrappers das Feld `status` hat
819
+ const statusText = status?.status?.status || status?.status || (typeof status === 'string' ? status : null);
820
+
821
+ if (statusText) {
822
+ await safeSend(`💬 *Status:*\n\n${statusText}`);
605
823
  } else {
606
824
  await safeSend('❌ Kein Status vorhanden');
607
825
  }
608
826
  } catch (e) {
827
+ console.error('[DEBUG] Fehler bei getStatus:', e);
609
828
  await safeSend(`❌ Fehler: ${e.message}`);
610
829
  }
611
830
  break;
612
831
 
613
832
  case '!kontakt':
614
833
  try {
615
- const senderJid = msg.isGroup ? msg.participant : msg.from;
834
+ const senderJid = msg.isGroup ? msg.mentions : msg.mentions
835
+ console.log(`[DEBUG] getContact aufgerufen für Session: ${msg.sessionId}, JID: ${senderJid}`);
616
836
  const contact = await getContact(msg.sessionId, senderJid);
617
-
618
- let contactInfo = `👤 *Kontaktinfo:*\n\n`;
837
+
838
+ // Guard: getContact may return undefined/null
839
+ if (!contact || !contact.jid) {
840
+ console.error('[DEBUG] getContact returned empty for', senderJid, contact);
841
+ await safeSend(`❌ Kontakt nicht gefunden für ${senderJid.split('@')[0] || senderJid}`);
842
+ break;
843
+ }
844
+
845
+ let contactInfo = `👤 *Kontaktinfo:\n\n`;
619
846
  contactInfo += `JID: ${contact.jid}\n`;
620
847
  contactInfo += `Nummer: ${contact.jid.split('@')[0]}\n`;
621
848
  contactInfo += `Exists: ${contact.exists ? 'Ja' : 'Nein'}\n`;
622
-
623
849
  await safeSend(contactInfo);
624
850
  } catch (e) {
625
851
  await safeSend(`❌ Fehler: ${e.message}`);
626
852
  }
627
853
  break;
628
854
 
629
- case '!meinestatus':
855
+ case '!meinstatus':
630
856
  const newStatus = args.join(' ');
631
857
  if (!newStatus) {
632
- await safeSend('❌ Verwendung: !meinestatus <neuer Status>');
858
+ await safeSend('❌ Verwendung: !meinstatus <neuer Status>');
633
859
  break;
634
860
  }
635
-
636
861
  try {
637
- await updateProfileStatus(msg.sessionId, newStatus);
862
+ console.log(`[DEBUG] updateProfileStatus aufgerufen für Session: ${msg.sessionId}, Status: ${newStatus}`);
863
+ const result = await updateProfileStatus(msg.sessionId, newStatus);
864
+ console.log(`[DEBUG] updateProfileStatus Rückgabe:`, result);
638
865
  await safeSend(`✅ Status geändert zu: "${newStatus}"`);
639
866
  } catch (e) {
867
+ console.error('[DEBUG] Fehler bei updateProfileStatus:', e);
640
868
  await safeSend(`❌ Fehler: ${e.message}`);
641
869
  }
642
870
  break;