plex-bot.js aktualisiert
This commit is contained in:
parent
ea34cc706d
commit
4da9acc842
462
plex-bot.js
462
plex-bot.js
@ -510,41 +510,6 @@ function updateEnvPassword(newPassword) {
|
||||
passwordChangeRequired = false; // Sperre aufheben, Login wieder möglich
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// /faq Befehl: Zeigt alle FAQs an
|
||||
bot.onText(/\/faq/, (msg) => {
|
||||
const chatId = msg.chat.id;
|
||||
@ -824,7 +789,6 @@ bot.on('callback_query', (query) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Verarbeite die Callback-Daten für die Bestätigung
|
||||
bot.on('callback_query', (query) => {
|
||||
const chatId = query.from.id; // Hier verwenden wir query.from.id, um die chatId zu erhalten
|
||||
@ -976,14 +940,6 @@ if (query.data.startsWith('change_email')) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Lade Abonnenten beim Start
|
||||
loadSubscribers();
|
||||
|
||||
@ -1098,6 +1054,9 @@ bot.onText(/\/profil/, (msg) => {
|
||||
nightModeText = '🌙 Nachtmodus: Nicht aktiv';
|
||||
}
|
||||
|
||||
// Anzahl der hinzugefügten Benutzer
|
||||
const addedUsersCount = user.addedUsers || 0; // Standard auf 0, falls nicht definiert
|
||||
|
||||
const profileMessage = `
|
||||
📝 *Profil Informationen:*\n\n
|
||||
👤 *Name:* @${userName}\n
|
||||
@ -1163,6 +1122,7 @@ ${nightModeText}\n
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Callback query handler for profile editing
|
||||
bot.on('callback_query', (callbackQuery) => {
|
||||
const action = callbackQuery.data;
|
||||
@ -1484,6 +1444,7 @@ bot.on('message', (msg) => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Befehl zum Sichern der Dateien
|
||||
bot.onText(/\/backup/, (msg) => {
|
||||
const chatId = msg.chat.id;
|
||||
@ -1774,8 +1735,8 @@ bot.onText(/\/bot/, (msg) => {
|
||||
// Logik für den Befehl...
|
||||
});
|
||||
|
||||
bot.onText(/\/admin/, (msg) => {
|
||||
logCommand('/admin', msg.from.username);
|
||||
bot.onText(/\/msg/, (msg) => {
|
||||
logCommand('/msg', msg.from.username);
|
||||
// Logik für den Befehl...
|
||||
});
|
||||
|
||||
@ -1864,6 +1825,11 @@ bot.onText(/\/key/, (msg) => {
|
||||
// Logik für den Befehl...
|
||||
});
|
||||
|
||||
bot.onText(/\/pause/, (msg) => {
|
||||
logCommand('/pause', msg.from.username);
|
||||
// Logik für den Befehl...
|
||||
});
|
||||
|
||||
|
||||
const userId1 = Number(process.env.USER1_ID); // USER1_ID aus .env laden und in Zahl umwandeln
|
||||
const userId2 = Number(process.env.USER2_ID); // USER2_ID aus .env laden und in Zahl umwandeln
|
||||
@ -1934,31 +1900,8 @@ bot.onText(/\/support/, (msg) => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Handler für den /admin-Befehl
|
||||
bot.onText(/\/admin/, (msg) => {
|
||||
// Handler für den /msg-Befehl
|
||||
bot.onText(/\/msg/, (msg) => {
|
||||
const chatId = msg.chat.id;
|
||||
const userId = msg.from.id;
|
||||
|
||||
@ -1973,18 +1916,51 @@ bot.onText(/\/admin/, (msg) => {
|
||||
if (msg.chat.id === chatId && msg.text) {
|
||||
const messageText = msg.text;
|
||||
|
||||
// Sende die Nachricht an alle Benutzer
|
||||
const users = yaml.load(USER_YML_PATH);
|
||||
const sendMessages = Object.keys(users).map(userChatId => {
|
||||
return bot.sendMessage(userChatId, `❗️Systemnachricht\n\n"${messageText}"`).catch(error => {
|
||||
logError(`Fehler beim Senden der Systemnachricht an chatId ${userChatId}: ${error.message}`);
|
||||
// Frage den Benutzer, ob er ein Bild hinzufügen möchte
|
||||
bot.sendMessage(chatId, 'Möchtest du ein Bild hinzufügen? (ja/nein)').then(() => {
|
||||
bot.once('message', async (responseMsg) => {
|
||||
if (responseMsg.chat.id === chatId) {
|
||||
const addImage = responseMsg.text.toLowerCase();
|
||||
|
||||
if (addImage === 'ja') {
|
||||
bot.sendMessage(chatId, 'Bitte sende das Bild, das du an alle Benutzer senden möchtest:').then(() => {
|
||||
bot.once('photo', async (photoMsg) => {
|
||||
const photoId = photoMsg.photo[photoMsg.photo.length - 1].file_id; // Nimm das höchste Auflösungsbild
|
||||
const users = yaml.load(USER_YML_PATH);
|
||||
const sendMessages = Object.keys(users).map(userChatId => {
|
||||
return bot.sendPhoto(userChatId, photoId, {
|
||||
caption: `❗️Systemnachricht\n\n"${messageText}"`
|
||||
}).catch(error => {
|
||||
logError(`Fehler beim Senden der Systemnachricht an chatId ${userChatId}: ${error.message}`);
|
||||
});
|
||||
}).filter(promise => promise !== undefined);
|
||||
|
||||
await Promise.all(sendMessages);
|
||||
bot.sendMessage(chatId, 'Nachricht mit Bild wurde an alle Benutzer gesendet.').catch(error => {
|
||||
logError(`Fehler beim Senden der Bestätigung an chatId ${chatId}: ${error.message}`);
|
||||
});
|
||||
});
|
||||
}).catch(error => {
|
||||
logError(`Fehler beim Senden der Bildanforderung an chatId ${chatId}: ${error.message}`);
|
||||
});
|
||||
} else {
|
||||
// Sende nur die Textnachricht an alle Benutzer
|
||||
const users = yaml.load(USER_YML_PATH);
|
||||
const sendMessages = Object.keys(users).map(userChatId => {
|
||||
return bot.sendMessage(userChatId, `❗️Systemnachricht\n\n"${messageText}"`).catch(error => {
|
||||
logError(`Fehler beim Senden der Systemnachricht an chatId ${userChatId}: ${error.message}`);
|
||||
});
|
||||
}).filter(promise => promise !== undefined);
|
||||
|
||||
await Promise.all(sendMessages);
|
||||
bot.sendMessage(chatId, 'Nachricht wurde an alle Benutzer gesendet.').catch(error => {
|
||||
logError(`Fehler beim Senden der Bestätigung an chatId ${chatId}: ${error.message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}).filter(promise => promise !== undefined);
|
||||
|
||||
await Promise.all(sendMessages);
|
||||
|
||||
bot.sendMessage(chatId, 'Nachricht wurde an alle Benutzer gesendet.').catch(error => {
|
||||
logError(`Fehler beim Senden der Bestätigung an chatId ${chatId}: ${error.message}`);
|
||||
}).catch(error => {
|
||||
logError(`Fehler beim Senden der Bildanfrage an chatId ${chatId}: ${error.message}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -2889,9 +2865,21 @@ bot.onText(/\/latestmovie/, async (msg) => {
|
||||
|
||||
// Bild anzeigen, wenn vorhanden
|
||||
if (movieThumb) {
|
||||
bot.sendPhoto(chatId, movieThumb, { caption: message, reply_markup: replyMarkup }).catch(error => {
|
||||
logError(`Error sending photo to chatId ${chatId}: ${error.message}`);
|
||||
});
|
||||
try {
|
||||
const response = await axios.get(movieThumb, { responseType: 'arraybuffer' });
|
||||
const imagePath = path.join(__dirname, 'temp_image.jpg');
|
||||
fs.writeFileSync(imagePath, response.data);
|
||||
|
||||
await bot.sendPhoto(chatId, imagePath, {
|
||||
caption: message,
|
||||
reply_markup: replyMarkup
|
||||
});
|
||||
|
||||
fs.unlinkSync(imagePath); // Lösche das temporäre Bild nach dem Senden
|
||||
} catch (error) {
|
||||
logError(`Error downloading or sending image: ${error.message}`);
|
||||
bot.sendMessage(chatId, message, { reply_markup: replyMarkup });
|
||||
}
|
||||
} else {
|
||||
bot.sendMessage(chatId, message, { reply_markup: replyMarkup }).catch(error => {
|
||||
logError(`Error sending message to chatId ${chatId}: ${error.message}`);
|
||||
@ -2954,8 +2942,8 @@ bot.onText(/\/info/, async (msg) => {
|
||||
`🎞️ Episoden: ${episodeCount}\n\n` +
|
||||
`📚 Staffeln: ${seasonCount}\n\n\n` +
|
||||
`📊 Top-Genre: ${topGenre}\n\n` +
|
||||
`💾 Gesamtgröße-Filme: ${totalSize}\n\n` +
|
||||
`💾 Gesamtgröße-Serien: 1.70TB\n\n\n` +
|
||||
`💾 Gesamtgröße-Filme: 4.74TB\n\n` +
|
||||
`💾 Gesamtgröße-Serien: 5.46TB\n\n\n` +
|
||||
`⏳ Ältester Film: ${oldestMovie.title} (${oldestMovie.year})\n\n` +
|
||||
`🆕 Neuester Film: ${newestMovie.title} (${newestMovie.year})\n\n\n` +
|
||||
`© 2024 M_Viper`;
|
||||
@ -3196,6 +3184,20 @@ async function fetchPlexData(url) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const usersNightMode = {}; // Temporärer Speicher für Nachtmodus
|
||||
|
||||
// Funktion zum Laden der Benutzerdaten aus der user.yml
|
||||
@ -3494,6 +3496,12 @@ setInterval(() => {
|
||||
activateNightMode();
|
||||
}, 60 * 1000); // Überprüfung alle 60 Sekunden
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Funktion zum Erstellen der Datei 'w_offen.json' im Hauptverzeichnis, falls sie noch nicht existiert
|
||||
function ensureWOffenFileExists() {
|
||||
const filePath = path.join(__dirname, 'w_offen.json'); // Hauptverzeichnis
|
||||
@ -4405,7 +4413,8 @@ function createHelpMessage() {
|
||||
`🎬 /trailer - Fordere einen Trailer für einen bestimmten Film an. \n\n` +
|
||||
`🔝 /empfehlung - Film Empfehlung des Tages.\n\n` +
|
||||
`📰 /newsletter - zeigt die Newsletter Funktion an\n\n` +
|
||||
`🌙 /night - Schaltet den Nachtmodus ein oder aus.\n\n` + // Hinzugefügter Befehl
|
||||
`🌙 /night - Schaltet den Nachtmodus ein oder aus.\n\n` +
|
||||
`⏸️ /pause - Pausiert die Benachrichtigungen.\n\n` +
|
||||
`❓ /help - Zeigt diese Hilfennachricht an.\n\n`;
|
||||
}
|
||||
|
||||
@ -4425,7 +4434,7 @@ function createMoreHelpMessage() {
|
||||
// Funktion zum Erstellen der Admin-Hilfennachricht
|
||||
function createAdminHelpMessage() {
|
||||
return `*👨💻 Admin Befehle* \n\n` +
|
||||
`🛠️ /admin - sendet eine Nachricht an alle Nutzer.\n\n` +
|
||||
`🛠️ /msg - sendet eine Nachricht an alle Nutzer.\n\n` +
|
||||
`🔒 /passwd - gibt dir das Aktuelle Passwort vom Frontend\n\n` +
|
||||
`✨ /open\\_wishes - Zeigt alle offenen Wünsche an\n\n` +
|
||||
`👤 /user - Zeigt Benutzerinformationen an.\n\n` +
|
||||
@ -4582,6 +4591,224 @@ bot.on('callback_query', (callbackQuery) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const pauseDurations = [
|
||||
{ text: '🕔 5 Minuten', value: 5 * 60 * 1000 },
|
||||
{ text: '🕙 10 Minuten', value: 10 * 60 * 1000 },
|
||||
{ text: '🕕 15 Minuten', value: 15 * 60 * 1000 },
|
||||
{ text: '🕧 30 Minuten', value: 30 * 60 * 1000 },
|
||||
{ text: '🕐 1 Stunde', value: 1 * 60 * 60 * 1000 },
|
||||
{ text: '🕑 2 Stunden', value: 2 * 60 * 60 * 1000 },
|
||||
{ text: '🕒 4 Stunden', value: 4 * 60 * 60 * 1000 },
|
||||
{ text: '🕓 8 Stunden', value: 8 * 60 * 60 * 1000 },
|
||||
{ text: '🕔 12 Stunden', value: 12 * 60 * 60 * 1000 },
|
||||
{ text: '🕛 24 Stunden', value: 24 * 60 * 60 * 1000 },
|
||||
];
|
||||
|
||||
// Funktion zum Laden der Benutzerdaten aus der user.yml
|
||||
function loadUserData() {
|
||||
if (!fs.existsSync(USER_YML_PATH)) {
|
||||
fs.writeFileSync(USER_YML_PATH, yaml.stringify({}));
|
||||
}
|
||||
return yaml.load(USER_YML_PATH);
|
||||
}
|
||||
|
||||
// Funktion zum Speichern der Benutzerdaten in die user.yml
|
||||
function saveUserData(userData) {
|
||||
fs.writeFileSync(USER_YML_PATH, yaml.stringify(userData, 4));
|
||||
}
|
||||
|
||||
// Funktion zur Überprüfung, ob der Nachtmodus aktiv ist
|
||||
function isNightModeActive(userId) {
|
||||
const userData = loadUserData();
|
||||
const user = userData[userId];
|
||||
|
||||
if (!user || !user.nightModes) return false;
|
||||
|
||||
const currentTime = new Date();
|
||||
const currentMinutes = currentTime.getHours() * 60 + currentTime.getMinutes();
|
||||
|
||||
function timeToMinutes(time) {
|
||||
const [hours, minutes] = time.split(':').map(Number);
|
||||
return hours * 60 + minutes;
|
||||
}
|
||||
|
||||
return user.nightModes.some(nightMode => {
|
||||
const startMinutes = timeToMinutes(nightMode.startTime);
|
||||
const endMinutes = timeToMinutes(nightMode.endTime);
|
||||
|
||||
if (startMinutes < endMinutes) {
|
||||
return currentMinutes >= startMinutes && currentMinutes < endMinutes;
|
||||
} else {
|
||||
return currentMinutes >= startMinutes || currentMinutes < endMinutes;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// /pause Befehl
|
||||
bot.onText(/\/pause/, (msg) => {
|
||||
const chatId = msg.chat.id;
|
||||
const userId = chatId.toString();
|
||||
|
||||
// Nachtmodus-Überprüfung
|
||||
if (isNightModeActive(userId)) {
|
||||
bot.sendMessage(chatId, '⚠️ Der Nachtmodus ist aktiv. Der /pause-Befehl ist zurzeit deaktiviert.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Inline-Buttons für den /pause-Befehl
|
||||
const buttons = [
|
||||
[
|
||||
{ text: '▶️ Pause beginnen', callback_data: 'start_pause' },
|
||||
{ text: '⏹️ Pause vorzeitig beenden', callback_data: 'end_pause' },
|
||||
],
|
||||
];
|
||||
|
||||
bot.sendMessage(chatId, '🔧 Wählen Sie eine Option:', {
|
||||
reply_markup: {
|
||||
inline_keyboard: buttons,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Callback-Query-Handler für die Inline-Buttons
|
||||
bot.on('callback_query', async (query) => {
|
||||
const chatId = query.message.chat.id;
|
||||
const userId = chatId.toString();
|
||||
const userData = loadUserData();
|
||||
|
||||
userData[userId] = userData[userId] || { notifications: true };
|
||||
|
||||
if (query.data === 'start_pause') {
|
||||
const durationButtons = [];
|
||||
for (let i = 0; i < pauseDurations.length; i += 3) {
|
||||
const buttonGroup = pauseDurations.slice(i, i + 3).map(duration => ({
|
||||
text: duration.text,
|
||||
callback_data: `pause_${duration.value}`,
|
||||
}));
|
||||
durationButtons.push(buttonGroup);
|
||||
}
|
||||
|
||||
durationButtons.push([{ text: '⌛️ Eigene Zeit angeben', callback_data: 'custom_time' }]);
|
||||
|
||||
bot.sendMessage(chatId, '⏳ Bitte wählen Sie die Dauer für die Benachrichtigungspause:', {
|
||||
reply_markup: {
|
||||
inline_keyboard: durationButtons,
|
||||
},
|
||||
});
|
||||
} else if (query.data.startsWith('pause_')) {
|
||||
const pauseDuration = parseInt(query.data.split('_')[1], 10);
|
||||
|
||||
userData[userId].pausedUntil = Date.now() + pauseDuration;
|
||||
userData[userId].notifications = false;
|
||||
|
||||
saveUserData(userData);
|
||||
|
||||
bot.sendMessage(chatId, `✅ Benachrichtigungen wurden für ${pauseDuration / (60 * 1000)} Minuten pausiert.`);
|
||||
|
||||
setTimeout(() => {
|
||||
userData[userId].pausedUntil = undefined;
|
||||
userData[userId].notifications = true;
|
||||
saveUserData(userData);
|
||||
bot.sendMessage(chatId, '🔔 Benachrichtigungen sind jetzt wieder aktiviert.');
|
||||
}, pauseDuration);
|
||||
} else if (query.data === 'end_pause') {
|
||||
userData[userId].pausedUntil = undefined;
|
||||
userData[userId].notifications = true;
|
||||
saveUserData(userData);
|
||||
bot.sendMessage(chatId, '🔔 Benachrichtigungen sind jetzt wieder aktiviert.');
|
||||
} else if (query.data === 'custom_time') {
|
||||
bot.sendMessage(chatId, '⏳ Bitte geben Sie die Pause in Minuten an (z.B. 10 für 10 Minuten):');
|
||||
bot.once('message', async (msg) => {
|
||||
if (msg.chat.id === chatId) {
|
||||
const customTime = parseInt(msg.text, 10);
|
||||
if (!isNaN(customTime) && customTime > 0) {
|
||||
const pauseDuration = customTime * 60 * 1000;
|
||||
userData[userId].pausedUntil = Date.now() + pauseDuration;
|
||||
userData[userId].notifications = false;
|
||||
|
||||
saveUserData(userData);
|
||||
|
||||
bot.sendMessage(chatId, `✅ Benachrichtigungen wurden für ${customTime} Minuten pausiert.`);
|
||||
|
||||
setTimeout(() => {
|
||||
userData[userId].pausedUntil = undefined;
|
||||
userData[userId].notifications = true;
|
||||
saveUserData(userData);
|
||||
bot.sendMessage(chatId, '🔔 Benachrichtigungen sind jetzt wieder aktiviert.');
|
||||
}, pauseDuration);
|
||||
} else {
|
||||
bot.sendMessage(chatId, '⚠️ Bitte geben Sie eine gültige Zahl ein.');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Funktion zum Abrufen der letzten 10 hinzugefügten Filme
|
||||
async function fetchLatest10Movies() {
|
||||
try {
|
||||
@ -4718,10 +4945,10 @@ bot.onText(/\/latest10movies/, async (msg) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
//Anfang für Frontend
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
// schnittstelle für Kontakt.html
|
||||
app.get('/api/contact-info', (req, res) => {
|
||||
res.json({
|
||||
@ -4800,7 +5027,6 @@ app.get('/api/latest-movies', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
app.get('/api/telegram-link', (req, res) => {
|
||||
res.json({ link: process.env.TELEGRAM_LINK }); // Stelle den Link aus der .env bereit
|
||||
});
|
||||
@ -5036,14 +5262,6 @@ app.get('/api/feedback', (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Endpunkt /api/users, um die user.yml-Datei zu lesen und die Daten im JSON-Format zurückzugeben
|
||||
app.get('/api/users', (req, res) => {
|
||||
try {
|
||||
@ -5118,8 +5336,6 @@ app.get('/api/last-restart', (req, res) => {
|
||||
// Beispiel: Rufe die Funktion auf, wenn der Bot neu gestartet wird
|
||||
onBotRestart();
|
||||
|
||||
|
||||
|
||||
app.post('/api/send-message', async (req, res) => {
|
||||
const { message } = req.body;
|
||||
|
||||
@ -5319,31 +5535,6 @@ app.post('/api/download-backup', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// API-Endpunkt zum Abrufen der Entwicklerberichte
|
||||
app.get('/api/dev-reports', (req, res) => {
|
||||
try {
|
||||
@ -5434,30 +5625,13 @@ function sendToTelegram(report) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Ende Frontend
|
||||
|
||||
|
||||
|
||||
|
||||
/// Definition der logDebug-Funktion
|
||||
function logDebug(message) {
|
||||
console.log(`${new Date().toISOString()} - DEBUG: ${message}`);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Express-Server starten
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Webhook server running on port ${PORT}`);
|
||||
|
Loading…
x
Reference in New Issue
Block a user