waengine 1.0.6 → 1.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/README.md CHANGED
@@ -496,20 +496,52 @@ const messageTypes = await msg.stats.getMessagesByType()
496
496
 
497
497
  ### **Prefix Setup**
498
498
  ```javascript
499
- // Set prefix
499
+ // Global Prefix (Fallback)
500
500
  const prefix = "!"
501
501
  client.setPrefix(prefix)
502
502
 
503
- // Register commands
503
+ // Chat-spezifische Prefixes (NEU in v1.0.7!)
504
+ client.setChatPrefix(chatId, "#") // Für spezifischen Chat
505
+ client.getChatPrefix(chatId) // Prefix abrufen
506
+ client.removeChatPrefix(chatId) // Prefix entfernen
507
+
508
+ // Commands registrieren
504
509
  client.addCommand('help', async (msg, args) => {
505
510
  await msg.reply('Help text')
506
511
  })
512
+ ```
507
513
 
508
- client.addCommand('ping', async (msg, args) => {
509
- await msg.reply('Pong! 🏓')
510
- })
514
+ ### **Chat-spezifische Prefixes (v1.0.7)**
515
+ Jeder Chat/Gruppe kann einen eigenen Prefix haben:
516
+
517
+ ```javascript
518
+ // Setprefix Command (Admin only)
519
+ client.addCommand('setprefix', async (msg, args) => {
520
+ if (msg.isGroup && !(await msg.isAdmin())) {
521
+ return msg.reply('❌ Nur Admins können den Prefix ändern!');
522
+ }
523
+
524
+ const newPrefix = args[0];
525
+ client.setChatPrefix(msg.from, newPrefix);
526
+ await msg.reply(`✅ Prefix geändert zu: "${newPrefix}"`);
527
+ });
528
+
529
+ // Prefix Info Command
530
+ client.addCommand('prefixinfo', async (msg) => {
531
+ const chatPrefix = client.getChatPrefix(msg.from);
532
+ const stats = client.getPrefixStats();
533
+
534
+ await msg.reply(`🎯 Aktueller Prefix: "${chatPrefix}"\n📊 Gesamt Chats: ${stats.totalChats}`);
535
+ });
511
536
  ```
512
537
 
538
+ **Features:**
539
+ - ✅ **Persistent Storage** - Prefixes werden automatisch gespeichert
540
+ - ✅ **Admin-only** - Nur Admins können Prefixes in Gruppen ändern
541
+ - ✅ **Validierung** - Max 5 Zeichen, keine Leerzeichen
542
+ - ✅ **Statistics** - Übersicht über alle verwendeten Prefixes
543
+ - ✅ **Fallback** - Global Prefix als Standard
544
+
513
545
  ### **Command Properties**
514
546
  ```javascript
515
547
  // In message events
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waengine",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "🚀 WAEngine - The most powerful WhatsApp Bot Library with Multi-Device Support & EasyBot API",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -24,6 +24,9 @@
24
24
  "messaging",
25
25
  "multi-account",
26
26
  "load-balancing",
27
+ "prefix-system",
28
+ "chat-specific",
29
+ "group-management",
27
30
  "typescript",
28
31
  "javascript",
29
32
  "nodejs"
@@ -47,6 +50,8 @@
47
50
  },
48
51
  "dependencies": {
49
52
  "@whiskeysockets/baileys": "^7.0.0-rc.9",
53
+ "axios": "^1.13.4",
54
+ "node-cron": "^3.0.3",
50
55
  "pino": "^8.0.0",
51
56
  "playwright": "^1.58.1",
52
57
  "qrcode": "^1.5.4",
@@ -0,0 +1,185 @@
1
+ // AI Integration für WAEngine
2
+ import axios from 'axios';
3
+
4
+ export class AIIntegration {
5
+ constructor(options = {}) {
6
+ this.apiKey = options.apiKey || process.env.OPENAI_API_KEY;
7
+ this.baseURL = options.baseURL || 'https://api.openai.com/v1';
8
+ this.model = options.model || 'gpt-3.5-turbo';
9
+ this.enabled = !!this.apiKey;
10
+
11
+ if (!this.enabled) {
12
+ console.log('⚠️ AI Integration deaktiviert - Kein API Key gefunden');
13
+ } else {
14
+ console.log('🤖 AI Integration aktiviert');
15
+ }
16
+ }
17
+
18
+ // ===== CHAT COMPLETION =====
19
+
20
+ async chat(prompt, options = {}) {
21
+ if (!this.enabled) {
22
+ throw new Error('❌ AI Integration nicht konfiguriert! Setze OPENAI_API_KEY');
23
+ }
24
+
25
+ try {
26
+ const response = await axios.post(`${this.baseURL}/chat/completions`, {
27
+ model: options.model || this.model,
28
+ messages: [
29
+ {
30
+ role: 'system',
31
+ content: options.systemPrompt || 'Du bist ein hilfreicher WhatsApp Bot Assistent. Antworte kurz und freundlich auf Deutsch.'
32
+ },
33
+ {
34
+ role: 'user',
35
+ content: prompt
36
+ }
37
+ ],
38
+ max_tokens: options.maxTokens || 500,
39
+ temperature: options.temperature || 0.7
40
+ }, {
41
+ headers: {
42
+ 'Authorization': `Bearer ${this.apiKey}`,
43
+ 'Content-Type': 'application/json'
44
+ }
45
+ });
46
+
47
+ return response.data.choices[0].message.content.trim();
48
+ } catch (error) {
49
+ console.error('❌ AI Chat Fehler:', error.response?.data || error.message);
50
+ throw new Error(`AI Fehler: ${error.response?.data?.error?.message || error.message}`);
51
+ }
52
+ }
53
+
54
+ // ===== SMART RESPONSES =====
55
+
56
+ async smartReply(message, context = {}) {
57
+ const prompt = `
58
+ Kontext: WhatsApp Bot Nachricht
59
+ User schrieb: "${message}"
60
+ Chat-Type: ${context.isGroup ? 'Gruppe' : 'Privat'}
61
+ ${context.userName ? `User: ${context.userName}` : ''}
62
+
63
+ Antworte natürlich und hilfreich. Maximal 2 Sätze.
64
+ `.trim();
65
+
66
+ return await this.chat(prompt, {
67
+ systemPrompt: 'Du bist ein freundlicher WhatsApp Bot. Antworte natürlich und kurz.',
68
+ maxTokens: 200
69
+ });
70
+ }
71
+
72
+ // ===== TEXT ANALYSIS =====
73
+
74
+ async analyzeMessage(text) {
75
+ const prompt = `
76
+ Analysiere diese Nachricht:
77
+ "${text}"
78
+
79
+ Gib zurück als JSON:
80
+ {
81
+ "sentiment": "positive/negative/neutral",
82
+ "language": "de/en/es/fr/etc",
83
+ "category": "question/command/greeting/complaint/other",
84
+ "toxicity": "low/medium/high",
85
+ "confidence": 0.0-1.0
86
+ }
87
+ `.trim();
88
+
89
+ try {
90
+ const response = await this.chat(prompt, {
91
+ systemPrompt: 'Du bist ein Text-Analyse-Experte. Antworte nur mit gültigem JSON.',
92
+ maxTokens: 150
93
+ });
94
+
95
+ return JSON.parse(response);
96
+ } catch (error) {
97
+ return {
98
+ sentiment: 'neutral',
99
+ language: 'unknown',
100
+ category: 'other',
101
+ toxicity: 'low',
102
+ confidence: 0.5
103
+ };
104
+ }
105
+ }
106
+
107
+ // ===== MODERATION =====
108
+
109
+ async moderateContent(text) {
110
+ try {
111
+ const response = await axios.post(`${this.baseURL}/moderations`, {
112
+ input: text
113
+ }, {
114
+ headers: {
115
+ 'Authorization': `Bearer ${this.apiKey}`,
116
+ 'Content-Type': 'application/json'
117
+ }
118
+ });
119
+
120
+ const result = response.data.results[0];
121
+
122
+ return {
123
+ flagged: result.flagged,
124
+ categories: result.categories,
125
+ scores: result.category_scores,
126
+ safe: !result.flagged
127
+ };
128
+ } catch (error) {
129
+ console.error('❌ Moderation Fehler:', error.message);
130
+ return { flagged: false, safe: true };
131
+ }
132
+ }
133
+
134
+ // ===== TRANSLATION =====
135
+
136
+ async translate(text, targetLang = 'de') {
137
+ const prompt = `Übersetze folgenden Text nach ${targetLang}. Antworte nur mit der Übersetzung:\n\n"${text}"`;
138
+
139
+ return await this.chat(prompt, {
140
+ systemPrompt: 'Du bist ein professioneller Übersetzer. Antworte nur mit der Übersetzung.',
141
+ maxTokens: 300
142
+ });
143
+ }
144
+
145
+ // ===== SUMMARIZATION =====
146
+
147
+ async summarize(text, maxLength = 100) {
148
+ const prompt = `Fasse folgenden Text in maximal ${maxLength} Zeichen zusammen:\n\n"${text}"`;
149
+
150
+ return await this.chat(prompt, {
151
+ systemPrompt: 'Du bist ein Experte für Textzusammenfassungen. Sei präzise und kurz.',
152
+ maxTokens: Math.ceil(maxLength / 2)
153
+ });
154
+ }
155
+
156
+ // ===== QUESTION ANSWERING =====
157
+
158
+ async answerQuestion(question, context = '') {
159
+ const prompt = context ?
160
+ `Kontext: ${context}\n\nFrage: ${question}` :
161
+ question;
162
+
163
+ return await this.chat(prompt, {
164
+ systemPrompt: 'Du bist ein hilfreicher Assistent. Beantworte Fragen präzise und verständlich.',
165
+ maxTokens: 400
166
+ });
167
+ }
168
+
169
+ // ===== CREATIVE WRITING =====
170
+
171
+ async generateText(prompt, style = 'normal') {
172
+ const stylePrompts = {
173
+ funny: 'Schreibe lustig und humorvoll',
174
+ formal: 'Schreibe formal und professionell',
175
+ casual: 'Schreibe locker und umgangssprachlich',
176
+ creative: 'Schreibe kreativ und fantasievoll',
177
+ normal: 'Schreibe natürlich und verständlich'
178
+ };
179
+
180
+ return await this.chat(prompt, {
181
+ systemPrompt: `Du bist ein kreativer Schreiber. ${stylePrompts[style] || stylePrompts.normal}.`,
182
+ maxTokens: 600
183
+ });
184
+ }
185
+ }
package/src/client.js CHANGED
@@ -3,6 +3,11 @@ import pino from "pino";
3
3
  import { generateQRCode, closeBrowser } from "./qr.js";
4
4
  import { Message } from "./message.js";
5
5
  import { SessionManager } from "./session-manager.js";
6
+ import { PrefixManager } from "./prefix-manager.js";
7
+ import { getStorage } from "./storage.js";
8
+ import { AIIntegration } from "./ai-integration.js";
9
+ import { HTTPClient } from "./http-client.js";
10
+ import { Scheduler } from "./scheduler.js";
6
11
 
7
12
  export class WhatsAppClient {
8
13
  constructor(options = {}) {
@@ -24,10 +29,26 @@ export class WhatsAppClient {
24
29
  // Session Manager
25
30
  this.sessionManager = new SessionManager(this.options.authDir);
26
31
 
27
- // Prefix System
28
- this.prefix = null;
32
+ // Prefix System (erweitert für gruppen-spezifische Prefixes)
33
+ this.prefix = null; // Global fallback
34
+ this.prefixManager = new PrefixManager('./data');
29
35
  this.commands = new Map();
30
36
 
37
+ // Storage System
38
+ this.storage = getStorage();
39
+
40
+ // AI Integration
41
+ this.ai = new AIIntegration(options.ai || {});
42
+
43
+ // HTTP Client
44
+ this.http = new HTTPClient(options.http || {});
45
+
46
+ // Scheduler System
47
+ this.scheduler = new Scheduler(this);
48
+
49
+ // Waiting System für Messages
50
+ this.waiting = this.scheduler.createWaiting();
51
+
31
52
  // Deine eigenen API-Objekte
32
53
  this.get = new GetAPI(this);
33
54
  this.add = new AddAPI(this);
@@ -308,28 +329,32 @@ export class WhatsAppClient {
308
329
 
309
330
  const messageObj = new Message(this, messageData);
310
331
 
311
- // Prefix System - Command Check
312
- if (this.prefix && messageData.text && messageData.text.startsWith(this.prefix)) {
313
- const commandText = messageData.text.slice(this.prefix.length).trim();
314
- const [command, ...args] = commandText.split(' ');
315
-
316
- console.log(`⚡ Command: ${this.prefix}${command}`);
317
-
318
- messageObj.isCommand = true;
319
- messageObj.command = command.toLowerCase();
320
- messageObj.args = args;
321
- messageObj.commandText = commandText;
322
-
323
- // Command Event emittieren
324
- this.emit('command', messageObj);
332
+ // Prefix System - Command Check (erweitert für Chat-spezifische Prefixes)
333
+ const chatPrefix = this.prefixManager.getPrefix(messageData.from);
334
+
335
+ if (messageData.text && messageData.text.startsWith(chatPrefix)) {
336
+ const commandData = this.prefixManager.parseCommand(messageData.text, messageData.from);
325
337
 
326
- // Spezifischen Command Handler aufrufen falls vorhanden
327
- if (this.commands.has(command.toLowerCase())) {
328
- const handler = this.commands.get(command.toLowerCase());
329
- try {
330
- handler(messageObj, args);
331
- } catch (error) {
332
- console.error(`❌ Fehler in Command '${command}':`, error);
338
+ if (commandData) {
339
+ console.log(`⚡ Command in ${messageData.from}: ${commandData.prefix}${commandData.command}`);
340
+
341
+ messageObj.isCommand = true;
342
+ messageObj.command = commandData.command;
343
+ messageObj.args = commandData.args;
344
+ messageObj.commandText = commandData.commandText;
345
+ messageObj.prefix = commandData.prefix;
346
+
347
+ // Command Event emittieren
348
+ this.emit('command', messageObj);
349
+
350
+ // Spezifischen Command Handler aufrufen falls vorhanden
351
+ if (this.commands.has(commandData.command)) {
352
+ const handler = this.commands.get(commandData.command);
353
+ try {
354
+ handler(messageObj, commandData.args);
355
+ } catch (error) {
356
+ console.error(`❌ Fehler in Command '${commandData.command}':`, error);
357
+ }
333
358
  }
334
359
  }
335
360
  } else {
@@ -424,15 +449,43 @@ export class WhatsAppClient {
424
449
  };
425
450
  }
426
451
 
427
- // ===== PREFIX SYSTEM =====
452
+ // ===== PREFIX SYSTEM (ERWEITERT) =====
428
453
 
454
+ // Global Prefix (Fallback)
429
455
  setPrefix(prefix) {
430
456
  this.prefix = prefix;
457
+ this.prefixManager.defaultPrefix = prefix;
458
+ console.log(`🌐 Global Prefix gesetzt: "${prefix}"`);
431
459
  return this;
432
460
  }
433
461
 
434
- getPrefix() {
435
- return this.prefix;
462
+ getPrefix(chatId = null) {
463
+ if (chatId) {
464
+ return this.prefixManager.getPrefix(chatId);
465
+ }
466
+ return this.prefix || this.prefixManager.defaultPrefix;
467
+ }
468
+
469
+ // Chat-spezifische Prefixes
470
+ setChatPrefix(chatId, prefix) {
471
+ return this.prefixManager.setPrefix(chatId, prefix);
472
+ }
473
+
474
+ getChatPrefix(chatId) {
475
+ return this.prefixManager.getPrefix(chatId);
476
+ }
477
+
478
+ removeChatPrefix(chatId) {
479
+ return this.prefixManager.removePrefix(chatId);
480
+ }
481
+
482
+ // Prefix Statistics
483
+ getPrefixStats() {
484
+ return this.prefixManager.getStats();
485
+ }
486
+
487
+ getAllPrefixes() {
488
+ return this.prefixManager.getAllPrefixes();
436
489
  }
437
490
 
438
491
  addCommand(command, handler) {
@@ -0,0 +1,276 @@
1
+ // HTTP Client für WAEngine
2
+ import axios from 'axios';
3
+
4
+ export class HTTPClient {
5
+ constructor(options = {}) {
6
+ this.timeout = options.timeout || 10000;
7
+ this.retries = options.retries || 3;
8
+ this.baseHeaders = options.headers || {};
9
+
10
+ // Axios Instance erstellen
11
+ this.axios = axios.create({
12
+ timeout: this.timeout,
13
+ headers: this.baseHeaders
14
+ });
15
+
16
+ console.log('🌐 HTTP Client initialisiert');
17
+ }
18
+
19
+ // ===== BASIC HTTP METHODS =====
20
+
21
+ async get(url, options = {}) {
22
+ return await this.request('GET', url, null, options);
23
+ }
24
+
25
+ async post(url, data = null, options = {}) {
26
+ return await this.request('POST', url, data, options);
27
+ }
28
+
29
+ async put(url, data = null, options = {}) {
30
+ return await this.request('PUT', url, data, options);
31
+ }
32
+
33
+ async delete(url, options = {}) {
34
+ return await this.request('DELETE', url, null, options);
35
+ }
36
+
37
+ // ===== CORE REQUEST METHOD =====
38
+
39
+ async request(method, url, data = null, options = {}) {
40
+ let lastError;
41
+
42
+ for (let attempt = 1; attempt <= this.retries; attempt++) {
43
+ try {
44
+ const config = {
45
+ method,
46
+ url,
47
+ ...options
48
+ };
49
+
50
+ if (data) {
51
+ config.data = data;
52
+ }
53
+
54
+ const response = await this.axios(config);
55
+ return response.data;
56
+
57
+ } catch (error) {
58
+ lastError = error;
59
+
60
+ if (attempt < this.retries && this.shouldRetry(error)) {
61
+ console.log(`🔄 HTTP Retry ${attempt}/${this.retries} für ${url}`);
62
+ await this.delay(1000 * attempt); // Exponential backoff
63
+ } else {
64
+ break;
65
+ }
66
+ }
67
+ }
68
+
69
+ throw new Error(`HTTP Request failed: ${lastError.message}`);
70
+ }
71
+
72
+ shouldRetry(error) {
73
+ // Retry bei Netzwerk-Fehlern oder 5xx Status Codes
74
+ return !error.response || error.response.status >= 500;
75
+ }
76
+
77
+ delay(ms) {
78
+ return new Promise(resolve => setTimeout(resolve, ms));
79
+ }
80
+
81
+ // ===== API WRAPPERS =====
82
+
83
+ // Weather API
84
+ async getWeather(city, apiKey = process.env.WEATHER_API_KEY) {
85
+ if (!apiKey) {
86
+ throw new Error('❌ Weather API Key fehlt! Setze WEATHER_API_KEY');
87
+ }
88
+
89
+ try {
90
+ const data = await this.get(`https://api.openweathermap.org/data/2.5/weather`, {
91
+ params: {
92
+ q: city,
93
+ appid: apiKey,
94
+ units: 'metric',
95
+ lang: 'de'
96
+ }
97
+ });
98
+
99
+ return {
100
+ city: data.name,
101
+ country: data.sys.country,
102
+ temperature: Math.round(data.main.temp),
103
+ description: data.weather[0].description,
104
+ humidity: data.main.humidity,
105
+ windSpeed: data.wind.speed,
106
+ icon: data.weather[0].icon
107
+ };
108
+ } catch (error) {
109
+ throw new Error(`Wetter-Fehler: ${error.message}`);
110
+ }
111
+ }
112
+
113
+ // News API
114
+ async getNews(category = 'general', apiKey = process.env.NEWS_API_KEY) {
115
+ if (!apiKey) {
116
+ throw new Error('❌ News API Key fehlt! Setze NEWS_API_KEY');
117
+ }
118
+
119
+ try {
120
+ const data = await this.get(`https://newsapi.org/v2/top-headlines`, {
121
+ params: {
122
+ country: 'de',
123
+ category: category,
124
+ apiKey: apiKey,
125
+ pageSize: 5
126
+ }
127
+ });
128
+
129
+ return data.articles.map(article => ({
130
+ title: article.title,
131
+ description: article.description,
132
+ url: article.url,
133
+ source: article.source.name,
134
+ publishedAt: new Date(article.publishedAt).toLocaleDateString('de-DE')
135
+ }));
136
+ } catch (error) {
137
+ throw new Error(`News-Fehler: ${error.message}`);
138
+ }
139
+ }
140
+
141
+ // Crypto Prices
142
+ async getCryptoPrice(symbol = 'bitcoin') {
143
+ try {
144
+ const data = await this.get(`https://api.coingecko.com/api/v3/simple/price`, {
145
+ params: {
146
+ ids: symbol,
147
+ vs_currencies: 'eur,usd',
148
+ include_24hr_change: true
149
+ }
150
+ });
151
+
152
+ const coin = data[symbol];
153
+ return {
154
+ symbol: symbol,
155
+ priceEUR: coin.eur,
156
+ priceUSD: coin.usd,
157
+ change24h: coin.eur_24h_change?.toFixed(2) || 0
158
+ };
159
+ } catch (error) {
160
+ throw new Error(`Crypto-Fehler: ${error.message}`);
161
+ }
162
+ }
163
+
164
+ // QR Code Generator
165
+ async generateQRCode(text, size = 200) {
166
+ try {
167
+ const url = `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(text)}`;
168
+
169
+ // Return URL instead of downloading
170
+ return {
171
+ url: url,
172
+ text: text,
173
+ size: size
174
+ };
175
+ } catch (error) {
176
+ throw new Error(`QR-Code-Fehler: ${error.message}`);
177
+ }
178
+ }
179
+
180
+ // URL Shortener
181
+ async shortenUrl(longUrl, apiKey = process.env.BITLY_API_KEY) {
182
+ if (!apiKey) {
183
+ // Fallback zu kostenlosem Service
184
+ try {
185
+ const data = await this.post('https://is.gd/create.php', null, {
186
+ params: {
187
+ format: 'json',
188
+ url: longUrl
189
+ }
190
+ });
191
+
192
+ return {
193
+ shortUrl: data.shorturl,
194
+ longUrl: longUrl,
195
+ service: 'is.gd'
196
+ };
197
+ } catch (error) {
198
+ throw new Error(`URL-Shortener-Fehler: ${error.message}`);
199
+ }
200
+ }
201
+
202
+ // Bitly API
203
+ try {
204
+ const data = await this.post('https://api-ssl.bitly.com/v4/shorten', {
205
+ long_url: longUrl
206
+ }, {
207
+ headers: {
208
+ 'Authorization': `Bearer ${apiKey}`,
209
+ 'Content-Type': 'application/json'
210
+ }
211
+ });
212
+
213
+ return {
214
+ shortUrl: data.link,
215
+ longUrl: longUrl,
216
+ service: 'bitly'
217
+ };
218
+ } catch (error) {
219
+ throw new Error(`Bitly-Fehler: ${error.message}`);
220
+ }
221
+ }
222
+
223
+ // Random Facts
224
+ async getRandomFact() {
225
+ try {
226
+ const data = await this.get('https://uselessfacts.jsph.pl/random.json?language=en');
227
+ return data.text;
228
+ } catch (error) {
229
+ throw new Error(`Random-Fact-Fehler: ${error.message}`);
230
+ }
231
+ }
232
+
233
+ // Random Joke
234
+ async getRandomJoke() {
235
+ try {
236
+ const data = await this.get('https://official-joke-api.appspot.com/random_joke');
237
+ return `${data.setup}\n\n${data.punchline}`;
238
+ } catch (error) {
239
+ throw new Error(`Joke-Fehler: ${error.message}`);
240
+ }
241
+ }
242
+
243
+ // IP Info
244
+ async getIPInfo(ip = '') {
245
+ try {
246
+ const url = ip ? `http://ip-api.com/json/${ip}` : 'http://ip-api.com/json/';
247
+ const data = await this.get(url);
248
+
249
+ return {
250
+ ip: data.query,
251
+ country: data.country,
252
+ city: data.city,
253
+ region: data.regionName,
254
+ timezone: data.timezone,
255
+ isp: data.isp
256
+ };
257
+ } catch (error) {
258
+ throw new Error(`IP-Info-Fehler: ${error.message}`);
259
+ }
260
+ }
261
+
262
+ // Website Screenshot (via API)
263
+ async getWebsiteScreenshot(url, width = 1280, height = 720) {
264
+ try {
265
+ const screenshotUrl = `https://api.screenshotmachine.com/?key=${process.env.SCREENSHOT_API_KEY}&url=${encodeURIComponent(url)}&dimension=${width}x${height}`;
266
+
267
+ return {
268
+ screenshotUrl: screenshotUrl,
269
+ originalUrl: url,
270
+ dimensions: `${width}x${height}`
271
+ };
272
+ } catch (error) {
273
+ throw new Error(`Screenshot-Fehler: ${error.message}`);
274
+ }
275
+ }
276
+ }