waengine 1.0.8 → 1.0.10
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/CHANGELOG.md +110 -0
- package/FEATURES.md +2354 -0
- package/PLUGIN-SYSTEM.md +271 -0
- package/package.json +12 -3
- package/plugins/analytics-plugin/config.json +91 -0
- package/plugins/analytics-plugin/index.js +461 -0
- package/plugins/creative-plugin/config.json +87 -0
- package/plugins/creative-plugin/index.js +320 -0
- package/plugins/economy-system/config.json +48 -0
- package/plugins/economy-system/index.js +237 -0
- package/plugins/education-plugin/index.js +275 -0
- package/plugins/games-plugin/config.json +35 -0
- package/plugins/games-plugin/index.js +300 -0
- package/plugins/moderation-plugin/config.json +86 -0
- package/plugins/moderation-plugin/index.js +458 -0
- package/plugins/music-plugin/config.json +32 -0
- package/plugins/music-plugin/index.js +221 -0
- package/plugins/travel-plugin/index.js +230 -0
- package/src/client.js +22 -0
- package/src/easy-bot.js +16 -15
- package/src/index.js +2 -0
- package/src/message.js +109 -1
- package/src/plugin-manager-fixed.js +116 -0
- package/src/plugin-manager.js +105 -0
- package/src/sticker-creator.js +413 -0
- package/src/storage.js +5 -4
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
// 🎨 WAEngine Sticker Creator mit Sharp Integration
|
|
2
|
+
import sharp from 'sharp';
|
|
3
|
+
import { readFileSync, writeFileSync, unlinkSync, existsSync, mkdirSync, readdirSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import axios from 'axios';
|
|
6
|
+
|
|
7
|
+
export class StickerCreator {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
this.message = message;
|
|
10
|
+
this.client = message.client;
|
|
11
|
+
this.tempDir = './temp-stickers';
|
|
12
|
+
|
|
13
|
+
// Erstelle temp Ordner falls nicht vorhanden
|
|
14
|
+
this.ensureTempDir();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
ensureTempDir() {
|
|
18
|
+
try {
|
|
19
|
+
if (!existsSync(this.tempDir)) {
|
|
20
|
+
mkdirSync(this.tempDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.log('⚠️ Temp-Ordner konnte nicht erstellt werden:', error.message);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get sticker() {
|
|
28
|
+
return {
|
|
29
|
+
fromMedia: async (mediaBuffer, options = {}) => {
|
|
30
|
+
try {
|
|
31
|
+
const {
|
|
32
|
+
pack = 'WAEngine',
|
|
33
|
+
author = 'Bot',
|
|
34
|
+
quality = 'high',
|
|
35
|
+
crop = true,
|
|
36
|
+
animated = false
|
|
37
|
+
} = options;
|
|
38
|
+
|
|
39
|
+
console.log('🎨 Erstelle Sticker mit Sharp...');
|
|
40
|
+
|
|
41
|
+
let processedBuffer;
|
|
42
|
+
|
|
43
|
+
if (animated) {
|
|
44
|
+
// Für animierte Sticker (GIF/WebP)
|
|
45
|
+
processedBuffer = await this.processAnimatedSticker(mediaBuffer, options);
|
|
46
|
+
} else {
|
|
47
|
+
// Für statische Sticker
|
|
48
|
+
processedBuffer = await this.processStaticSticker(mediaBuffer, options);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Sticker-Metadaten für WhatsApp
|
|
52
|
+
const stickerMessage = {
|
|
53
|
+
sticker: processedBuffer,
|
|
54
|
+
mimetype: animated ? 'image/webp' : 'image/webp'
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Sende Sticker
|
|
58
|
+
const result = await this.client.socket.sendMessage(this.message.from, stickerMessage);
|
|
59
|
+
console.log('✅ Sticker erfolgreich gesendet');
|
|
60
|
+
return result;
|
|
61
|
+
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('❌ Fehler beim Erstellen des Stickers:', error);
|
|
64
|
+
throw new Error(`Sticker konnte nicht erstellt werden: ${error.message}`);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
fromImage: async (imagePath, options = {}) => {
|
|
69
|
+
try {
|
|
70
|
+
console.log('🖼️ Erstelle Sticker aus Bild:', imagePath);
|
|
71
|
+
|
|
72
|
+
let imageBuffer;
|
|
73
|
+
|
|
74
|
+
if (typeof imagePath === 'string') {
|
|
75
|
+
if (imagePath.startsWith('http')) {
|
|
76
|
+
// URL - lade herunter
|
|
77
|
+
console.log('📥 Lade Bild von URL...');
|
|
78
|
+
const response = await axios.get(imagePath, {
|
|
79
|
+
responseType: 'arraybuffer',
|
|
80
|
+
timeout: 10000
|
|
81
|
+
});
|
|
82
|
+
imageBuffer = Buffer.from(response.data);
|
|
83
|
+
} else {
|
|
84
|
+
// Lokaler Pfad
|
|
85
|
+
console.log('📁 Lade lokales Bild...');
|
|
86
|
+
imageBuffer = readFileSync(imagePath);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
// Bereits ein Buffer
|
|
90
|
+
imageBuffer = imagePath;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return await this.sticker.fromMedia(imageBuffer, options);
|
|
94
|
+
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('❌ Fehler beim Laden des Bildes:', error);
|
|
97
|
+
throw new Error(`Bild konnte nicht geladen werden: ${error.message}`);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
fromVideo: async (videoPath, options = {}) => {
|
|
102
|
+
try {
|
|
103
|
+
console.log('🎥 Erstelle animierten Sticker aus Video:', videoPath);
|
|
104
|
+
|
|
105
|
+
const {
|
|
106
|
+
duration = 6, // Max 6 Sekunden für Sticker
|
|
107
|
+
fps = 15,
|
|
108
|
+
...stickerOptions
|
|
109
|
+
} = options;
|
|
110
|
+
|
|
111
|
+
let videoBuffer;
|
|
112
|
+
|
|
113
|
+
if (typeof videoPath === 'string') {
|
|
114
|
+
if (videoPath.startsWith('http')) {
|
|
115
|
+
const response = await axios.get(videoPath, {
|
|
116
|
+
responseType: 'arraybuffer',
|
|
117
|
+
timeout: 15000
|
|
118
|
+
});
|
|
119
|
+
videoBuffer = Buffer.from(response.data);
|
|
120
|
+
} else {
|
|
121
|
+
videoBuffer = readFileSync(videoPath);
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
videoBuffer = videoPath;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Video zu animiertem WebP konvertieren
|
|
128
|
+
const animatedOptions = {
|
|
129
|
+
...stickerOptions,
|
|
130
|
+
animated: true,
|
|
131
|
+
duration: duration,
|
|
132
|
+
fps: fps
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return await this.sticker.fromMedia(videoBuffer, animatedOptions);
|
|
136
|
+
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error('❌ Fehler beim Erstellen des Video-Stickers:', error);
|
|
139
|
+
throw new Error(`Video-Sticker konnte nicht erstellt werden: ${error.message}`);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
fromText: async (text, options = {}) => {
|
|
144
|
+
try {
|
|
145
|
+
console.log('📝 Erstelle Text-Sticker:', text);
|
|
146
|
+
|
|
147
|
+
const {
|
|
148
|
+
backgroundColor = '#FFFFFF',
|
|
149
|
+
textColor = '#000000',
|
|
150
|
+
fontSize = 64,
|
|
151
|
+
fontFamily = 'Arial',
|
|
152
|
+
width = 512,
|
|
153
|
+
height = 512,
|
|
154
|
+
padding = 50,
|
|
155
|
+
...stickerOptions
|
|
156
|
+
} = options;
|
|
157
|
+
|
|
158
|
+
// Erstelle Text-Bild mit Sharp
|
|
159
|
+
const textImage = await this.createTextImage(text, {
|
|
160
|
+
backgroundColor,
|
|
161
|
+
textColor,
|
|
162
|
+
fontSize,
|
|
163
|
+
fontFamily,
|
|
164
|
+
width,
|
|
165
|
+
height,
|
|
166
|
+
padding
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return await this.sticker.fromMedia(textImage, stickerOptions);
|
|
170
|
+
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error('❌ Fehler beim Text-Sticker:', error);
|
|
173
|
+
throw new Error(`Text-Sticker konnte nicht erstellt werden: ${error.message}`);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
fromUrl: async (url, options = {}) => {
|
|
178
|
+
try {
|
|
179
|
+
console.log('🌐 Erstelle Sticker aus URL:', url);
|
|
180
|
+
|
|
181
|
+
// Lade von URL mit Timeout
|
|
182
|
+
const response = await axios.get(url, {
|
|
183
|
+
responseType: 'arraybuffer',
|
|
184
|
+
timeout: 10000,
|
|
185
|
+
headers: {
|
|
186
|
+
'User-Agent': 'WAEngine/1.0.8'
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
if (response.status !== 200) {
|
|
191
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const mediaBuffer = Buffer.from(response.data);
|
|
195
|
+
const contentType = response.headers['content-type'];
|
|
196
|
+
|
|
197
|
+
console.log('📄 Content-Type:', contentType);
|
|
198
|
+
|
|
199
|
+
// Bestimme Typ basierend auf Content-Type
|
|
200
|
+
if (contentType?.includes('image/gif') || contentType?.includes('video/')) {
|
|
201
|
+
return await this.sticker.fromVideo(mediaBuffer, { ...options, animated: true });
|
|
202
|
+
} else if (contentType?.startsWith('image/')) {
|
|
203
|
+
return await this.sticker.fromImage(mediaBuffer, options);
|
|
204
|
+
} else {
|
|
205
|
+
// Versuche als Bild
|
|
206
|
+
return await this.sticker.fromMedia(mediaBuffer, options);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.error('❌ Fehler beim Laden von URL:', error);
|
|
211
|
+
throw new Error(`URL konnte nicht geladen werden: ${error.message}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async processStaticSticker(imageBuffer, options = {}) {
|
|
218
|
+
const {
|
|
219
|
+
quality = 'high',
|
|
220
|
+
crop = true,
|
|
221
|
+
width = 512,
|
|
222
|
+
height = 512
|
|
223
|
+
} = options;
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
let sharpImage = sharp(imageBuffer);
|
|
227
|
+
|
|
228
|
+
// Hole Metadaten
|
|
229
|
+
const metadata = await sharpImage.metadata();
|
|
230
|
+
console.log(`📊 Bild-Info: ${metadata.width}x${metadata.height}, Format: ${metadata.format}`);
|
|
231
|
+
|
|
232
|
+
// Resize und Crop Logic
|
|
233
|
+
if (crop) {
|
|
234
|
+
// Quadratisch croppen (zentriert)
|
|
235
|
+
const size = Math.min(metadata.width, metadata.height);
|
|
236
|
+
const left = Math.floor((metadata.width - size) / 2);
|
|
237
|
+
const top = Math.floor((metadata.height - size) / 2);
|
|
238
|
+
|
|
239
|
+
sharpImage = sharpImage
|
|
240
|
+
.extract({ left, top, width: size, height: size })
|
|
241
|
+
.resize(width, height, {
|
|
242
|
+
fit: 'cover',
|
|
243
|
+
position: 'center'
|
|
244
|
+
});
|
|
245
|
+
} else {
|
|
246
|
+
// Proportional resize
|
|
247
|
+
sharpImage = sharpImage.resize(width, height, {
|
|
248
|
+
fit: 'inside',
|
|
249
|
+
withoutEnlargement: false,
|
|
250
|
+
background: { r: 255, g: 255, b: 255, alpha: 0 }
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Qualitäts-Einstellungen
|
|
255
|
+
const qualitySettings = {
|
|
256
|
+
high: { quality: 90, effort: 6 },
|
|
257
|
+
medium: { quality: 75, effort: 4 },
|
|
258
|
+
low: { quality: 60, effort: 2 }
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const settings = qualitySettings[quality] || qualitySettings.high;
|
|
262
|
+
|
|
263
|
+
// Zu WebP konvertieren (optimal für WhatsApp Sticker)
|
|
264
|
+
const processedBuffer = await sharpImage
|
|
265
|
+
.webp(settings)
|
|
266
|
+
.toBuffer();
|
|
267
|
+
|
|
268
|
+
console.log(`✅ Sticker verarbeitet: ${processedBuffer.length} bytes`);
|
|
269
|
+
return processedBuffer;
|
|
270
|
+
|
|
271
|
+
} catch (error) {
|
|
272
|
+
console.error('❌ Sharp Verarbeitungsfehler:', error);
|
|
273
|
+
throw error;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async processAnimatedSticker(mediaBuffer, options = {}) {
|
|
278
|
+
const {
|
|
279
|
+
quality = 'high',
|
|
280
|
+
width = 512,
|
|
281
|
+
height = 512,
|
|
282
|
+
duration = 6,
|
|
283
|
+
fps = 15
|
|
284
|
+
} = options;
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
console.log('🎬 Verarbeite animierten Sticker...');
|
|
288
|
+
|
|
289
|
+
// Für animierte Sticker - vereinfachte Verarbeitung
|
|
290
|
+
// In einer vollständigen Implementation würdest du FFmpeg verwenden
|
|
291
|
+
let sharpImage = sharp(mediaBuffer, { animated: true });
|
|
292
|
+
|
|
293
|
+
const metadata = await sharpImage.metadata();
|
|
294
|
+
console.log(`📊 Animiertes Bild-Info: ${metadata.width}x${metadata.height}, Seiten: ${metadata.pages}`);
|
|
295
|
+
|
|
296
|
+
// Resize für animierte WebP
|
|
297
|
+
const processedBuffer = await sharpImage
|
|
298
|
+
.resize(width, height, {
|
|
299
|
+
fit: 'cover',
|
|
300
|
+
position: 'center'
|
|
301
|
+
})
|
|
302
|
+
.webp({
|
|
303
|
+
quality: quality === 'high' ? 80 : quality === 'medium' ? 60 : 40,
|
|
304
|
+
effort: 4
|
|
305
|
+
})
|
|
306
|
+
.toBuffer();
|
|
307
|
+
|
|
308
|
+
console.log(`✅ Animierter Sticker verarbeitet: ${processedBuffer.length} bytes`);
|
|
309
|
+
return processedBuffer;
|
|
310
|
+
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.error('❌ Animierter Sticker Fehler:', error);
|
|
313
|
+
// Fallback: Als statisches Bild verarbeiten
|
|
314
|
+
console.log('🔄 Fallback: Verarbeite als statisches Bild...');
|
|
315
|
+
return await this.processStaticSticker(mediaBuffer, options);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async createTextImage(text, options = {}) {
|
|
320
|
+
const {
|
|
321
|
+
backgroundColor = '#FFFFFF',
|
|
322
|
+
textColor = '#000000',
|
|
323
|
+
fontSize = 64,
|
|
324
|
+
width = 512,
|
|
325
|
+
height = 512,
|
|
326
|
+
padding = 50
|
|
327
|
+
} = options;
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
console.log('🎨 Erstelle Text-Bild mit Sharp...');
|
|
331
|
+
|
|
332
|
+
// SVG für Text erstellen (Sharp unterstützt SVG-Text)
|
|
333
|
+
const textSvg = `
|
|
334
|
+
<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
|
|
335
|
+
<rect width="100%" height="100%" fill="${backgroundColor}"/>
|
|
336
|
+
<text x="50%" y="50%"
|
|
337
|
+
font-family="Arial, sans-serif"
|
|
338
|
+
font-size="${fontSize}"
|
|
339
|
+
fill="${textColor}"
|
|
340
|
+
text-anchor="middle"
|
|
341
|
+
dominant-baseline="middle"
|
|
342
|
+
style="word-wrap: break-word;">
|
|
343
|
+
${text}
|
|
344
|
+
</text>
|
|
345
|
+
</svg>
|
|
346
|
+
`;
|
|
347
|
+
|
|
348
|
+
// SVG zu Buffer konvertieren
|
|
349
|
+
const textBuffer = await sharp(Buffer.from(textSvg))
|
|
350
|
+
.png()
|
|
351
|
+
.toBuffer();
|
|
352
|
+
|
|
353
|
+
console.log('✅ Text-Bild erstellt');
|
|
354
|
+
return textBuffer;
|
|
355
|
+
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error('❌ Text-Bild Fehler:', error);
|
|
358
|
+
|
|
359
|
+
// Fallback: Einfaches farbiges Rechteck
|
|
360
|
+
console.log('🔄 Fallback: Erstelle einfaches Bild...');
|
|
361
|
+
return await sharp({
|
|
362
|
+
create: {
|
|
363
|
+
width: width,
|
|
364
|
+
height: height,
|
|
365
|
+
channels: 4,
|
|
366
|
+
background: backgroundColor
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
.png()
|
|
370
|
+
.toBuffer();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Convenience Methods
|
|
375
|
+
async fromMedia(mediaBuffer, options = {}) {
|
|
376
|
+
return await this.sticker.fromMedia(mediaBuffer, options);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async fromImage(imagePath, options = {}) {
|
|
380
|
+
return await this.sticker.fromImage(imagePath, options);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async fromVideo(videoPath, options = {}) {
|
|
384
|
+
return await this.sticker.fromVideo(videoPath, options);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
async fromText(text, options = {}) {
|
|
388
|
+
return await this.sticker.fromText(text, options);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async fromUrl(url, options = {}) {
|
|
392
|
+
return await this.sticker.fromUrl(url, options);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Cleanup
|
|
396
|
+
cleanup() {
|
|
397
|
+
try {
|
|
398
|
+
// Temp-Dateien löschen falls vorhanden
|
|
399
|
+
if (existsSync(this.tempDir)) {
|
|
400
|
+
const files = readdirSync(this.tempDir);
|
|
401
|
+
files.forEach(file => {
|
|
402
|
+
try {
|
|
403
|
+
unlinkSync(join(this.tempDir, file));
|
|
404
|
+
} catch (error) {
|
|
405
|
+
// Ignoriere Fehler beim Löschen
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
} catch (error) {
|
|
410
|
+
// Ignoriere Cleanup-Fehler
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
package/src/storage.js
CHANGED
|
@@ -16,7 +16,7 @@ export class WAStorage {
|
|
|
16
16
|
ensureBaseDir() {
|
|
17
17
|
if (!fs.existsSync(this.baseDir)) {
|
|
18
18
|
fs.mkdirSync(this.baseDir, { recursive: true });
|
|
19
|
-
|
|
19
|
+
// Stille Directory-Erstellung
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -135,7 +135,7 @@ export class WAStorage {
|
|
|
135
135
|
const filePath = this.getFilePath(fileName);
|
|
136
136
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
137
137
|
this.cache.set(fileName, data);
|
|
138
|
-
|
|
138
|
+
// Stille Speicherung - keine Console-Ausgabe
|
|
139
139
|
return true;
|
|
140
140
|
} catch (error) {
|
|
141
141
|
console.error(`❌ Fehler beim Schreiben in ${fileName}:`, error);
|
|
@@ -250,7 +250,7 @@ export class WAStorage {
|
|
|
250
250
|
if (fs.existsSync(filePath)) {
|
|
251
251
|
fs.unlinkSync(filePath);
|
|
252
252
|
this.cache.delete(fileName);
|
|
253
|
-
|
|
253
|
+
// Stille Löschung
|
|
254
254
|
return true;
|
|
255
255
|
}
|
|
256
256
|
|
|
@@ -337,7 +337,7 @@ export class WAStorage {
|
|
|
337
337
|
// Cache leeren
|
|
338
338
|
clearCache() {
|
|
339
339
|
this.cache.clear();
|
|
340
|
-
|
|
340
|
+
// Stille Cache-Bereinigung
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
// Backup erstellen
|
|
@@ -357,6 +357,7 @@ export class WAStorage {
|
|
|
357
357
|
backedUp++;
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
+
// Nur bei explizitem Backup eine Meldung
|
|
360
361
|
console.log(`💾 Backup erstellt: ${backedUp} Dateien in ${backupDir}`);
|
|
361
362
|
return backupDir;
|
|
362
363
|
} catch (error) {
|