@deathnaitsa/wa-api 2.0.7 → 2.0.8
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/dist/WhatsAppClient.cjs +1 -1
- package/dist/WhatsAppClient.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/socket.js +258 -30
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
|
-
//
|
|
188
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
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
|
|
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
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
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.
|
|
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
|
-
|
|
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 '!
|
|
855
|
+
case '!meinstatus':
|
|
630
856
|
const newStatus = args.join(' ');
|
|
631
857
|
if (!newStatus) {
|
|
632
|
-
await safeSend('❌ Verwendung: !
|
|
858
|
+
await safeSend('❌ Verwendung: !meinstatus <neuer Status>');
|
|
633
859
|
break;
|
|
634
860
|
}
|
|
635
|
-
|
|
636
861
|
try {
|
|
637
|
-
|
|
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;
|