waengine 1.9.8 → 2.0.0
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/bin/waengine.js +7 -0
- package/package.json +8 -2
- package/src/auto-session-menu.js +77 -0
- package/src/device-detector.js +376 -0
- package/src/index.js +5 -0
- package/src/init.js +22 -0
- package/src/session-launcher.js +96 -0
- package/src/session-menu.js +462 -0
package/bin/waengine.js
ADDED
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "waengine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
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",
|
|
7
|
+
"bin": {
|
|
8
|
+
"waengine": "./bin/waengine.js",
|
|
9
|
+
"waengine-menu": "./bin/waengine.js"
|
|
10
|
+
},
|
|
7
11
|
"scripts": {
|
|
8
|
-
"start": "node
|
|
12
|
+
"start": "node start.js",
|
|
13
|
+
"menu": "node start.js",
|
|
9
14
|
"test": "node test.js",
|
|
10
15
|
"example:basic": "node examples/easy-bot-examples.js einfach",
|
|
11
16
|
"example:multi": "node examples/multi-device-example.js",
|
|
@@ -65,6 +70,7 @@
|
|
|
65
70
|
"dependencies": {
|
|
66
71
|
"@whiskeysockets/baileys": "^7.0.0-rc.9",
|
|
67
72
|
"axios": "^1.13.4",
|
|
73
|
+
"chalk": "^5.3.0",
|
|
68
74
|
"node-cron": "^3.0.3",
|
|
69
75
|
"pino": "^8.0.0",
|
|
70
76
|
"qrcode": "^1.5.4",
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Auto-Session-Menu - Wird automatisch beim Import der Library gestartet
|
|
2
|
+
import { SessionMenu } from './session-menu.js';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
// Globale Variable um zu tracken ob das Menü bereits gezeigt wurde
|
|
7
|
+
let menuShown = false;
|
|
8
|
+
let autoMenuEnabled = true;
|
|
9
|
+
|
|
10
|
+
// Prüfe ob User das Auto-Menu deaktiviert hat
|
|
11
|
+
const configPath = './.waengine-config.json';
|
|
12
|
+
if (fs.existsSync(configPath)) {
|
|
13
|
+
try {
|
|
14
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
15
|
+
if (config.disableAutoSessionMenu === true) {
|
|
16
|
+
autoMenuEnabled = false;
|
|
17
|
+
}
|
|
18
|
+
} catch (e) {
|
|
19
|
+
// Ignore config errors
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Zeige das Session-Menu automatisch beim ersten Import
|
|
24
|
+
export async function showAutoSessionMenu() {
|
|
25
|
+
if (menuShown || !autoMenuEnabled) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
menuShown = true;
|
|
30
|
+
|
|
31
|
+
const menu = new SessionMenu();
|
|
32
|
+
|
|
33
|
+
// Wenn keine Sessions existieren, zeige das Menü
|
|
34
|
+
if (menu.sessions.length === 0) {
|
|
35
|
+
console.log('\n🎉 Willkommen bei WAEngine!\n');
|
|
36
|
+
console.log('Es wurden noch keine Sessions gefunden.');
|
|
37
|
+
console.log('Lass uns eine erstellen...\n');
|
|
38
|
+
|
|
39
|
+
await menu.start();
|
|
40
|
+
return menu.getActiveSessions();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Wenn Sessions existieren, frage ob sie gestartet werden sollen
|
|
44
|
+
console.log('\n📱 WAEngine Session Manager\n');
|
|
45
|
+
console.log(`Gefundene Sessions: ${menu.sessions.length}\n`);
|
|
46
|
+
|
|
47
|
+
const readline = require('readline').createInterface({
|
|
48
|
+
input: process.stdin,
|
|
49
|
+
output: process.stdout
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const answer = await new Promise(resolve => {
|
|
53
|
+
readline.question('Möchtest du das Session-Menü öffnen? (j/n): ', resolve);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
readline.close();
|
|
57
|
+
|
|
58
|
+
if (answer.toLowerCase() === 'j' || answer.toLowerCase() === 'y') {
|
|
59
|
+
await menu.start();
|
|
60
|
+
return menu.getActiveSessions();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Funktion um das Auto-Menu zu deaktivieren
|
|
67
|
+
export function disableAutoSessionMenu() {
|
|
68
|
+
const config = {
|
|
69
|
+
disableAutoSessionMenu: true
|
|
70
|
+
};
|
|
71
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
72
|
+
console.log('✅ Auto-Session-Menu deaktiviert');
|
|
73
|
+
console.log(' Zum Reaktivieren: Lösche .waengine-config.json');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Export für manuelle Nutzung
|
|
77
|
+
export { SessionMenu };
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WhatsApp Device Detector
|
|
3
|
+
* Erkennt Gerätetypen anhand der Message ID
|
|
4
|
+
*
|
|
5
|
+
* Message ID Struktur:
|
|
6
|
+
* - WhatsApp Web: 3EB0XXXXXXXXXXXXXXXX (beginnt oft mit 3EB0)
|
|
7
|
+
* - Android: Meist 20 Zeichen, alphanumerisch
|
|
8
|
+
* - iPhone: Meist mit Bindestrichen, z.B. XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
|
9
|
+
* - Desktop: Ähnlich wie Web, aber andere Präfixe
|
|
10
|
+
* - Business: Spezielle Präfixe wie BAE5
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export class DeviceDetector {
|
|
14
|
+
constructor() {
|
|
15
|
+
// Pattern-Definitionen für verschiedene Gerätetypen
|
|
16
|
+
this.patterns = {
|
|
17
|
+
// WhatsApp Web - typische Präfixe
|
|
18
|
+
web: {
|
|
19
|
+
prefixes: ['3EB0', '3AA0', '3A', '3E'],
|
|
20
|
+
pattern: /^3[EA][AB0-9]{2}[A-F0-9]{16,20}$/i,
|
|
21
|
+
confidence: 0.85
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// iPhone/iOS - oft mit Bindestrichen oder spezifischen Mustern
|
|
25
|
+
iphone: {
|
|
26
|
+
prefixes: ['BAE5', 'ABCD'],
|
|
27
|
+
pattern: /^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}$/i,
|
|
28
|
+
alternativePattern: /^[A-F0-9]{32}$/i,
|
|
29
|
+
confidence: 0.80
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// Android - meist alphanumerisch ohne Bindestriche
|
|
33
|
+
android: {
|
|
34
|
+
pattern: /^[A-F0-9]{20,32}$/i,
|
|
35
|
+
excludePrefixes: ['3EB0', '3AA0', 'BAE5'],
|
|
36
|
+
confidence: 0.75
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
// WhatsApp Desktop (Windows/Mac)
|
|
40
|
+
desktop: {
|
|
41
|
+
prefixes: ['3EB1', '3EB2', '3AA1'],
|
|
42
|
+
pattern: /^3[EA][AB][12][A-F0-9]{16,20}$/i,
|
|
43
|
+
confidence: 0.85
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// WhatsApp Business
|
|
47
|
+
business: {
|
|
48
|
+
prefixes: ['BAE5', 'BAE6'],
|
|
49
|
+
pattern: /^BAE[56][A-F0-9]{16,20}$/i,
|
|
50
|
+
confidence: 0.90
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Statistiken
|
|
55
|
+
this.stats = {
|
|
56
|
+
total: 0,
|
|
57
|
+
detected: {},
|
|
58
|
+
unknown: 0
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Hauptfunktion: Erkennt Gerätetyp anhand der Message ID
|
|
64
|
+
* @param {string} messageId - Die WhatsApp Message ID
|
|
65
|
+
* @returns {Object} Erkennungsergebnis mit Gerätetyp und Confidence
|
|
66
|
+
*/
|
|
67
|
+
detectDevice(messageId) {
|
|
68
|
+
if (!messageId || typeof messageId !== 'string') {
|
|
69
|
+
return this.createResult('unknown', 0, 'Ungültige Message ID');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this.stats.total++;
|
|
73
|
+
|
|
74
|
+
// Normalisiere Message ID (Großbuchstaben, Leerzeichen entfernen)
|
|
75
|
+
const normalizedId = messageId.trim().toUpperCase();
|
|
76
|
+
|
|
77
|
+
// Prüfe jeden Gerätetyp
|
|
78
|
+
const results = [];
|
|
79
|
+
|
|
80
|
+
// 1. Business Check (höchste Priorität)
|
|
81
|
+
const businessResult = this.checkBusiness(normalizedId);
|
|
82
|
+
if (businessResult.confidence > 0.7) {
|
|
83
|
+
return this.recordResult(businessResult);
|
|
84
|
+
}
|
|
85
|
+
results.push(businessResult);
|
|
86
|
+
|
|
87
|
+
// 2. iPhone Check
|
|
88
|
+
const iphoneResult = this.checkIPhone(normalizedId);
|
|
89
|
+
if (iphoneResult.confidence > 0.7) {
|
|
90
|
+
return this.recordResult(iphoneResult);
|
|
91
|
+
}
|
|
92
|
+
results.push(iphoneResult);
|
|
93
|
+
|
|
94
|
+
// 3. Desktop Check
|
|
95
|
+
const desktopResult = this.checkDesktop(normalizedId);
|
|
96
|
+
if (desktopResult.confidence > 0.7) {
|
|
97
|
+
return this.recordResult(desktopResult);
|
|
98
|
+
}
|
|
99
|
+
results.push(desktopResult);
|
|
100
|
+
|
|
101
|
+
// 4. Web Check
|
|
102
|
+
const webResult = this.checkWeb(normalizedId);
|
|
103
|
+
if (webResult.confidence > 0.7) {
|
|
104
|
+
return this.recordResult(webResult);
|
|
105
|
+
}
|
|
106
|
+
results.push(webResult);
|
|
107
|
+
|
|
108
|
+
// 5. Android Check (niedrigste Priorität, da am unspezifischsten)
|
|
109
|
+
const androidResult = this.checkAndroid(normalizedId);
|
|
110
|
+
results.push(androidResult);
|
|
111
|
+
|
|
112
|
+
// Bestes Ergebnis zurückgeben
|
|
113
|
+
const bestResult = results.reduce((best, current) =>
|
|
114
|
+
current.confidence > best.confidence ? current : best
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return this.recordResult(bestResult);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Prüft auf WhatsApp Business
|
|
122
|
+
*/
|
|
123
|
+
checkBusiness(messageId) {
|
|
124
|
+
const { prefixes, pattern, confidence } = this.patterns.business;
|
|
125
|
+
|
|
126
|
+
// Prefix-Check
|
|
127
|
+
const hasPrefix = prefixes.some(prefix => messageId.startsWith(prefix));
|
|
128
|
+
if (hasPrefix && pattern.test(messageId)) {
|
|
129
|
+
return this.createResult('business', confidence, 'Business Prefix erkannt');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return this.createResult('business', 0, 'Kein Business Pattern');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Prüft auf iPhone/iOS
|
|
137
|
+
*/
|
|
138
|
+
checkIPhone(messageId) {
|
|
139
|
+
const { prefixes, pattern, alternativePattern, confidence } = this.patterns.iphone;
|
|
140
|
+
|
|
141
|
+
// UUID-Format (mit Bindestrichen)
|
|
142
|
+
if (pattern.test(messageId)) {
|
|
143
|
+
return this.createResult('iphone', confidence, 'UUID-Format erkannt');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Alternative: 32 Zeichen Hex ohne Bindestriche
|
|
147
|
+
if (alternativePattern.test(messageId)) {
|
|
148
|
+
// Zusätzliche Heuristik: iPhone IDs haben oft bestimmte Charakteristiken
|
|
149
|
+
const hasIPhoneCharacteristics = this.hasIPhoneCharacteristics(messageId);
|
|
150
|
+
if (hasIPhoneCharacteristics) {
|
|
151
|
+
return this.createResult('iphone', confidence * 0.9, 'iPhone Charakteristiken erkannt');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Prefix-Check
|
|
156
|
+
const hasPrefix = prefixes.some(prefix => messageId.startsWith(prefix));
|
|
157
|
+
if (hasPrefix) {
|
|
158
|
+
return this.createResult('iphone', confidence * 0.8, 'iPhone Prefix erkannt');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return this.createResult('iphone', 0, 'Kein iPhone Pattern');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Prüft auf WhatsApp Desktop
|
|
166
|
+
*/
|
|
167
|
+
checkDesktop(messageId) {
|
|
168
|
+
const { prefixes, pattern, confidence } = this.patterns.desktop;
|
|
169
|
+
|
|
170
|
+
// Prefix-Check
|
|
171
|
+
const hasPrefix = prefixes.some(prefix => messageId.startsWith(prefix));
|
|
172
|
+
if (hasPrefix && pattern.test(messageId)) {
|
|
173
|
+
return this.createResult('desktop', confidence, 'Desktop Prefix erkannt');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return this.createResult('desktop', 0, 'Kein Desktop Pattern');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Prüft auf WhatsApp Web
|
|
181
|
+
*/
|
|
182
|
+
checkWeb(messageId) {
|
|
183
|
+
const { prefixes, pattern, confidence } = this.patterns.web;
|
|
184
|
+
|
|
185
|
+
// Prefix-Check
|
|
186
|
+
const hasPrefix = prefixes.some(prefix => messageId.startsWith(prefix));
|
|
187
|
+
if (hasPrefix && pattern.test(messageId)) {
|
|
188
|
+
return this.createResult('web', confidence, 'Web Prefix erkannt');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return this.createResult('web', 0, 'Kein Web Pattern');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Prüft auf Android
|
|
196
|
+
*/
|
|
197
|
+
checkAndroid(messageId) {
|
|
198
|
+
const { pattern, excludePrefixes, confidence } = this.patterns.android;
|
|
199
|
+
|
|
200
|
+
// Ausschluss-Check: Nicht wenn andere spezifische Präfixe
|
|
201
|
+
const hasExcludedPrefix = excludePrefixes.some(prefix =>
|
|
202
|
+
messageId.startsWith(prefix)
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
if (hasExcludedPrefix) {
|
|
206
|
+
return this.createResult('android', 0, 'Ausgeschlossener Prefix');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Pattern-Check
|
|
210
|
+
if (pattern.test(messageId)) {
|
|
211
|
+
// Android ist der Fallback, daher niedrigere Confidence
|
|
212
|
+
return this.createResult('android', confidence, 'Android Pattern erkannt');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return this.createResult('android', 0, 'Kein Android Pattern');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Heuristische Prüfung auf iPhone-Charakteristiken
|
|
220
|
+
*/
|
|
221
|
+
hasIPhoneCharacteristics(messageId) {
|
|
222
|
+
// iPhone IDs haben oft eine gleichmäßigere Verteilung von Zeichen
|
|
223
|
+
const charDistribution = this.analyzeCharDistribution(messageId);
|
|
224
|
+
|
|
225
|
+
// Prüfe auf gleichmäßige Verteilung (iPhone typisch)
|
|
226
|
+
const isBalanced = charDistribution.variance < 0.3;
|
|
227
|
+
|
|
228
|
+
return isBalanced;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Analysiert die Zeichenverteilung
|
|
233
|
+
*/
|
|
234
|
+
analyzeCharDistribution(str) {
|
|
235
|
+
const counts = {};
|
|
236
|
+
for (const char of str) {
|
|
237
|
+
counts[char] = (counts[char] || 0) + 1;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const values = Object.values(counts);
|
|
241
|
+
const mean = values.reduce((a, b) => a + b, 0) / values.length;
|
|
242
|
+
const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length;
|
|
243
|
+
|
|
244
|
+
return { mean, variance: variance / mean };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Erstellt ein Erkennungsergebnis
|
|
249
|
+
*/
|
|
250
|
+
createResult(deviceType, confidence, reason) {
|
|
251
|
+
return {
|
|
252
|
+
deviceType,
|
|
253
|
+
confidence: Math.round(confidence * 100) / 100,
|
|
254
|
+
reason,
|
|
255
|
+
timestamp: Date.now()
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Zeichnet Ergebnis in Statistiken auf
|
|
261
|
+
*/
|
|
262
|
+
recordResult(result) {
|
|
263
|
+
if (result.confidence > 0.5) {
|
|
264
|
+
this.stats.detected[result.deviceType] =
|
|
265
|
+
(this.stats.detected[result.deviceType] || 0) + 1;
|
|
266
|
+
} else {
|
|
267
|
+
this.stats.unknown++;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Batch-Erkennung für mehrere Message IDs
|
|
275
|
+
*/
|
|
276
|
+
detectBatch(messageIds) {
|
|
277
|
+
return messageIds.map(id => ({
|
|
278
|
+
messageId: id,
|
|
279
|
+
...this.detectDevice(id)
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Erweiterte Analyse mit zusätzlichen Informationen
|
|
285
|
+
*/
|
|
286
|
+
analyzeMessage(message) {
|
|
287
|
+
const messageId = message.key?.id || message.id;
|
|
288
|
+
const detection = this.detectDevice(messageId);
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
messageId,
|
|
292
|
+
...detection,
|
|
293
|
+
metadata: {
|
|
294
|
+
length: messageId?.length || 0,
|
|
295
|
+
hasHyphens: messageId?.includes('-') || false,
|
|
296
|
+
prefix: messageId?.substring(0, 4) || '',
|
|
297
|
+
timestamp: message.messageTimestamp || message.timestamp,
|
|
298
|
+
from: message.key?.remoteJid || message.from,
|
|
299
|
+
isGroup: (message.key?.remoteJid || message.from)?.includes('@g.us')
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Gibt Statistiken zurück
|
|
306
|
+
*/
|
|
307
|
+
getStats() {
|
|
308
|
+
return {
|
|
309
|
+
...this.stats,
|
|
310
|
+
detectionRate: this.stats.total > 0
|
|
311
|
+
? Math.round(((this.stats.total - this.stats.unknown) / this.stats.total) * 100)
|
|
312
|
+
: 0
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Setzt Statistiken zurück
|
|
318
|
+
*/
|
|
319
|
+
resetStats() {
|
|
320
|
+
this.stats = {
|
|
321
|
+
total: 0,
|
|
322
|
+
detected: {},
|
|
323
|
+
unknown: 0
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Gibt eine lesbare Beschreibung des Gerätetyps zurück
|
|
329
|
+
*/
|
|
330
|
+
getDeviceDescription(deviceType) {
|
|
331
|
+
const descriptions = {
|
|
332
|
+
web: '🌐 WhatsApp Web',
|
|
333
|
+
iphone: '📱 iPhone/iOS',
|
|
334
|
+
android: '🤖 Android',
|
|
335
|
+
desktop: '💻 WhatsApp Desktop',
|
|
336
|
+
business: '💼 WhatsApp Business',
|
|
337
|
+
unknown: '❓ Unbekannt'
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
return descriptions[deviceType] || descriptions.unknown;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Formatiert ein Erkennungsergebnis für die Ausgabe
|
|
345
|
+
*/
|
|
346
|
+
formatResult(result) {
|
|
347
|
+
const description = this.getDeviceDescription(result.deviceType);
|
|
348
|
+
const confidenceBar = '█'.repeat(Math.round(result.confidence * 10));
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
device: description,
|
|
352
|
+
confidence: `${Math.round(result.confidence * 100)}%`,
|
|
353
|
+
confidenceBar,
|
|
354
|
+
reason: result.reason,
|
|
355
|
+
reliable: result.confidence >= 0.7
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Singleton-Instanz für einfache Verwendung
|
|
361
|
+
export const deviceDetector = new DeviceDetector();
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Convenience-Funktionen für direkten Import
|
|
365
|
+
*/
|
|
366
|
+
export function detectDevice(messageId) {
|
|
367
|
+
return deviceDetector.detectDevice(messageId);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function detectDeviceFromMessage(message) {
|
|
371
|
+
return deviceDetector.analyzeMessage(message);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function getDeviceStats() {
|
|
375
|
+
return deviceDetector.getStats();
|
|
376
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { WhatsAppClient } from "./client.js";
|
|
2
2
|
export { MultiWhatsAppClient } from "./multi-client.js";
|
|
3
3
|
export { DeviceManager } from "./device-manager.js";
|
|
4
|
+
export { DeviceDetector, deviceDetector, detectDevice, detectDeviceFromMessage, getDeviceStats } from "./device-detector.js";
|
|
4
5
|
export { PrefixManager } from "./prefix-manager.js";
|
|
5
6
|
export { WAStorage, createStorage, getStorage, write, read, del } from "./storage.js";
|
|
6
7
|
export { AIIntegration } from "./ai-integration.js";
|
|
@@ -48,3 +49,7 @@ export { GamingManager } from "./gaming-manager.js";
|
|
|
48
49
|
export { DatabaseManager } from "./database-manager.js";
|
|
49
50
|
export { ABTestingManager } from "./ab-testing.js";
|
|
50
51
|
export { ReportingManager } from "./reporting-manager.js";
|
|
52
|
+
|
|
53
|
+
// ===== SESSION MANAGEMENT SYSTEM - NEU! =====
|
|
54
|
+
export { SessionMenu } from "./session-menu.js";
|
|
55
|
+
export { SessionLauncher, launchSessionMenu, quickStart } from "./session-launcher.js";
|
package/src/init.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Auto-Init für WAEngine - Startet Session-Menu automatisch
|
|
2
|
+
import { SessionMenu } from './session-menu.js';
|
|
3
|
+
|
|
4
|
+
// Diese Funktion wird automatisch beim Import ausgeführt
|
|
5
|
+
let initialized = false;
|
|
6
|
+
|
|
7
|
+
export async function initWAEngine() {
|
|
8
|
+
if (initialized) return;
|
|
9
|
+
initialized = true;
|
|
10
|
+
|
|
11
|
+
const menu = new SessionMenu();
|
|
12
|
+
|
|
13
|
+
// Starte das Menü automatisch
|
|
14
|
+
await menu.start();
|
|
15
|
+
|
|
16
|
+
return menu.getActiveSessions();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Automatischer Start beim Import (nur wenn als Hauptmodul geladen)
|
|
20
|
+
if (import.meta.url === `file:///${process.argv[1].replace(/\\/g, '/')}`) {
|
|
21
|
+
initWAEngine();
|
|
22
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { SessionMenu } from './session-menu.js';
|
|
2
|
+
import { WhatsAppClient } from './client.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Automatischer Session-Launcher für die Library
|
|
6
|
+
* Wird automatisch beim Import aufgerufen
|
|
7
|
+
*/
|
|
8
|
+
export class SessionLauncher {
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.autoStart = options.autoStart !== false; // Standard: true
|
|
11
|
+
this.baseAuthDir = options.baseAuthDir || './sessions';
|
|
12
|
+
this.sessionMenu = new SessionMenu(this.baseAuthDir);
|
|
13
|
+
this.clients = new Map();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Startet das interaktive Session-Menü
|
|
18
|
+
*/
|
|
19
|
+
async startInteractive() {
|
|
20
|
+
await this.sessionMenu.start();
|
|
21
|
+
return this.sessionMenu.getActiveSessions();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Startet eine spezifische Session ohne Menü
|
|
26
|
+
*/
|
|
27
|
+
async startSession(sessionName) {
|
|
28
|
+
const sock = await this.sessionMenu.startSession(sessionName);
|
|
29
|
+
if (sock) {
|
|
30
|
+
// Erstelle WhatsAppClient-Wrapper
|
|
31
|
+
const client = new WhatsAppClient({
|
|
32
|
+
authDir: this.sessionMenu.sessions.find(s => s.name === sessionName)?.authDir,
|
|
33
|
+
socket: sock
|
|
34
|
+
});
|
|
35
|
+
this.clients.set(sessionName, client);
|
|
36
|
+
return client;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Startet alle Sessions ohne Menü
|
|
43
|
+
*/
|
|
44
|
+
async startAllSessions() {
|
|
45
|
+
const sessions = this.sessionMenu.sessions;
|
|
46
|
+
const clients = [];
|
|
47
|
+
|
|
48
|
+
for (const session of sessions) {
|
|
49
|
+
const client = await this.startSession(session.name);
|
|
50
|
+
if (client) {
|
|
51
|
+
clients.push(client);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return clients;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Gibt alle aktiven Clients zurück
|
|
60
|
+
*/
|
|
61
|
+
getClients() {
|
|
62
|
+
return Array.from(this.clients.values());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Gibt einen spezifischen Client zurück
|
|
67
|
+
*/
|
|
68
|
+
getClient(sessionName) {
|
|
69
|
+
return this.clients.get(sessionName);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Einfache Funktion zum Starten des Session-Menüs
|
|
75
|
+
*/
|
|
76
|
+
export async function launchSessionMenu(options = {}) {
|
|
77
|
+
const launcher = new SessionLauncher(options);
|
|
78
|
+
return await launcher.startInteractive();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Schnellstart-Funktion für Single-Session
|
|
83
|
+
*/
|
|
84
|
+
export async function quickStart(sessionName = 'default', options = {}) {
|
|
85
|
+
const launcher = new SessionLauncher(options);
|
|
86
|
+
|
|
87
|
+
// Prüfe ob Session existiert
|
|
88
|
+
const existingSession = launcher.sessionMenu.sessions.find(s => s.name === sessionName);
|
|
89
|
+
|
|
90
|
+
if (!existingSession) {
|
|
91
|
+
console.log(`⚠️ Session "${sessionName}" nicht gefunden. Starte interaktives Menü...`);
|
|
92
|
+
return await launcher.startInteractive();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return await launcher.startSession(sessionName);
|
|
96
|
+
}
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import readline from 'readline';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { makeWASocket, useMultiFileAuthState, fetchLatestBaileysVersion, DisconnectReason } from '@whiskeysockets/baileys';
|
|
5
|
+
import pino from 'pino';
|
|
6
|
+
import qrcode from 'qrcode-terminal';
|
|
7
|
+
|
|
8
|
+
// ANSI Color Codes (ohne externe Dependencies)
|
|
9
|
+
const c = {
|
|
10
|
+
cyan: (text) => `\x1b[36m${text}\x1b[0m`,
|
|
11
|
+
yellow: (text) => `\x1b[33m${text}\x1b[0m`,
|
|
12
|
+
green: (text) => `\x1b[32m${text}\x1b[0m`,
|
|
13
|
+
red: (text) => `\x1b[31m${text}\x1b[0m`,
|
|
14
|
+
white: (text) => `\x1b[37m${text}\x1b[0m`,
|
|
15
|
+
gray: (text) => `\x1b[90m${text}\x1b[0m`,
|
|
16
|
+
bold: (text) => `\x1b[1m${text}\x1b[0m`
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export class SessionMenu {
|
|
20
|
+
constructor(baseAuthDir = './sessions') {
|
|
21
|
+
this.baseAuthDir = baseAuthDir;
|
|
22
|
+
this.sessionsConfigPath = path.join(baseAuthDir, 'sessions.json');
|
|
23
|
+
this.activeSessions = new Map();
|
|
24
|
+
this.rl = null;
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(baseAuthDir)) {
|
|
27
|
+
fs.mkdirSync(baseAuthDir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.loadSessionsConfig();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
loadSessionsConfig() {
|
|
34
|
+
if (fs.existsSync(this.sessionsConfigPath)) {
|
|
35
|
+
const data = fs.readFileSync(this.sessionsConfigPath, 'utf-8');
|
|
36
|
+
this.sessions = JSON.parse(data);
|
|
37
|
+
} else {
|
|
38
|
+
this.sessions = [];
|
|
39
|
+
this.saveSessionsConfig();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
saveSessionsConfig() {
|
|
44
|
+
fs.writeFileSync(this.sessionsConfigPath, JSON.stringify(this.sessions, null, 2));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
clearScreen() {
|
|
48
|
+
console.clear();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
showBanner() {
|
|
52
|
+
console.log(c.cyan('╔════════════════════════════════════════╗'));
|
|
53
|
+
console.log(c.cyan('║ WhatsApp Bot Session Manager ║'));
|
|
54
|
+
console.log(c.cyan('╚════════════════════════════════════════╝\n'));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
showMainMenu() {
|
|
58
|
+
this.clearScreen();
|
|
59
|
+
this.showBanner();
|
|
60
|
+
|
|
61
|
+
console.log(c.yellow('📋 Hauptmenü:\n'));
|
|
62
|
+
console.log(c.white(' 1️⃣ Neue Session erstellen'));
|
|
63
|
+
console.log(c.white(' 2️⃣ Alle Sessions starten'));
|
|
64
|
+
console.log(c.white(' 3️⃣ Einzelne Session starten'));
|
|
65
|
+
console.log(c.white(' 4️⃣ Sessions verwalten'));
|
|
66
|
+
console.log(c.white(' 5️⃣ Beenden\n'));
|
|
67
|
+
|
|
68
|
+
if (this.sessions.length > 0) {
|
|
69
|
+
console.log(c.gray('📊 Verfügbare Sessions:'));
|
|
70
|
+
this.sessions.forEach((session, index) => {
|
|
71
|
+
const status = this.activeSessions.has(session.name) ?
|
|
72
|
+
c.green('● Online') : c.red('○ Offline');
|
|
73
|
+
console.log(c.gray(` ${index + 1}. ${session.name} ${status}`));
|
|
74
|
+
});
|
|
75
|
+
console.log('');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
createReadline() {
|
|
80
|
+
if (this.rl) {
|
|
81
|
+
this.rl.close();
|
|
82
|
+
}
|
|
83
|
+
this.rl = readline.createInterface({
|
|
84
|
+
input: process.stdin,
|
|
85
|
+
output: process.stdout
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
question(query) {
|
|
90
|
+
return new Promise(resolve => {
|
|
91
|
+
this.rl.question(query, resolve);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async showCreateSessionMenu() {
|
|
96
|
+
this.clearScreen();
|
|
97
|
+
this.showBanner();
|
|
98
|
+
console.log(c.yellow('🆕 Neue Session erstellen\n'));
|
|
99
|
+
|
|
100
|
+
const sessionName = await this.question(c.white('📝 Session-Name eingeben: '));
|
|
101
|
+
|
|
102
|
+
if (!sessionName || sessionName.trim() === '') {
|
|
103
|
+
console.log(c.red('\n❌ Ungültiger Name!'));
|
|
104
|
+
await this.waitForEnter();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (this.sessions.find(s => s.name === sessionName)) {
|
|
109
|
+
console.log(c.red('\n❌ Session existiert bereits!'));
|
|
110
|
+
await this.waitForEnter();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log(c.yellow('\n🔐 Login-Methode wählen:\n'));
|
|
115
|
+
console.log(c.white(' 1️⃣ Pairing Code (Telefonnummer)'));
|
|
116
|
+
console.log(c.white(' 2️⃣ QR Code scannen\n'));
|
|
117
|
+
|
|
118
|
+
const method = await this.question(c.white('Auswahl (1 oder 2): '));
|
|
119
|
+
|
|
120
|
+
if (method === '1') {
|
|
121
|
+
await this.createSessionWithPairing(sessionName);
|
|
122
|
+
} else if (method === '2') {
|
|
123
|
+
await this.createSessionWithQR(sessionName);
|
|
124
|
+
} else {
|
|
125
|
+
console.log(c.red('\n❌ Ungültige Auswahl!'));
|
|
126
|
+
await this.waitForEnter();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async createSessionWithPairing(sessionName) {
|
|
131
|
+
console.log(c.yellow('\n📱 Pairing Code Login\n'));
|
|
132
|
+
|
|
133
|
+
const phoneNumber = await this.question(c.white('Telefonnummer (mit Vorwahl, z.B. +491234567890): '));
|
|
134
|
+
|
|
135
|
+
if (!phoneNumber.startsWith('+')) {
|
|
136
|
+
console.log(c.red('\n❌ Nummer muss mit + beginnen!'));
|
|
137
|
+
await this.waitForEnter();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const cleanNumber = phoneNumber.replace(/[^0-9]/g, '');
|
|
142
|
+
|
|
143
|
+
console.log(c.cyan('\n🔄 Verbinde...'));
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const authDir = path.join(this.baseAuthDir, sessionName);
|
|
147
|
+
const { state, saveCreds } = await useMultiFileAuthState(authDir);
|
|
148
|
+
const { version } = await fetchLatestBaileysVersion();
|
|
149
|
+
|
|
150
|
+
const sock = makeWASocket({
|
|
151
|
+
version,
|
|
152
|
+
auth: state,
|
|
153
|
+
printQRInTerminal: false,
|
|
154
|
+
logger: pino({ level: 'silent' })
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (!sock.authState.creds.registered) {
|
|
158
|
+
const code = await sock.requestPairingCode(cleanNumber);
|
|
159
|
+
console.log(c.green(`\n✅ Pairing Code: ${c.bold(code)}\n`));
|
|
160
|
+
console.log(c.yellow('📲 Gehe zu WhatsApp > Verknüpfte Geräte > Gerät verknüpfen'));
|
|
161
|
+
console.log(c.yellow(' und gib den Code ein!\n'));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
await new Promise((resolve, reject) => {
|
|
165
|
+
sock.ev.on('connection.update', async (update) => {
|
|
166
|
+
const { connection, lastDisconnect } = update;
|
|
167
|
+
|
|
168
|
+
if (connection === 'open') {
|
|
169
|
+
console.log(c.green('✅ Erfolgreich verbunden!'));
|
|
170
|
+
|
|
171
|
+
this.sessions.push({
|
|
172
|
+
name: sessionName,
|
|
173
|
+
authDir: authDir,
|
|
174
|
+
method: 'pairing',
|
|
175
|
+
phoneNumber: phoneNumber,
|
|
176
|
+
createdAt: new Date().toISOString()
|
|
177
|
+
});
|
|
178
|
+
this.saveSessionsConfig();
|
|
179
|
+
|
|
180
|
+
await sock.end();
|
|
181
|
+
resolve();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (connection === 'close') {
|
|
185
|
+
const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
|
|
186
|
+
if (!shouldReconnect) {
|
|
187
|
+
reject(new Error('Verbindung fehlgeschlagen'));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
sock.ev.on('creds.update', saveCreds);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
console.log(c.green('\n✅ Session erfolgreich erstellt!'));
|
|
196
|
+
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.log(c.red(`\n❌ Fehler: ${error.message}`));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
await this.waitForEnter();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async createSessionWithQR(sessionName) {
|
|
205
|
+
console.log(c.yellow('\n📱 QR Code Login\n'));
|
|
206
|
+
console.log(c.cyan('🔄 Generiere QR Code...\n'));
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
const authDir = path.join(this.baseAuthDir, sessionName);
|
|
210
|
+
const { state, saveCreds } = await useMultiFileAuthState(authDir);
|
|
211
|
+
const { version } = await fetchLatestBaileysVersion();
|
|
212
|
+
|
|
213
|
+
const sock = makeWASocket({
|
|
214
|
+
version,
|
|
215
|
+
auth: state,
|
|
216
|
+
printQRInTerminal: false,
|
|
217
|
+
logger: pino({ level: 'silent' })
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
let qrShown = false;
|
|
221
|
+
|
|
222
|
+
sock.ev.on('connection.update', async (update) => {
|
|
223
|
+
const { connection, lastDisconnect, qr } = update;
|
|
224
|
+
|
|
225
|
+
if (qr && !qrShown) {
|
|
226
|
+
console.log(c.yellow('📲 Scanne den QR Code mit WhatsApp:\n'));
|
|
227
|
+
qrcode.generate(qr, { small: true });
|
|
228
|
+
qrShown = true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (connection === 'open') {
|
|
232
|
+
console.log(c.green('\n✅ Erfolgreich verbunden!'));
|
|
233
|
+
|
|
234
|
+
this.sessions.push({
|
|
235
|
+
name: sessionName,
|
|
236
|
+
authDir: authDir,
|
|
237
|
+
method: 'qr',
|
|
238
|
+
createdAt: new Date().toISOString()
|
|
239
|
+
});
|
|
240
|
+
this.saveSessionsConfig();
|
|
241
|
+
|
|
242
|
+
await sock.end();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (connection === 'close') {
|
|
246
|
+
const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
|
|
247
|
+
if (!shouldReconnect) {
|
|
248
|
+
console.log(c.red('\n❌ Verbindung fehlgeschlagen'));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
sock.ev.on('creds.update', saveCreds);
|
|
254
|
+
|
|
255
|
+
await new Promise(resolve => setTimeout(resolve, 60000));
|
|
256
|
+
|
|
257
|
+
if (sock.user) {
|
|
258
|
+
console.log(c.green('\n✅ Session erfolgreich erstellt!'));
|
|
259
|
+
} else {
|
|
260
|
+
console.log(c.red('\n❌ Timeout - QR Code nicht gescannt'));
|
|
261
|
+
await sock.end();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.log(c.red(`\n❌ Fehler: ${error.message}`));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
await this.waitForEnter();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async startAllSessions() {
|
|
272
|
+
this.clearScreen();
|
|
273
|
+
this.showBanner();
|
|
274
|
+
console.log(c.yellow('🚀 Starte alle Sessions...\n'));
|
|
275
|
+
|
|
276
|
+
if (this.sessions.length === 0) {
|
|
277
|
+
console.log(c.red('❌ Keine Sessions vorhanden!'));
|
|
278
|
+
await this.waitForEnter();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
for (const session of this.sessions) {
|
|
283
|
+
await this.startSession(session.name);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
console.log(c.green(`\n✅ ${this.activeSessions.size} Session(s) gestartet!`));
|
|
287
|
+
await this.waitForEnter();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async startSingleSession() {
|
|
291
|
+
this.clearScreen();
|
|
292
|
+
this.showBanner();
|
|
293
|
+
console.log(c.yellow('🎯 Einzelne Session starten\n'));
|
|
294
|
+
|
|
295
|
+
if (this.sessions.length === 0) {
|
|
296
|
+
console.log(c.red('❌ Keine Sessions vorhanden!'));
|
|
297
|
+
await this.waitForEnter();
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
console.log(c.white('Verfügbare Sessions:\n'));
|
|
302
|
+
this.sessions.forEach((session, index) => {
|
|
303
|
+
const status = this.activeSessions.has(session.name) ?
|
|
304
|
+
c.green('● Online') : c.red('○ Offline');
|
|
305
|
+
console.log(c.white(` ${index + 1}. ${session.name} ${status}`));
|
|
306
|
+
});
|
|
307
|
+
console.log('');
|
|
308
|
+
|
|
309
|
+
const choice = await this.question(c.white('Session-Nummer: '));
|
|
310
|
+
const index = parseInt(choice) - 1;
|
|
311
|
+
|
|
312
|
+
if (index >= 0 && index < this.sessions.length) {
|
|
313
|
+
const session = this.sessions[index];
|
|
314
|
+
console.log(c.cyan(`\n🔄 Starte ${session.name}...`));
|
|
315
|
+
await this.startSession(session.name);
|
|
316
|
+
console.log(c.green(`✅ ${session.name} gestartet!`));
|
|
317
|
+
} else {
|
|
318
|
+
console.log(c.red('\n❌ Ungültige Auswahl!'));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
await this.waitForEnter();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async startSession(sessionName) {
|
|
325
|
+
const session = this.sessions.find(s => s.name === sessionName);
|
|
326
|
+
if (!session) {
|
|
327
|
+
console.log(c.red(`❌ Session "${sessionName}" nicht gefunden!`));
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (this.activeSessions.has(sessionName)) {
|
|
332
|
+
console.log(c.yellow(`⚠️ ${sessionName} läuft bereits!`));
|
|
333
|
+
return this.activeSessions.get(sessionName);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
try {
|
|
337
|
+
const { state, saveCreds } = await useMultiFileAuthState(session.authDir);
|
|
338
|
+
const { version } = await fetchLatestBaileysVersion();
|
|
339
|
+
|
|
340
|
+
const sock = makeWASocket({
|
|
341
|
+
version,
|
|
342
|
+
auth: state,
|
|
343
|
+
printQRInTerminal: false,
|
|
344
|
+
logger: pino({ level: 'silent' })
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
sock.ev.on('creds.update', saveCreds);
|
|
348
|
+
|
|
349
|
+
sock.ev.on('connection.update', (update) => {
|
|
350
|
+
const { connection } = update;
|
|
351
|
+
if (connection === 'open') {
|
|
352
|
+
console.log(c.green(`✅ ${sessionName} verbunden`));
|
|
353
|
+
}
|
|
354
|
+
if (connection === 'close') {
|
|
355
|
+
this.activeSessions.delete(sessionName);
|
|
356
|
+
console.log(c.red(`❌ ${sessionName} getrennt`));
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
this.activeSessions.set(sessionName, sock);
|
|
361
|
+
return sock;
|
|
362
|
+
|
|
363
|
+
} catch (error) {
|
|
364
|
+
console.log(c.red(`❌ Fehler beim Starten von ${sessionName}: ${error.message}`));
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async manageSessionsMenu() {
|
|
370
|
+
this.clearScreen();
|
|
371
|
+
this.showBanner();
|
|
372
|
+
console.log(c.yellow('⚙️ Sessions verwalten\n'));
|
|
373
|
+
|
|
374
|
+
if (this.sessions.length === 0) {
|
|
375
|
+
console.log(c.red('❌ Keine Sessions vorhanden!'));
|
|
376
|
+
await this.waitForEnter();
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
console.log(c.white('Verfügbare Sessions:\n'));
|
|
381
|
+
this.sessions.forEach((session, index) => {
|
|
382
|
+
const status = this.activeSessions.has(session.name) ?
|
|
383
|
+
c.green('● Online') : c.red('○ Offline');
|
|
384
|
+
console.log(c.white(` ${index + 1}. ${session.name} ${status}`));
|
|
385
|
+
});
|
|
386
|
+
console.log(c.white(` ${this.sessions.length + 1}. Zurück\n`));
|
|
387
|
+
|
|
388
|
+
const choice = await this.question(c.white('Session zum Löschen auswählen: '));
|
|
389
|
+
const index = parseInt(choice) - 1;
|
|
390
|
+
|
|
391
|
+
if (index >= 0 && index < this.sessions.length) {
|
|
392
|
+
const session = this.sessions[index];
|
|
393
|
+
const confirm = await this.question(c.red(`⚠️ ${session.name} wirklich löschen? (j/n): `));
|
|
394
|
+
|
|
395
|
+
if (confirm.toLowerCase() === 'j') {
|
|
396
|
+
if (this.activeSessions.has(session.name)) {
|
|
397
|
+
const sock = this.activeSessions.get(session.name);
|
|
398
|
+
await sock.end();
|
|
399
|
+
this.activeSessions.delete(session.name);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (fs.existsSync(session.authDir)) {
|
|
403
|
+
fs.rmSync(session.authDir, { recursive: true, force: true });
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
this.sessions.splice(index, 1);
|
|
407
|
+
this.saveSessionsConfig();
|
|
408
|
+
|
|
409
|
+
console.log(c.green(`\n✅ ${session.name} gelöscht!`));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
await this.waitForEnter();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
async waitForEnter() {
|
|
417
|
+
await this.question(c.gray('\nDrücke Enter um fortzufahren...'));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async start() {
|
|
421
|
+
this.createReadline();
|
|
422
|
+
|
|
423
|
+
let running = true;
|
|
424
|
+
while (running) {
|
|
425
|
+
this.showMainMenu();
|
|
426
|
+
const choice = await this.question(c.white('Auswahl: '));
|
|
427
|
+
|
|
428
|
+
switch (choice) {
|
|
429
|
+
case '1':
|
|
430
|
+
await this.showCreateSessionMenu();
|
|
431
|
+
break;
|
|
432
|
+
case '2':
|
|
433
|
+
await this.startAllSessions();
|
|
434
|
+
break;
|
|
435
|
+
case '3':
|
|
436
|
+
await this.startSingleSession();
|
|
437
|
+
break;
|
|
438
|
+
case '4':
|
|
439
|
+
await this.manageSessionsMenu();
|
|
440
|
+
break;
|
|
441
|
+
case '5':
|
|
442
|
+
running = false;
|
|
443
|
+
break;
|
|
444
|
+
default:
|
|
445
|
+
console.log(c.red('\n❌ Ungültige Auswahl!'));
|
|
446
|
+
await this.waitForEnter();
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
this.rl.close();
|
|
451
|
+
this.clearScreen();
|
|
452
|
+
console.log(c.cyan('👋 Auf Wiedersehen!\n'));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
getActiveSessions() {
|
|
456
|
+
return this.activeSessions;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
getSession(sessionName) {
|
|
460
|
+
return this.activeSessions.get(sessionName);
|
|
461
|
+
}
|
|
462
|
+
}
|