This repository has been archived by the owner on Apr 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
KiwiBot.js
588 lines (490 loc) · 23.3 KB
/
KiwiBot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
const fs = require('fs');
const { Client, Intents, MessageEmbed, WebhookClient } = require('discord.js');
const axios = require('axios');
const cheerio = require('cheerio');
const jsdom = require('jsdom');
const ntpClient = require('ntp-client');
let lastPlayedTitle = '';
let lastPlayedArtist = '';
let previousModerator = null; // Speichert den vorherigen Moderator
let previousTime = null; // Speichert die vorherige Uhrzeit
// Lese die Token-Daten aus Token.json
const data = fs.readFileSync('Token.json', 'utf8');
const { discord_token } = JSON.parse(data);
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
],
});
const prefix = '!'; // Aktualisiere den gewünschten Präfix
const onAirRoleId = 'RolleID'; // Aktualisiere mit der gewünschten Rollen-ID
const streamURLServer1 = 'URL'; // Aktualisiere die URL für Server 1
const streamURLServer2 = 'URL'; // Aktualisiere die URL für Server 2
const pingInterval = 24 * 60 * 60 * 1000; // 24 Stunden in Millisekunden
const pingIntervalServer2 = 24 * 60 * 60 * 1000; // 24 Stunden in Millisekunden für Server 2
const webhookUrl = 'Webhook'; // Aktualisiere mit deiner Webhook-URL
const sendeplanUrl = 'URL'; // Aktualisiere die URL für den Sendeplan
const sendeplanFilePath = 'Sendeplan.json'; // Dateipfad für die Sendeplaninformationen
const channelServer1Id = 'CHANNELID'; // Kanal-ID für Server 1
const channelServer2Id = 'CHANNELID'; // Kanal-ID für Server 2
const birthdayUser = 'Benutzername'; // Hier den Benutzernamen des Geburtstagskindes einsetzen
const channel = message.channel; // Hier den Kanal angeben, in dem du die Nachricht senden möchtest
const currentDate = new Date();
const formattedDate = `${currentDate.getDate()}.${currentDate.getMonth() + 1}.${currentDate.getFullYear() % 100}`;
const rolleID = ''
cron.schedule('0 7 * * *', { timeZone: 'Europe/Berlin' }, async () => { //passe die gewünschte Zeitzone an.
try { // Führe die Funktion extractAndSaveData() aus, um den Sendeplan abzurufen und zu speichern
await extractAndSaveData(); console.log('Sendeplan erfolgreich abgerufen und gespeichert.');
// Führe die Funktion extractAndSendScheduleInfo() aus, um den Sendeplan zu verschicken
await extractAndSendScheduleInfo(message); // Stelle sicher, dass "message" korrekt definiert ist
console.log('Sendeplan erfolgreich verschickt.');
} catch (error) {
console.error('Fehler beim geplanten Ausführen der Aufgaben:', error);
}});
//Aufruf Client
client.once('ready', () => {
console.log('Bot is ready!');
createOnAirButton(channel, onAirRoleId);
checkStreamStatusServer1();
setInterval(checkStreamStatusServer1, 60000);
// Intervall für das Pingen und Senden von Statusnachrichten für Server 1
setInterval(() => {
pingStreamServer1(channelServer1Id);
}, pingInterval);
// Intervall für das Pingen und Senden von Statusnachrichten für Server 2
setInterval(() => {
pingStreamServer2(channelServer2Id);
}, pingInterval);
});
client.on('messageCreate', async message => {
if (message.author.bot) return;
// Überprüfen, ob die Nachricht mit dem Präfix beginnt
if (message.content.startsWith(prefix)) {
const args = message.content.slice(prefix.length).trim().split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'ping') {
// Führe die Ping-Funktion für Server 1 aus und sende die Statusnachricht
const pingMessage = await pingStreamServer1(channelServer1Id); // Hier die Kanal-ID für Server 1 einfügen
if (pingMessage && pingMessage.content) {
message.channel.send(pingMessage).then(msg => msg.delete()); // Nachricht senden und sofort löschen
}
// Führe die Ping-Funktion für Server 2 aus und sende die Statusnachricht
const pingMessage2 = await pingStreamServer2(channelServer2Id); // Hier die Kanal-ID für Server 2 einfügen
if (pingMessage2 && pingMessage2.content) {
message.channel.send(pingMessage2).then(msg => msg.delete()); // Nachricht senden und sofort löschen
}
// Nachricht, die den Befehl !ping enthält, löschen
message.delete(); // Lösche die ursprüngliche Nachricht
}
// Neuer Befehl !startExtract
if (command === 'startextract') {
try {
await extractAndSaveData();
message.channel.send('Datenextraktion erfolgreich abgeschlossen und gespeichert.');
} catch (error) {
console.error('Fehler beim manuellen Starten der Datenextraktion:', error);
message.channel.send('Fehler beim manuellen Starten der Datenextraktion.');
}
}
// Überprüfe, ob die Nachricht den Befehl "!plan" enthält
if (command === 'plan') {
try {
// Rufe die Funktion extractAndSendScheduleInfo() auf
await extractAndSendScheduleInfo(message);
message.channel.send('Befehl "!plan" wurde ausgeführt.');
} catch (error) {
console.error('Fehler beim Ausführen des Befehls "!plan":', error);
message.channel.send('Fehler beim Ausführen des Befehls "!plan".');
}
}
// Füge hier deine anderen Befehle und Logik hinzu
// ...
}
});
// Funktionen für Server 1
async function checkStreamStatusServer1() {
try {
// Holen der HTML-Seite von Server 1
const responseServer1 = await axios.get(streamURLServer1);
if (!responseServer1 || !responseServer1.data) {
console.error('Keine Daten von Server 1 erhalten oder ungültige Antwort.');
return;
}
// Extrahieren der Informationen aus dem HTML mit dem angegebenen CSS-Pfad
const server1Data = responseServer1.data;
// Hier verwenden wir cheerio, um den Moderator, Interpreten und Titel zu extrahieren
const $ = cheerio.load(server1Data);
const anchorElement = $('body > table:nth-child(4) > tbody > tr:nth-child(8) > td:nth-child(2) > b > a');
const text = anchorElement.text().trim();
// Überprüfung auf leere Werte
if (!text) {
console.error('Ungültige Werte für Nachricht auf Server 1.');
return;
}
// Extrahieren von Moderator, Interpret und Titel
let finalModerator = 'DBKS'; // Standardwert, falls der Trennstrich "|" nicht gefunden wird
let artist = '';
let title = '';
if (text.includes('|')) {
const [titleAndArtist, moderator] = text.split(' | ');
[artist, title] = titleAndArtist.split(' - ');
if (moderator) {
finalModerator = moderator;
}
} else {
[artist, title] = text.split(' - ');
}
// Überprüfen, ob Interpret und Titel vorhanden sind
if (!artist || !title) {
console.error('Ungültige Werte für Nachricht auf Server 1.');
// Fallback-Titel und Interpret, wenn keine gefunden werden
artist = 'XXX'; // Muss geändert werden
title = 'XXX'; // Muss geändert werden
// Fallback für Moderator, wenn kein Moderator nach dem | gefunden wird
if (text.includes('<a href="currentsong?sid=1">')) { /(/< Muss angepasst werden
finalModerator = text.split('<a href="currentsong?sid=1">')[1].split('</a>')[0]; //Muss angepasst werden
}
}
// Überprüfen, ob sich die Informationen geändert haben
if (lastPlayedTitle !== title || lastPlayedArtist !== artist) {
// Hier kannst du die gewonnenen Informationen verwenden
console.log('Moderator auf Server 1:', finalModerator);
console.log('Interpret auf Server 1:', artist);
console.log('Titel auf Server 1:', title);
// Erstelle ein Embed oder sende eine Nachricht mit den Informationen
const channelServer1 = client.channels.cache.get('1145840462826053652'); // Aktualisiere die Kanal-ID für Server 1
if (!channelServer1) {
console.error('Kanal für Server 1 nicht gefunden.');
return;
}
const embed = new MessageEmbed()
.setColor(0x00ff00)
.setDescription(`🎙️ Live ist **${finalModerator}!**\nGespielt wird *${title}* von *${artist}*.`);
if (!embed.description) {
console.error('Embed-Beschreibung ist leer.');
return;
}
channelServer1.send({ embeds: [embed] });
// Aktualisiere die zuletzt gespielten Informationen
lastPlayedTitle = title;
lastPlayedArtist = artist;
}
} catch (error) {
console.error('Fehler beim Überprüfen des Stream-Status auf Server 1:', error);
}
}
async function isServerOnline(serverURL) {
try {
const response = await axios.head(serverURL);
return response.status === 200; // Überprüft, ob der Server mit Statuscode 200 antwortet (OK)
} catch (error) {
console.error('Fehler beim Überprüfen des Serverstatus:', error);
return false; // Der Server wird als offline betrachtet, wenn eine Ausnahme auftritt
}
}
async function pingHTTPServer(serverURL) {
try {
const startTime = Date.now(); // Zeit vor dem Senden der Anfrage
await axios.get(serverURL);
const endTime = Date.now(); // Zeit nach dem Empfang der Antwort
const roundTripTime = endTime - startTime; // Berechnung der Round-Trip-Zeit in Millisekunden
return roundTripTime;
} catch (error) {
console.error('Fehler beim Pingen des HTTP-Servers:', error);
return -1; // Oder eine andere geeignete Fehlermeldung oder -1, um anzuzeigen, dass das Pingen fehlgeschlagen ist
}
}
function generateStatusMessage(serverName, onlineStatus, roundTripTime) {
let color;
if (onlineStatus) {
color = '#00ff00'; // Grüner Balken für Online
onlineStatus = 'Online';
} else {
color = '#ff0000'; // Roter Balken für Offline
onlineStatus = 'Offline';
}
// Hier können Sie Ihre Statusnachricht erstellen und zurückgeben
const embed = new MessageEmbed()
.setColor(color)
.setDescription(`**Server: ${serverName}**
Status: ${onlineStatus}
Ping: ${roundTripTime} ms`);
return { embeds: [embed] };
}
async function pingStreamServer1(channelId) {
try {
const roundTripTime = await pingHTTPServer(streamURLServer1); // Round-Trip-Zeit für Server 1 erhalten
const isServerOnlineResult = await isServerOnline(streamURLServer1);
console.log('Server 1 Online-Status:', isServerOnlineResult);
const channelServerStatus = client.channels.cache.get(channelId);
// Hier eine Statusnachricht generieren, ähnlich wie in checkStreamStatusServer1
const serverName = 'StreamServer'; // Setzen Sie den Namen Ihres Servers
const onlineStatus = isServerOnlineResult ? true : false; // Hier wird der Online-Status als boolescher Wert übergeben
const statusMessage = generateStatusMessage(serverName, onlineStatus, roundTripTime);
// Nachricht senden
channelServerStatus.send(statusMessage);
} catch (error) {
console.error('Fehler beim Pingen und Aktualisieren des Status auf Server 1:', error);
}
}
// Funktion pingStreamServer2, die die Funktion pingHTTPServer verwendet und automatisch Nachrichten sendet
async function pingStreamServer2(channelId) {
try {
const roundTripTime = await pingHTTPServer(streamURLServer2); // Round-Trip-Zeit für Server 2 erhalten
const isServerOnlineResult = await isServerOnline(streamURLServer2);
console.log('Server 2 Online-Status:', isServerOnlineResult);
const channelServerStatus = client.channels.cache.get(channelId);
// Hier eine Statusnachricht generieren, ähnlich wie in checkStreamStatusServer1
const serverName = 'ModServer'; // Setzen Sie den Namen Ihres Servers
const onlineStatus = isServerOnlineResult ? true : false; // Hier wird der Online-Status als boolescher Wert übergeben
const statusMessage = generateStatusMessage(serverName, onlineStatus, roundTripTime);
// Nachricht senden
channelServerStatus.send(statusMessage);
} catch (error) {
console.error('Fehler beim Pingen und Aktualisieren des Status auf Server 2:', error);
}
}
//Funktion zum Parsen der Uhrzeit und Umwandeln in Minuten seit Mitternacht
function parseTime(timeString) {
const [hours, minutes] = timeString.split(':').map(Number);
return hours * 60 + minutes;
}
// Funktion zum Extrahieren der Bild-URL für den Moderator
function extractModeratorImageUrl(htmlData, moderatorName) {
const $ = cheerio.load(htmlData);
const imgTags = $('img.img-responsive');
for (let i = 0; i < imgTags.length; i++) {
const imgTag = $(imgTags[i]);
const src = imgTag.attr('src');
const normalizedModeratorName = moderatorName
.replace(/[ö]/g, 'oe')
.replace(/[ü]/g, 'ue')
.replace(/[ä]/g, 'ae')
.toLowerCase()
.replace(/\s/g, ''); // Entferne Leerzeichen
if (src && src.toLowerCase().includes(normalizedModeratorName)) {
return src;
}
}
// Wenn kein Bild gefunden wurde, gib einen Standard-URL zurück
return ' XXX'; //Muss durch eine BildUrl ersetzt werden.
}
// Funktion zum Abrufen der HTML-Daten
async function fetchHTML() {
try {
const response = await axios.get(sendeplanUrl);
return response.data;
} catch (error) {
console.error('Fehler beim Abrufen der HTML-Daten:', error);
throw error;
}
}
// Hauptfunktion zum Extrahieren und Speichern der Daten
async function extractAndSaveData() {
try {
console.log('Die extractAndSaveData() - Funktion wird aufgerufen.');
// Hier startet der try-Block
const htmlData = await fetchHTML();
console.log('HTML-Daten erfolgreich abgerufen.');
const $ = cheerio.load(htmlData);
// Erstelle ein leeres Array, um die Daten zu speichern
const sendeplan = [];
// Durchlaufe die Tabellenzeilen und extrahiere die Informationen
$('tbody tr').each((index, element) => {
const row = $(element);
// Extrahiere die Zeit
const zeit = row.find('td:nth-child(1)').text().trim();
// Extrahiere die Beschreibung
const beschreibung = row.find('td:nth-child(2) a').text().trim();
// Extrahiere den Moderator
const moderator = row.find('td:nth-child(3)').text().trim();
// Überprüfe, ob es sich um ein Event handelt
const istEvent = row.hasClass('table-success');
// Füge die Daten dem sendeplan-Array hinzu
sendeplan.push({
zeit,
beschreibung,
moderator,
istEvent,
});
});
console.log('Daten erfolgreich extrahiert und in das sendeplan-Array eingefügt.');
console.log('Daten erfolgreich extrahiert und verarbeitet.');
// Speichere die Daten in einer JSON-Datei
fs.writeFileSync('PlanDaten.json', JSON.stringify(sendeplan, null, 2));
console.log('Daten erfolgreich in PlanDaten.json gespeichert.');
} catch (error) {
// Hier wird ein Fehler abgefangen, wenn er im try-Block auftritt
console.error('Fehler beim Extrahieren und Speichern der Daten:', error);
}
}
async function extractAndSendScheduleInfo(message, schedule) {
try {
// Pfad zur JSON-Datei festlegen
const jsonFilePath = 'PlanDaten.json';
// Überprüfen, ob die JSON-Datei existiert
if (!fs.existsSync(jsonFilePath)) {
console.error('Die JSON-Datei existiert nicht.');
message.channel.send('Die JSON-Datei existiert nicht.');
return;
}
// JSON-Datei lesen und Daten parsen
const jsonContent = fs.readFileSync(jsonFilePath, 'utf8');
const sendeplanData = JSON.parse(jsonContent);
// Überprüfen, ob die Sendeplaninformationen vorhanden und nicht leer sind
if (!sendeplanData || !Array.isArray(sendeplanData) || sendeplanData.length === 0) {
console.error('Ungültige oder leere Sendeplaninformationen.');
message.channel.send('Ungültige oder leere Sendeplaninformationen.');
return;
}
// Pfad zur HTML-Datei festlegen
const htmlFilePath = 'mod.html';
// HTML-Datei lesen und Inhalt in htmlData speichern
const htmlData = fs.readFileSync(htmlFilePath, 'utf8');
//Durch jeden Eintrag im Sendeplan iterieren und nur gültige Einträge senden
for (const entry of sendeplanData) {
if (entry.zeit && entry.beschreibung && entry.moderator) {
const { zeit, beschreibung, moderator, istEvent } = entry;
// Mod-Namen aus den Sendeplandaten und HTML in Kleinbuchstaben konvertieren
const modNameInSendeplan = moderator.toLowerCase();
const modNameInHtml = moderator.toLowerCase();
// Überprüfen, ob der erste Buchstabe des Mod-Namens in Kleinbuchstaben ist
const isFirstLetterLowerCase = modNameInHtml[0] === modNameInHtml[0].toLowerCase();
// Falls der erste Buchstabe in Kleinbuchstaben ist, konvertiere ihn in Großbuchstaben
const modNameInMessage = isFirstLetterLowerCase
? modNameInHtml.charAt(0).toUpperCase() + modNameInHtml.slice(1)
: modNameInHtml;
if (modNameInSendeplan === modNameInHtml) {
// Wenn sie übereinstimmen, extrahiere die Bild-URL
const moderatorImageUrl = extractModeratorImageUrl(htmlData, modNameInSendeplan);
const embed = new MessageEmbed()
.setTitle(`:radio: Sendeplan ${formattedDate} :radio:`)
.addFields(
{ name: 'Uhrzeit', value: zeit },
{ name: 'Moderator', value: modNameInMessage, inline: true }, // Hier den Mod-Namen in der Nachricht mit einem Großbuchstaben beginnend
{ name: 'Beschreibung', value: beschreibung },
{ name: 'Event', value: istEvent ? 'Ja' : 'Nein' }
)
.setImage(moderatorImageUrl)
.setFooter({ text: 'Anpassen' }); //Unbedingt anpassen
if (istEvent) {
embed.setColor('#00FF00');
}
const webhookClient = new WebhookClient({ url: webhookUrl });
await webhookClient.send({ embeds: [embed] });
console.log(`Sendeplan erfolgreich in Discord gepostet für Zeit: ${zeit}`);
}
}
}
console.log('Sendeplaninformationen wurden erfolgreich verarbeitet.');
} catch (error) {
console.error('Fehler beim Abrufen des Sendeplans oder Senden der Nachricht:', error);
}
}
// Funktion zum Überprüfen und Aktualisieren der OnAir-Rolle
async function toggleOnAirRole(user, channel, onAirRoleId) {
if (!user.bot) {
const member = channel.guild.members.cache.get(user.id);
if (member.roles.cache.has(onAirRoleId)) {
// Benutzer hat bereits die "OnAir"-Rolle, entferne sie
await member.roles.remove(onAirRoleId);
} else {
// Benutzer hat die "OnAir"-Rolle nicht, füge sie hinzu
await member.roles.add(onAirRoleId);
}
}
}
// Erstelle die "OnAir"-Schaltfläche
async function createOnAirButton(channel, onAirRoleId) {
const onAirMessage = await channel.send('Klicke auf das Symbol für die "OnAir" Anzeige! 🎙️');
await onAirMessage.react('🎙️');
const filter = (reaction, user) => reaction.emoji.name === '🎙️' && !user.bot;
const collector = onAirMessage.createReactionCollector({ filter, time: 60000 });
collector.on('collect', async (reaction, user) => {
await toggleOnAirRole(user, channel, onAirRoleId);
await reaction.users.remove(user.id);
});
}
function loadBirthdayData() {
try {
const data = fs.readFileSync(birthdayFilePath, 'utf8');
return JSON.parse(data);
} catch (error) {
console.error('Fehler beim Laden der Geburtstagsdaten:', error);
return {};
}
}
function calculateAge(birthdate) {
const today = new Date();
const birthDate = new Date(birthdate);
const age = today.getFullYear() - birthDate.getFullYear();
// Überprüfe, ob der Geburtstag dieses Jahr bereits stattgefunden hat
if (today < new Date(today.getFullYear(), birthDate.getMonth(), birthDate.getDate())) {
age--;
}
return age;
}
function calculateAge(birthdate) {
const today = new Date();
const birthDate = new Date(birthdate);
const age = today.getFullYear() - birthDate.getFullYear();
// Überprüfe, ob der Geburtstag dieses Jahr bereits stattgefunden hat
if (today < new Date(today.getFullYear(), birthDate.getMonth(), birthDate.getDate())) {
age--;
}
return age;
}
async function checkBirthdays() {
const today = new Date();
const currentDate = `${today.getMonth() + 1}-${today.getDate()}`; // Format: JJJJ-MM-DD
const birthdayData = loadBirthdayData(); // Stelle sicher, dass die Funktion `loadBirthdayData` definiert ist und die Geburtstagsdaten zurückgibt
for (const username in birthdayData) {
if (birthdayData.hasOwnProperty(username)) {
const birthdate = birthdayData[username];
if (birthdate === currentDate) {
const birthdayUser = client.users.cache.find((user) => user.username === username);
if (birthdayUser) {
const age = calculateAge(birthdate);
// Sende Geburtstagsnachricht in den Zielkanal
await sendBirthdayMessage(birthdayUser, username, age, channelId);
console.log(`Geburtstagsnachricht an ${birthdayUser.username} im Kanal gesendet.`);
}
}
}
}
}
async function sendBirthdayMessage(user, username, age, channelId) {
const birthdayEmbed = {
color: 0xffd700, // Goldene Farbe
title: `:birthday: Geburtstagsgrüße :birthday:`,
description: `Der Böse KiwiSound wünscht ${user} alles Gute zum Geburtstag! Du bist jetzt ${age} Jahre alt. :tada: :confetti_ball:`,
timestamp: new Date(),
footer: {
text: 'Powered by DBKS',
},
};
// Hier weise die spezielle Rolle zu, falls vorhanden
const guild = user.guild;
if (guild) {
const role = guild.roles.cache.get(roleId);
if (role) {
await user.roles.add(role);
}
}
// Hier sendest du die Nachricht in den Zielkanal
const channel = user.client.channels.cache.get(channelId);
if (channel && channel.type === "text") {
try {
await channel.send({ embed: birthdayEmbed });
console.log(`Geburtstagsnachricht an ${username} im Kanal gesendet.`);
} catch (error) {
console.error(`Fehler beim Senden der Geburtstagsnachricht an ${username}:`, error);
}
} else {
console.error(`Ungültiger Kanal oder Kanal nicht gefunden.`);
}
}
// Den Bot mit deinem Token anmelden (WICHTIG: Du musst die DATA.json-Datei füllen!)
client.login(discord_token);