Plex-Telegram-Bot/plex-bot.js

5495 lines
197 KiB
JavaScript
Raw Normal View History

2024-10-17 22:46:38 +00:00
require('dotenv').config();
const TelegramBot = require('node-telegram-bot-api');
const axios = require('axios');
const fs = require('fs');
const yaml = require('yamljs');
const path = require('path');
const dayjs = require('dayjs');
const dayOfYear = require('dayjs/plugin/dayOfYear');
const express = require('express');
const bodyParser = require('body-parser');
const NodeCache = require('node-cache');
const schedule = require('node-schedule');
const moment = require('moment');
const nodemailer = require('nodemailer');
const { scheduleJob } = require('node-schedule');
const { format } = require('date-fns');
const archiver = require('archiver');
2024-10-20 20:09:31 +00:00
2024-10-17 22:46:38 +00:00
const today = format(new Date(), 'yyyy-MM-dd');
console.log(today); // Sollte das aktuelle Datum im Format yyyy-MM-dd ausgeben
const CacheDir = path.join(__dirname, 'Cache');
const cacheFilePath = path.join(CacheDir, 'cache.json');
// Setze PROJECT_ROOT auf das aktuelle Verzeichnis
const PROJECT_ROOT = __dirname;
// Konstanten aus .env-Datei
const BOT_TOKEN = process.env.BOT_TOKEN;
const PLEX_TOKEN = process.env.PLEX_TOKEN;
const PLEX_DOMAIN = process.env.PLEX_DOMAIN;
const PLEX_LIBRARY_URL = `${PLEX_DOMAIN}/library/sections/all?X-Plex-Token=${PLEX_TOKEN}`;
const USER_YML_PATH = path.resolve(PROJECT_ROOT, process.env.USER_YML_PATH);
const LOG_DIR = path.resolve(PROJECT_ROOT, process.env.LOG_DIR);
const ERROR_LOG_PATH = path.resolve(LOG_DIR, process.env.ERROR_LOG_PATH);
const PORT = process.env.PORT;
const USER1_ID = process.env.USER1_ID;
const USER2_ID = process.env.USER2_ID;
const WEBHOOK_URL = process.env.WEBHOOK_URL;
const AUTHORIZED_USER_ID = process.env.AUTHORIZED_USER_ID;
const errorLogPath = process.env.ERROR_LOG_PATH;
// Debug-Ausgaben für Pfade
console.log('USER_YML_PATH:', USER_YML_PATH);
console.log('LOG_DIR:', LOG_DIR);
console.log('ERROR_LOG_PATH:', ERROR_LOG_PATH);
// Sicherstellen, dass Verzeichnisse und Dateien existieren
if (!fs.existsSync(LOG_DIR)) {
fs.mkdirSync(LOG_DIR, { recursive: true });
}
if (!fs.existsSync(USER_YML_PATH)) {
fs.writeFileSync(USER_YML_PATH, yaml.stringify({}, 4));
}
if (!fs.existsSync(ERROR_LOG_PATH)) {
fs.writeFileSync(ERROR_LOG_PATH, ''); // Leere Datei erstellen
}
// Erstelle den Cache-Ordner, falls er nicht existiert
if (!fs.existsSync(CacheDir)) {
fs.mkdirSync(CacheDir);
}
// Initialisiere den Cache mit einer bestimmten Lebensdauer (TTL) von 1 Stunde
const cache = new NodeCache({ stdTTL: 3600 });
// Funktion zum Speichern des Caches in eine Datei
function saveCacheToFile() {
const cacheData = cache.keys().reduce((acc, key) => {
acc[key] = cache.get(key);
return acc;
}, {});
fs.writeFileSync(cacheFilePath, JSON.stringify(cacheData));
}
// Funktion zum Laden des Caches aus einer Datei
function loadCacheFromFile() {
if (fs.existsSync(cacheFilePath)) {
const cacheData = JSON.parse(fs.readFileSync(cacheFilePath));
for (const [key, value] of Object.entries(cacheData)) {
cache.set(key, value);
}
}
}
// Funktion zum Abrufen von Plex-Daten
async function fetchPlexData(url) {
try {
const response = await axios.get(url, {
headers: {
'X-Plex-Token': PLEX_TOKEN
}
});
return response.data;
} catch (error) {
logError(`Error fetching Plex data: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen aller Filme
async function fetchAllMovies() {
try {
const sectionsData = await fetchPlexData(PLEX_LIBRARY_URL);
const sections = sectionsData.MediaContainer.Directory;
let movies = [];
for (const section of sections) {
const sectionUrl = `${PLEX_DOMAIN}/library/sections/${section.key}/all?X-Plex-Token=${PLEX_TOKEN}`;
const sectionData = await fetchPlexData(sectionUrl);
if (sectionData.MediaContainer && sectionData.MediaContainer.Metadata) {
const metadata = sectionData.MediaContainer.Metadata;
movies = movies.concat(metadata.filter(media => media.type === 'movie'));
}
}
movies.sort((a, b) => (b.addedAt || 0) - (a.addedAt || 0));
return movies;
} catch (error) {
logError(`Error fetching all movies: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen der Filme mit Caching
async function fetchMoviesWithCache() {
const cacheKey = 'allMovies';
const cachedMovies = cache.get(cacheKey);
if (cachedMovies) {
logMessage('Movies fetched from cache');
return cachedMovies;
}
try {
const movies = await fetchAllMovies();
cache.set(cacheKey, movies);
logMessage('Movies fetched from API and cached');
return movies;
} catch (error) {
logError(`Error fetching movies: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen eines zufälligen Films mit Caching
async function fetchRandomMovie() {
try {
const movies = await fetchMoviesWithCache();
if (movies.length === 0) return null;
const randomIndex = Math.floor(Math.random() * movies.length);
return movies[randomIndex];
} catch (error) {
logError(`Error fetching random movie: ${error.message}`);
throw error;
}
}
// Funktion zum Durchführen der Filmsuche mit Caching
async function searchMovies(query) {
try {
const movies = await fetchMoviesWithCache();
const results = movies.filter(movie =>
movie.title.toLowerCase().includes(query.toLowerCase())
);
return results;
} catch (error) {
logError(`Error searching movies: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen der gut bewerteten Filme mit Caching
async function fetchTopRatedMovies() {
try {
const movies = await fetchMoviesWithCache();
const ratedMovies = movies.filter(movie => movie.rating && movie.rating > 0);
ratedMovies.sort((a, b) => (b.rating || 0) - (a.rating || 0));
return ratedMovies;
} catch (error) {
logError(`Error fetching top-rated movies: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen des Films des Tages mit Caching
async function fetchDailyRecommendation() {
try {
const ratedMovies = await fetchTopRatedMovies();
if (ratedMovies.length === 0) return null;
dayjs.extend(dayOfYear); // Füge das Plugin hier hinzu
const dayOfYear = dayjs().dayOfYear();
const todayIndex = dayOfYear % ratedMovies.length;
return ratedMovies[todayIndex];
} catch (error) {
logError(`Error fetching daily recommendation: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen der letzten 10 hinzugefügten Filme mit Caching
async function fetchLatest10Movies() {
try {
const movies = await fetchMoviesWithCache();
const sortedMovies = movies
.filter(movie => movie.addedAt)
.sort((a, b) => b.addedAt - a.addedAt)
.slice(0, 10);
return sortedMovies;
} catch (error) {
logError(`Error fetching latest 10 movies: ${error.message}`);
throw error;
}
}
// Funktion zum automatischen Aktualisieren des Caches
async function updateCache() {
try {
await fetchMoviesWithCache(); // Stellt sicher, dass der Cache aktualisiert wird
logMessage('Cache wurde automatisch aktualisiert');
} catch (error) {
logError(`Fehler beim automatischen Aktualisieren des Caches: ${error.message}`);
}
}
// Lade den Cache beim Start
(async function start() {
try {
await fetchMoviesWithCache(); // Initialisiert den Cache beim Start
logMessage('Cache beim Start initialisiert');
// Speicher den Cache regelmäßig (z.B. jede Stunde)
schedule.scheduleJob('0 * * * *', saveCacheToFile);
// Plane die automatische Aktualisierung des Caches jede Stunde
schedule.scheduleJob('0 * * * *', updateCache);
// Beispiel für die Verwendung von node-schedule
function checkForNewMovies() {
// Hier könntest du eine Funktion zum Überprüfen neuer Filme einfügen
console.log('Checking for new movies...');
}
// Beispiel für geplante Aufgaben
schedule.scheduleJob('*/1 * * * *', checkForNewMovies);
} catch (error) {
logError(`Fehler beim Start des Bots: ${error.message}`);
}
})();
// Telegram-Bot-Instanz erstellen
const bot = new TelegramBot(BOT_TOKEN, { polling: true });
// Express-Server für Webhooks
const app = express();
app.use(bodyParser.json());
// Funktion zum Protokollieren von allgemeinen Nachrichten
function logMessage(message) {
const today = dayjs().format('YYYY-MM-DD');
const logFilePath = path.join(LOG_DIR, `${today}.log`);
fs.appendFileSync(logFilePath, `${dayjs().format('HH:mm:ss')} - ${message}\n`);
}
// Funktion zur Fehlerprotokollierung
function logError(error) {
const errorMessage = `${dayjs().format('HH:mm:ss')} - Error: ${error}\n`;
fs.appendFileSync(ERROR_LOG_PATH, errorMessage);
}
const faqFilePath = path.join(__dirname, 'faq.json'); // Pfad zur faq.json im Hauptverzeichnis
const authorizedUsers = [USER1_ID, USER2_ID];
// Funktion zum Laden der FAQs
function loadFaqs() {
if (!fs.existsSync(faqFilePath)) {
fs.writeFileSync(faqFilePath, JSON.stringify([])); // Leere Datei erstellen, wenn sie nicht existiert
}
const faqs = JSON.parse(fs.readFileSync(faqFilePath));
return faqs;
}
// Funktion zum Speichern der FAQs
function saveFaqs(faqs) {
fs.writeFileSync(faqFilePath, JSON.stringify(faqs, null, 2));
}
2024-10-18 23:49:19 +00:00
2024-10-17 22:46:38 +00:00
// Befehl zum Abrufen von Trailern
bot.onText(/\/trailer/, (msg) => {
const chatId = msg.chat.id;
// Nach dem Filmtitel fragen
bot.sendMessage(chatId, 'Bitte geben Sie den Titel des Films ein:');
// Auf die nächste Nachricht warten, die den Filmnamen enthält
bot.once('message', async (msg) => {
const filmTitle = msg.text;
try {
// YouTube API URL für die Suche
const url = `https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&q=${encodeURIComponent(filmTitle + ' trailer')}&key=${process.env.YOUTUBE_API_KEY}`;
const response = await axios.get(url);
const videos = response.data.items;
// Überprüfen, ob Videos gefunden wurden
if (videos.length > 0) {
const videoId = videos[0].id.videoId; // ID des ersten gefundenen Trailers
const trailerUrl = `https://www.youtube.com/watch?v=${videoId}`;
const reply = `Hier ist der Trailer für "${filmTitle}": ${trailerUrl}`;
bot.sendMessage(chatId, reply);
} else {
bot.sendMessage(chatId, `Leider konnte ich keinen Trailer für "${filmTitle}" finden.`);
}
} catch (error) {
console.error('Fehler beim Abrufen des Trailers:', error);
bot.sendMessage(chatId, 'Es gab ein Problem beim Abrufen des Trailers. Bitte versuche es später erneut.');
}
});
});
// Globale Variable zum Zählen der Passwortanforderungen
let passwordRequestCount = 0;
let passwordChangeRequired = false; // Sperrt Login, wenn Passwortänderung nötig ist
let newPassword = ''; // Speichert das neue Passwort
bot.onText(/\/passwd/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id.toString();
// Überprüfen, ob das Passwort geändert werden muss
if (passwordChangeRequired) {
const reply = `⚠️ Der Befehl /passwd ist zurzeit nicht verfügbar! Der Zugang wurde gesperrt bitte wenden dich an den Admin.`;
bot.sendMessage(chatId, reply, { parse_mode: 'HTML' });
return; // Beende die Ausführung, wenn das Passwort geändert werden muss
}
if (authorizedUsers.includes(userId)) {
// Zähler für Passwortanforderungen erhöhen
passwordRequestCount++;
// Wenn die Anzahl der Anfragen 10 erreicht, muss das Passwort geändert werden
if (passwordRequestCount >= 10) {
newPassword = generateRandomPassword(); // Zufälliges sicheres Passwort generieren
updateEnvPassword(newPassword); // Neues Passwort in der .env speichern
const changePwMessage = `⚠️ Du hast das Passwort zu oft angefordert. Der Zugang wurde gesperrt.`;
bot.sendMessage(chatId, changePwMessage, {
parse_mode: 'HTML',
protect_content: true,
}).then((sentMessage) => {
setTimeout(() => {
bot.deleteMessage(chatId, sentMessage.message_id).catch((err) => {
console.error('Fehler beim Löschen der Nachricht:', err);
});
}, 30000); // 30 Sekunden
});
// Zähler zurücksetzen und Sperre aktivieren
passwordRequestCount = 0;
passwordChangeRequired = true; // Passwort muss geändert werden
return; // Beende die Ausführung, um das alte Passwort nicht mehr zu senden
}
// Passwort aus der .env-Datei holen
const password = process.env.ADMIN_PW;
const reply = `🔒 Das Passwort für den Adminbereich lautet:\n\n<span class="tg-spoiler">${password}</span>\n\n‼️<em>Hinweis:‼\n</em> Diese Nachricht wird automatisch in 30 Sekunden gelöscht.`;
bot.sendMessage(chatId, reply, {
parse_mode: 'HTML',
protect_content: true, // Inhalt schützen
}).then((sentMessage) => {
setTimeout(() => {
bot.deleteMessage(chatId, sentMessage.message_id).catch((err) => {
console.error('Fehler beim Löschen der Antwortnachricht:', err);
});
}, 30000); // 30 Sekunden
});
setTimeout(() => {
bot.deleteMessage(chatId, msg.message_id).catch((err) => {
console.error('Fehler beim Löschen der ursprünglichen Nachricht:', err);
});
}, 30000); // 30 Sekunden
// Nachricht an den Dev senden
const devMessage = `🔒 Das Passwort für den Adminbereich wurde angefordert von:\n\n👤 <strong>@${msg.from.username}</strong>\n\n🆔 ID: <strong>${userId}</strong>\n\n📅 Datum: <strong>${new Date().toLocaleDateString('de-DE')}</strong>\n\n🕒 Uhrzeit: <strong>${new Date().toLocaleTimeString('de-DE')}</strong>`;
bot.sendMessage(process.env.DEV_CHAT_ID, devMessage, { parse_mode: 'HTML' }).catch((err) => {
console.error('Fehler beim Senden der Dev-Nachricht:', err);
});
} else {
const reply = `🚫 Zugriff verweigert!\nLeider hast du keine Berechtigung, diesen Befehl auszuführen.`;
bot.sendMessage(chatId, reply, {
parse_mode: 'HTML',
protect_content: true,
}).then((sentMessage) => {
setTimeout(() => {
bot.deleteMessage(chatId, sentMessage.message_id).catch((err) => {
console.error('Fehler beim Löschen der Antwortnachricht:', err);
});
}, 30000); // 30 Sekunden
});
setTimeout(() => {
bot.deleteMessage(chatId, msg.message_id).catch((err) => {
console.error('Fehler beim Löschen der ursprünglichen Nachricht:', err);
});
}, 30000); // 30 Sekunden
}
});
// /key Befehl
bot.onText(/\/key/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id.toString();
if (authorizedUsers.includes(userId)) {
if (passwordChangeRequired) {
const reply = `🔑 Neues Passwort:\n<span class="tg-spoiler">${newPassword}</span>\n\nDiese Nachricht wird in 30 Sekunden gelöscht.`;
bot.sendMessage(chatId, reply, { parse_mode: 'HTML' }).then((sentMessage) => {
setTimeout(() => {
bot.deleteMessage(chatId, sentMessage.message_id);
}, 30000);
});
setTimeout(() => {
bot.deleteMessage(chatId, msg.message_id);
}, 30000);
passwordChangeRequired = false; // /passwd wieder aktivieren
} else {
bot.sendMessage(chatId, "⚠️ Das Passwort wurde nicht geändert. Du kannst den /passwd Befehl nutzen.", { parse_mode: 'HTML' });
}
} else {
bot.sendMessage(chatId, "🚫 Zugriff verweigert!", { parse_mode: 'HTML' });
}
});
// Funktion zum Generieren eines sicheren zufälligen Passworts mit mindestens 12 Zeichen
function generateRandomPassword() {
const uppercaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const lowercaseChars = 'abcdefghijklmnopqrstuvwxyz';
const digits = '0123456789';
2024-10-18 13:02:39 +00:00
const specialChars = '@$!+-*&';
2024-10-17 22:46:38 +00:00
const allChars = uppercaseChars + lowercaseChars + digits + specialChars;
let password = '';
// Stelle sicher, dass das Passwort mindestens je einen Großbuchstaben, Kleinbuchstaben, Zahl und Sonderzeichen enthält
password += uppercaseChars.charAt(Math.floor(Math.random() * uppercaseChars.length));
password += lowercaseChars.charAt(Math.floor(Math.random() * lowercaseChars.length));
password += digits.charAt(Math.floor(Math.random() * digits.length));
password += specialChars.charAt(Math.floor(Math.random() * specialChars.length));
// Fülle das restliche Passwort mit zufälligen Zeichen auf, um 12 Zeichen zu erreichen
for (let i = 4; i < 12; i++) {
password += allChars.charAt(Math.floor(Math.random() * allChars.length));
}
// Das Passwort zufällig durchmischen
return shuffleString(password);
}
// Funktion zum Mischen eines Strings (optional, um die Zeichen zufällig anzuordnen)
function shuffleString(string) {
const array = string.split('');
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array.join('');
}
// Funktion zum Aktualisieren des Passworts in der .env-Datei
function updateEnvPassword(newPassword) {
const envFilePath = path.resolve(__dirname, '.env');
// Die aktuelle .env-Datei lesen
let envContent = fs.readFileSync(envFilePath, 'utf-8');
// Das Passwort in der Datei ändern
envContent = envContent.replace(/ADMIN_PW=.*/, `ADMIN_PW=${newPassword}`);
// Die geänderte Datei speichern
fs.writeFileSync(envFilePath, envContent);
// Umgebungsvariable aktualisieren, ohne den Bot neu zu starten
process.env.ADMIN_PW = newPassword;
// Passwortänderung abgeschlossen
passwordChangeRequired = false; // Sperre aufheben, Login wieder möglich
}
// /faq Befehl: Zeigt alle FAQs an
bot.onText(/\/faq/, (msg) => {
const chatId = msg.chat.id;
const faqs = loadFaqs();
if (faqs.length === 0) {
bot.sendMessage(chatId, 'Es gibt derzeit keine FAQs.');
} else {
let response = 'Häufig gestellte Fragen:\n\n';
faqs.forEach((faq, index) => {
response += `${index + 1}. *${faq.question}*\n${faq.answer}\n\n`;
});
bot.sendMessage(chatId, response, { parse_mode: 'Markdown' });
}
});
// /add_faq Befehl: Interaktives Hinzufügen einer neuen FAQ (nur für autorisierte Benutzer)
bot.onText(/\/add_faq/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id.toString();
if (!authorizedUsers.includes(userId)) {
bot.sendMessage(chatId, '❌ Du bist nicht autorisiert, diesen Befehl auszuführen.');
return;
}
// Frage nach der FAQ-Frage
bot.sendMessage(chatId, 'Bitte gib die FAQ-Frage ein:', {
reply_markup: { force_reply: true }
}).then(sentMessage => {
bot.onReplyToMessage(sentMessage.chat.id, sentMessage.message_id, (reply) => {
const question = reply.text;
// Frage nach der FAQ-Antwort
bot.sendMessage(chatId, 'Bitte gib die Antwort auf die Frage ein:', {
reply_markup: { force_reply: true }
}).then(sentMessage => {
bot.onReplyToMessage(sentMessage.chat.id, sentMessage.message_id, (reply) => {
const answer = reply.text;
// FAQ speichern
const faqs = loadFaqs();
faqs.push({ question, answer });
saveFaqs(faqs);
bot.sendMessage(chatId, '✅ FAQ erfolgreich hinzugefügt.');
});
});
});
});
});
// /del_faq Befehl: Interaktives Entfernen einer FAQ (nur für autorisierte Benutzer)
bot.onText(/\/del_faq/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id.toString();
if (!authorizedUsers.includes(userId)) {
bot.sendMessage(chatId, '❌ Du bist nicht autorisiert, diesen Befehl auszuführen.');
return;
}
const faqs = loadFaqs();
if (faqs.length === 0) {
bot.sendMessage(chatId, 'Es gibt derzeit keine FAQs zum Löschen.');
return;
}
// Liste der FAQs anzeigen und um Eingabe der Nummer bitten
let response = 'Welche FAQ möchtest du löschen?\n\n';
faqs.forEach((faq, index) => {
response += `${index + 1}. *${faq.question}*\n${faq.answer}\n\n`;
});
bot.sendMessage(chatId, response, {
parse_mode: 'Markdown',
reply_markup: { force_reply: true }
}).then(sentMessage => {
bot.onReplyToMessage(sentMessage.chat.id, sentMessage.message_id, (reply) => {
const faqIndex = parseInt(reply.text, 10) - 1;
if (isNaN(faqIndex) || faqIndex < 0 || faqIndex >= faqs.length) {
bot.sendMessage(chatId, '❌ Ungültige Auswahl.');
return;
}
// FAQ löschen
faqs.splice(faqIndex, 1);
saveFaqs(faqs);
bot.sendMessage(chatId, '✅ FAQ erfolgreich gelöscht.');
});
});
});
// Pfad zur Abonnentendatei
const subscribersFilePath = './subscribers.json';
const moviesApiUrl = `${process.env.PLEX_DOMAIN}/api/movies/latest`; // Beispiel-API-URL, anpassen
// Erstelle die subscribers.json, wenn sie nicht existiert
if (!fs.existsSync(subscribersFilePath)) {
fs.writeFileSync(subscribersFilePath, JSON.stringify([]));
}
let subscribers = [];
// Lade Abonnenten aus der subscribers.json
function loadSubscribers() {
try {
const data = fs.readFileSync(subscribersFilePath);
subscribers = JSON.parse(data);
} catch (error) {
console.error('Fehler beim Laden der Abonnenten:', error);
}
}
// Sende den Newsletter
async function sendNewsletter() {
loadSubscribers(); // Abonnenten laden
if (subscribers.length === 0) {
console.log('Keine Abonnenten gefunden.');
return;
}
const movies = await fetchLatestMovies(); // Filme abrufen
const htmlContent = createNewsletterContent(movies); // HTML-Inhalt erstellen
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
subscribers.forEach(subscriber => {
const mailOptions = {
from: process.env.SMTP_USER,
to: subscriber.email,
subject: 'Wöchentlicher Film-Newsletter',
html: htmlContent,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log('Fehler beim Senden der E-Mail:', error);
}
console.log('Newsletter gesendet an:', subscriber.email);
});
});
}
// Sofortige Bestätigungs-E-Mail senden
async function sendConfirmationEmail(email) {
const latestMovies = await fetchLatestMovies(); // Den zuletzt hinzugefügten Film abrufen
const latestMovie = latestMovies.length > 0 ? latestMovies[0] : null;
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
const logoUrl = process.env.PLEX_LOGO_URL; // Füge hier die URL zu deinem Plex-Logo hinzu
const latestMovieThumb = latestMovie ? `${process.env.PLEX_DOMAIN}${latestMovie.thumb}?X-Plex-Token=${process.env.PLEX_TOKEN}` : '';
const latestMovieTitle = latestMovie ? latestMovie.title : 'Kein Film gefunden';
const latestMovieSummary = latestMovie ? latestMovie.summary : 'Keine Zusammenfassung verfügbar';
const mailOptions = {
from: process.env.SMTP_USER,
to: email,
subject: '🎉 Bestätigung der Newsletter-Anmeldung 🎉',
html: `
<div style="font-family: Arial, sans-serif; text-align: center; background-color: #f4f4f4; padding: 20px; border-radius: 8px;">
<h1 style="color: #4CAF50;">Willkommen zum Viper-Plex Newsletter!</h1>
<p style="font-size: 18px;">Vielen Dank, dass Sie sich für unseren Newsletter angemeldet haben! 🎊</p>
<p style="font-size: 16px;">Ab sofort erhalten Sie jeden Sonntag die neuesten Informationen über spannende Filme.</p>
<img src="${logoUrl}" alt="Plex Logo" style="width: 100px; margin: 20px 0;"/>
<h2 style="color: #2196F3;">Zuletzt hinzugefügter Film:</h2>
<p style="font-size: 20px; font-weight: bold;">${latestMovieTitle}</p>
${latestMovieThumb ? `<img src="${latestMovieThumb}" alt="${latestMovieTitle} Poster" width="200" height="300" style="margin: 10px 0;"/>` : ''}
<p style="font-size: 18px;"><strong>Zusammenfassung:</strong> ${latestMovieSummary}</p>
<p style="font-size: 16px; color: #777;">Wir freuen uns, Sie als Teil unserer Viper-Plex Familie zu haben!</p>
<footer style="margin-top: 20px; font-size: 14px; color: #999;">Falls Sie Fragen haben, zögern Sie nicht, uns zu kontaktieren.</footer>
</div>
`,
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log('Fehler beim Senden der Bestätigungs-E-Mail:', error);
}
console.log('Bestätigungs-E-Mail gesendet an:', email);
});
}
// Filme abrufen
async function fetchLatestMovies() {
try {
const response = await axios.get(moviesApiUrl);
// Filtere nur Filme aus und ignoriere Serien und Staffeln
return response.data.movies.filter(movie => !movie.isSeries);
} catch (error) {
console.error('Fehler beim Abrufen der Filme:', error);
return [];
}
}
// Erstelle den HTML-Inhalt des Newsletters
function createNewsletterContent(movies) {
let html = `
<div style="font-family: Arial, sans-serif; text-align: center; background-color: #f4f4f4; padding: 20px; border-radius: 8px;">
<h1 style="color: #4CAF50;">Neueste Filme auf Viper-Plex</h1>
<div style="width: 80%; margin: auto;">
`;
movies.forEach(movie => {
const movieTitle = movie.title || 'Unbekannt';
const movieSummary = movie.summary || 'Keine Zusammenfassung verfügbar';
const addedAtDate = new Date((movie.addedAt || 0) * 1000).toLocaleString('de-DE'); // Konvertierung von Unix-Zeitstempel in lesbares Datum
const movieThumb = movie.thumb ? `${process.env.PLEX_DOMAIN}${movie.thumb}?X-Plex-Token=${process.env.PLEX_TOKEN}` : '';
html += `
<div style="background: #fff; border-radius: 8px; padding: 15px; margin: 10px 0; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);">
<h2 style="color: #2196F3;">${movieTitle}</h2>
${movieThumb ? `<img src="${movieThumb}" alt="${movieTitle} Poster" width="200" height="300" style="border-radius: 5px;"/>` : ''}
<p><strong>Zusammenfassung:</strong> ${movieSummary}</p>
<p><strong>Hinzugefügt am:</strong> ${addedAtDate}</p>
</div>
`;
});
html += `
</div>
</div>
`;
return html;
}
// Abmeldung vom Newsletter
bot.on('callback_query', (query) => {
const chatId = query.from.id; // Extrahiere die chatId aus dem Benutzer
// Überprüfen, ob die Abmeldung angefordert wird
if (query.data.startsWith('unsubscribe_')) {
const subscriberIndex = subscribers.findIndex(subscriber => subscriber.chatId === chatId);
if (subscriberIndex !== -1) {
const subscriber = subscribers[subscriberIndex];
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: 'Ja',
callback_data: `unsubscribe_yes_${chatId}`,
},
{
text: 'Nein',
callback_data: `unsubscribe_no_${chatId}`,
},
],
],
},
};
bot.sendMessage(chatId, `😥 Möchten Sie sich wirklich von dem Newsletter abmelden, ${subscriber.username}?`, options);
} else {
bot.sendMessage(chatId, '❗️ Sie sind nicht für den Newsletter angemeldet.');
}
}
});
// 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
if (query.data.startsWith('unsubscribe_yes')) {
const subscriberIndex = subscribers.findIndex(subscriber => subscriber.chatId === chatId);
if (subscriberIndex !== -1) {
subscribers.splice(subscriberIndex, 1); // Abonnenten entfernen
fs.writeFileSync(subscribersFilePath, JSON.stringify(subscribers, null, 2));
bot.sendMessage(chatId, '✅ Sie wurden erfolgreich vom Newsletter abgemeldet.');
} else {
bot.sendMessage(chatId, '❗️ Abonnent nicht gefunden.');
}
} else if (query.data.startsWith('unsubscribe_no')) {
bot.sendMessage(chatId, '❌ Abmeldung vom Newsletter abgebrochen.');
}
});
// Abmeldebefehl (z.B. /unsubscribe)
bot.onText(/\/unsubscribe/, (msg) => {
const chatId = msg.chat.id;
unsubscribeFromNewsletter(chatId);
});
// Planen des Newsletter-Versands jeden Sonntag um 10:00 Uhr
schedule.scheduleJob('0 10 * * 0', () => {
console.log('Sende wöchentlichen Newsletter...');
sendNewsletter();
});
// Abonnieren
bot.onText(/\/newsletter/, (msg) => {
const chatId = msg.chat.id;
const username = msg.from.username || 'Unbekannt';
// Überprüfen, ob der Benutzer bereits abonniert ist
const subscriber = subscribers.find(subscriber => subscriber.chatId === chatId);
if (!subscriber) {
// Wenn nicht abonniert, frage nach der E-Mail-Adresse
bot.sendMessage(chatId, 'Bitte geben Sie Ihre E-Mail-Adresse ein:');
bot.once('message', (msg) => {
const email = msg.text;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (emailRegex.test(email)) {
// Neuen Abonnenten hinzufügen
subscribers.push({ chatId, email, username });
fs.writeFileSync(subscribersFilePath, JSON.stringify(subscribers, null, 2));
sendConfirmationEmail(email); // Bestätigungs-E-Mail senden
bot.sendMessage(chatId, '🎉 Sie haben sich erfolgreich für den Newsletter angemeldet!');
} else {
bot.sendMessage(chatId, '❌ Ungültige E-Mail-Adresse. Bitte versuchen Sie es erneut.');
}
});
} else {
// Wenn bereits abonniert, zeige die Optionen an
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: 'Abmelden',
callback_data: `unsubscribe_${chatId}`,
},
{
text: 'Mailadresse ändern',
callback_data: `change_email_${chatId}`,
},
],
// Zusätzliche Optionen für Administratoren
...(isAdmin(chatId) ? [
[
{
text: 'Send Newsletter',
callback_data: 'send_newsletter',
},
{
text: 'Abonnenten',
callback_data: 'list_subscribers',
},
{
text: 'Abonnenten Entfernen',
callback_data: 'remove_subscriber',
},
]
] : []),
],
},
};
bot.sendMessage(chatId, 'Sie sind bereits angemeldet. Was möchten Sie tun?', options);
}
});
// Funktion, um zu überprüfen, ob der Benutzer ein Administrator ist
function isAdmin(chatId) {
const adminIds = [process.env.USER1_ID, process.env.USER2_ID];
return adminIds.includes(chatId.toString());
}
// Callback-Handler für die Buttons
bot.on('callback_query', (query) => {
const chatId = query.from.id; // chatId aus der Anfrage erhalten
if (query.data.startsWith('change_email')) {
bot.sendMessage(chatId, 'Bitte geben Sie Ihre neue E-Mail-Adresse ein:');
bot.once('message', (msg) => {
const newEmail = msg.text;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (emailRegex.test(newEmail)) {
const subscriberIndex = subscribers.findIndex(subscriber => subscriber.chatId === chatId);
if (subscriberIndex !== -1) {
subscribers[subscriberIndex].email = newEmail; // E-Mail-Adresse aktualisieren
fs.writeFileSync(subscribersFilePath, JSON.stringify(subscribers, null, 2));
bot.sendMessage(chatId, '✅ Ihre E-Mail-Adresse wurde erfolgreich aktualisiert.');
}
} else {
bot.sendMessage(chatId, '❌ Ungültige E-Mail-Adresse. Bitte versuchen Sie es erneut.');
}
});
} else if (query.data === 'send_newsletter') {
sendNewsletter(); // Newsletter sofort senden
bot.sendMessage(chatId, '📧 Der Newsletter wurde gesendet!');
} else if (query.data === 'list_subscribers') {
// Hier wird die Abonnentenliste formatiert
const subscriberList = subscribers.map(subscriber => `🔹 @${subscriber.username} - ${subscriber.email}`).join('\n') || 'Keine Abonnenten gefunden.';
bot.sendMessage(chatId, `📋 Abonnenten:\n\n${subscriberList}`);
} else if (query.data === 'remove_subscriber') {
bot.sendMessage(chatId, 'Bitte geben Sie die E-Mail-Adresse des Abonnenten ein, den Sie entfernen möchten:');
bot.once('message', (msg) => {
const emailToRemove = msg.text;
const subscriberIndex = subscribers.findIndex(subscriber => subscriber.email === emailToRemove);
if (subscriberIndex !== -1) {
subscribers.splice(subscriberIndex, 1); // Abonnenten entfernen
fs.writeFileSync(subscribersFilePath, JSON.stringify(subscribers, null, 2));
bot.sendMessage(chatId, `✅ Der Abonnent ${emailToRemove} wurde entfernt.`);
} else {
bot.sendMessage(chatId, '❌ Abonnent nicht gefunden.');
}
});
}
});
2024-10-20 20:09:31 +00:00
2024-10-17 22:46:38 +00:00
// Lade Abonnenten beim Start
loadSubscribers();
// Profilbefehl
bot.onText(/\/profil/, (msg) => {
2024-10-22 16:27:11 +00:00
const chatId = msg.chat.id;
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
const userFilePath = path.join(__dirname, 'user.yml');
const subscribersFilePath = path.join(__dirname, 'subscribers.json');
const wishesFilePath = path.join(__dirname, 'wunsch', `wishes_${chatId}.json`);
const feedbackFilePath = path.join(__dirname, 'feedback.log');
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Schritt 1: Benutzerinformationen aus user.yml lesen
fs.readFile(userFilePath, 'utf8', (err, userData) => {
2024-10-20 20:09:31 +00:00
if (err) {
2024-10-22 16:27:11 +00:00
console.error(`Fehler beim Lesen der Datei ${userFilePath}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Laden der Benutzerinformationen.')
2024-10-20 20:09:31 +00:00
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
2024-10-22 16:27:11 +00:00
const users = load(userData);
const user = users[chatId] || {}; // Benutzerdaten für den aktuellen Benutzer
// Initialisiere Benutzerinformationen
const userName = escapeMarkdownV2(user.username || 'Unbekannt');
const userId = chatId;
const firstUsedDate = escapeMarkdownV2(formatDate(user.firstUsed || new Date().toISOString())); // Aktuelles Datum verwenden, falls nicht vorhanden
// Benutzerlevel initialisieren
const commandCount = user.commandCount || 0; // Anzahl der Befehle aus den Benutzerdaten
const wishesCount = user.wishesCount || 0; // Anzahl der Wünsche aus Benutzerdaten
const userLevel = getUserLevel(commandCount, wishesCount); // Benutzerlevel ermitteln
// Admin und Dev IDs aus .env auslesen
const adminIds = [process.env.USER1_ID, process.env.USER2_ID];
const devId = process.env.DEV_CHAT_ID;
// Bestimme die Rolle basierend auf der ID
let roles = [];
if (adminIds.includes(String(chatId))) {
roles.push('Admin');
2024-10-20 20:09:31 +00:00
}
2024-10-22 16:27:11 +00:00
if (String(chatId) === devId) {
roles.push('DEV');
}
const role = roles.length > 0 ? roles.join(', ') : 'Benutzer';
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
fs.readFile(subscribersFilePath, 'utf8', (err, subsData) => {
if (err) {
console.error(`Fehler beim Lesen der Datei ${subscribersFilePath}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Laden des Newsletter-Status.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
let subscribers;
try {
subscribers = JSON.parse(subsData); // JSON sicher parsen
} catch (parseErr) {
console.error('Fehler beim Parsen der subscribers.json:', parseErr);
bot.sendMessage(chatId, 'Fehler beim Verarbeiten der Abonnentendaten.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
2024-10-20 20:09:31 +00:00
}
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Status prüfen, ob der Benutzer abonniert ist
const isSubscribed = subscribers.some(subscriber => subscriber.chatId === chatId);
const newsletterStatus = isSubscribed ? 'Ja' : 'Nein';
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Schritt 3: Wünsche aus wishes_${chatId}.json lesen
fs.readFile(wishesFilePath, 'utf8', (err, wishesData) => {
let wishesCount = 0; // Initialisierung der Wünsche
let notificationStatus = user.notifications ? 'Ja' : 'Nein';
if (!err) {
try {
const userWishes = JSON.parse(wishesData);
wishesCount = userWishes.length;
} catch (parseErr) {
console.error('Fehler beim Parsen der wishes-Datei:', parseErr);
}
}
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Schritt 4: Anzahl der Feedbacks zählen
fs.stat(feedbackFilePath, (err) => {
let feedbackCount = 0; // Standardwert für Feedbacks
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
if (!err) { // Datei existiert
fs.readFile(feedbackFilePath, 'utf8', (err, feedbackData) => {
if (!err) {
const feedbackLines = feedbackData.split('\n');
feedbackCount = feedbackLines.filter(line => line.includes(`chatId ${chatId}`)).length; // Zähle nur die Feedbacks des aktuellen Benutzers
}
// Benutzerlevel aktualisieren basierend auf den aktuellen Wünschen
const updatedUserLevel = getUserLevel(commandCount, wishesCount);
// Schritt 5: Nachricht formatieren und senden
const favoriteGenres = user.favoriteGenres && user.favoriteGenres.length > 0
? user.favoriteGenres.join(', ') // Genres als kommagetrennte Liste
: 'Nicht festgelegt'; // Standardwert, wenn keine Genres ausgewählt sind
// Nachtmodus-Anzeige
let nightModeText;
if (user.nightModes && user.nightModes.length > 0) {
const nightMode = user.nightModes[0]; // Nimm den ersten Nachtmodus
const startTime = nightMode.startTime;
const endTime = nightMode.endTime;
nightModeText = `🌙 Nachtmodus: ${startTime} \\- ${endTime}`; // Escape des Minuszeichens
} else {
nightModeText = '🌙 Nachtmodus: Nicht aktiv';
}
const profileMessage = `
2024-10-17 22:46:38 +00:00
📝 *Profil Informationen:*\n\n
👤 *Name:* @${userName}\n
🔑 *ID:* ${userId}\n
👤 *Nutzerrolle:* ${role}\n
🌟 *Benutzerlevel:* ${updatedUserLevel}\n
📅 *Registrierung:* ${firstUsedDate}\n
📰 *Newsletter:* ${newsletterStatus}\n
📋 *Anzahl der Wünsche:* ${wishesCount}\n
📬 *Anzahl der Feedbacks:* ${feedbackCount}\n
🔔 *Benachrichtigung:* ${notificationStatus}\n
2024-10-22 16:27:11 +00:00
${nightModeText}\n
🎭 *Lieblingsgenre:* ${favoriteGenres}\n
2024-10-17 22:46:38 +00:00
`.trim(); // Whitespace entfernen
2024-10-22 16:27:11 +00:00
// Sende Profilinformationen und zeige Button an
bot.sendMessage(chatId, profileMessage, {
parse_mode: 'MarkdownV2',
reply_markup: {
inline_keyboard: [
[{ text: 'Profil Bearbeiten', callback_data: 'edit_profile' }]
]
}
}).catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
});
} else {
// Datei existiert nicht, einfach die Nachricht senden
const favoriteGenres = user.favoriteGenres && user.favoriteGenres.length > 0
? user.favoriteGenres.join(', ') // Genres als kommagetrennte Liste
: 'Nicht festgelegt'; // Standardwert, wenn keine Genres ausgewählt sind
const nightModeText = user.nightModes && user.nightModes.length > 0
? `🌙 Nachtmodus: ${user.nightModes[0].startTime} \\- ${user.nightModes[0].endTime}`
: '🌙 Nachtmodus: Nicht aktiv';
const profileMessage = `
2024-10-17 22:46:38 +00:00
📝 *Profil Informationen:*\n\n
👤 *Name:* @${userName}\n
🔑 *ID:* ${userId}\n
👤 *Nutzerrolle:* ${role}\n
2024-10-22 16:27:11 +00:00
🌟 *Benutzerlevel:* ${updatedUserLevel}\n
2024-10-17 22:46:38 +00:00
📅 *Registrierung:* ${firstUsedDate}\n
📰 *Newsletter:* ${newsletterStatus}\n
📋 *Anzahl der Wünsche:* ${wishesCount}\n
📬 *Anzahl der Feedbacks:* 0\n
🔔 *Benachrichtigung:* ${notificationStatus}\n
2024-10-22 16:27:11 +00:00
${nightModeText}\n
🎭 *Lieblingsgenre:* ${favoriteGenres}\n
2024-10-17 22:46:38 +00:00
`.trim(); // Whitespace entfernen
2024-10-22 16:27:11 +00:00
bot.sendMessage(chatId, profileMessage, {
parse_mode: 'MarkdownV2',
reply_markup: {
inline_keyboard: [
[{ text: 'Profil Bearbeiten', callback_data: 'edit_profile' }]
]
}
}).catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
2024-10-20 20:09:31 +00:00
});
});
2024-10-22 16:27:11 +00:00
});
2024-10-17 22:46:38 +00:00
});
// Callback query handler for profile editing
bot.on('callback_query', (callbackQuery) => {
const action = callbackQuery.data;
const chatId = callbackQuery.message.chat.id;
if (action === 'edit_profile') {
2024-10-22 16:27:11 +00:00
// Zeige Bearbeitungsoptionen an, wenn der Benutzer "Profil Bearbeiten" drückt
bot.sendMessage(chatId, '🔍 Was möchten Sie tun? Wählen Sie eine der folgenden Optionen:', {
reply_markup: {
inline_keyboard: [
[
{ text: 'Genre bearbeiten', callback_data: 'edit_genres' },
{ text: 'Punkte löschen', callback_data: 'delete_points' },
{ text: 'Profil zurücksetzen', callback_data: 'reset_profile' }
],
[
{ text: 'Profil löschen', callback_data: 'delete_profile' }
]
]
}
});
} else if (action === 'edit_genres') {
// Genre-Auswahl anzeigen
bot.sendMessage(chatId, '🎬 Wählen Sie Ihre Lieblingsgenres aus:', {
reply_markup: {
inline_keyboard: [
[
{ text: 'Action', callback_data: 'select_genre_Action' },
{ text: 'Drama', callback_data: 'select_genre_Drama' },
{ text: 'Komödie', callback_data: 'select_genre_Comedy' }
],
[
{ text: 'Syfy', callback_data: 'select_genre_Syfy' },
{ text: 'Romantik', callback_data: 'select_genre_Romance' },
{ text: 'Thriller', callback_data: 'select_genre_Thriller' }
],
[
{ text: 'Fantasy', callback_data: 'select_genre_Fantasy' },
{ text: 'Family', callback_data: 'select_genre_Family' },
{ text: 'Zeichentrick', callback_data: 'select_genre_Animation' }
],
[
{ text: 'Anime', callback_data: 'select_genre_Anime' },
{ text: 'Horror', callback_data: 'select_genre_Horror' },
{ text: 'Katastrophen', callback_data: 'select_genre_Katastrophen' }
],
[
{ text: 'Krimi', callback_data: 'select_genre_Krimi' },
{ text: 'Mystery', callback_data: 'select_genre_Mystery' },
{ text: 'Western', callback_data: 'select_genre_Western' }
],
[
{ text: 'Abenteuer', callback_data: 'select_genre_Abenteuer' },
{ text: 'Dokumentation', callback_data: 'select_genre_Dokumentation' }
]
]
}
2024-10-17 22:46:38 +00:00
});
2024-10-22 16:27:11 +00:00
} else if (action.startsWith('select_genre_')) {
// Logik zum Hinzufügen/Entfernen des Genres vom Benutzerprofil
const selectedGenre = action.split('_')[2];
// Hier wird die Logik zum Speichern des Genres ins Profil hinzugefügt
2024-10-17 22:46:38 +00:00
fs.readFile(USER_YML_PATH, 'utf8', (err, userData) => {
if (err) {
console.error(`Fehler beim Lesen der Datei ${USER_YML_PATH}: ${err}`);
2024-10-22 16:27:11 +00:00
bot.sendMessage(chatId, 'Fehler beim Aktualisieren des Profils.')
2024-10-17 22:46:38 +00:00
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
const users = load(userData);
// Überprüfen, ob der Benutzer existiert
if (users[chatId]) {
2024-10-22 16:27:11 +00:00
// Genre zur Liste der Lieblingsgenres hinzufügen oder entfernen
if (!users[chatId].favoriteGenres) {
users[chatId].favoriteGenres = [];
}
const genreIndex = users[chatId].favoriteGenres.indexOf(selectedGenre);
if (genreIndex === -1) {
users[chatId].favoriteGenres.push(selectedGenre);
bot.sendMessage(chatId, `${selectedGenre} wurde zu Ihren Lieblingsgenres hinzugefügt.`);
} else {
users[chatId].favoriteGenres.splice(genreIndex, 1);
bot.sendMessage(chatId, `${selectedGenre} wurde aus Ihren Lieblingsgenres entfernt.`);
}
2024-10-17 22:46:38 +00:00
// Schreibe die aktualisierten Benutzerinformationen zurück in die Datei
fs.writeFile(USER_YML_PATH, dump(users), 'utf8', (err) => {
if (err) {
console.error(`Fehler beim Schreiben in die Datei ${USER_YML_PATH}: ${err}`);
2024-10-22 16:27:11 +00:00
bot.sendMessage(chatId, 'Fehler beim Aktualisieren des Profils.')
2024-10-17 22:46:38 +00:00
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
} else {
bot.sendMessage(chatId, '❌ Benutzer nicht gefunden.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
} else if (action === 'reset_profile') {
// Profil zurücksetzen
fs.readFile(USER_YML_PATH, 'utf8', (err, userData) => {
if (err) {
console.error(`Fehler beim Lesen der Datei ${USER_YML_PATH}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Zurücksetzen des Profils.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
const users = load(userData);
// Überprüfen, ob der Benutzer existiert
if (users[chatId]) {
// Setze die Standardwerte zurück
users[chatId] = {
userId: chatId,
username: users[chatId].username, // Behalte den Benutzernamen bei
firstUsed: users[chatId].firstUsed, // Behalte das erste Nutzungsdatum bei
notifications: true, // Standardwert für Benachrichtigungen
commandCount: 0, // Punkte zurücksetzen
userLevel: 'Neuling', // Benutzerlevel zurücksetzen
favoriteGenre: 'Nicht festgelegt' // Setze das Lieblingsgenre auf den Standardwert
};
// Schreibe die aktualisierten Benutzerinformationen zurück in die Datei
fs.writeFile(USER_YML_PATH, dump(users), 'utf8', (err) => {
if (err) {
console.error(`Fehler beim Schreiben in die Datei ${USER_YML_PATH}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Zurücksetzen des Profils.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
} else {
bot.sendMessage(chatId, '✅ Ihr Profil wurde erfolgreich zurückgesetzt.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
} else {
bot.sendMessage(chatId, '❌ Benutzer nicht gefunden.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
} else if (action === 'delete_profile') {
2024-10-22 16:27:11 +00:00
// Profil löschen
fs.readFile(USER_YML_PATH, 'utf8', (err, userData) => {
if (err) {
console.error(`Fehler beim Lesen der Datei ${USER_YML_PATH}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
const users = load(userData);
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Überprüfen, ob der Benutzer existiert
if (users[chatId]) {
// Benutzer aus user.yml entfernen
delete users[chatId];
2024-10-20 20:09:31 +00:00
2024-10-22 16:27:11 +00:00
// Schreibe die aktualisierten Benutzerinformationen zurück in die Datei
fs.writeFile(USER_YML_PATH, dump(users), 'utf8', (err) => {
if (err) {
console.error(`Fehler beim Schreiben in die Datei ${USER_YML_PATH}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Lösche zugehörige Einträge in w_offen.json
const wOffenFilePath = path.join(__dirname, 'w_offen.json'); // Pfad zur w_offen.json-Datei
fs.readFile(wOffenFilePath, 'utf8', (err, wOffenData) => {
if (err) {
console.error(`Fehler beim Lesen der Datei ${wOffenFilePath}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
let wOffen;
try {
wOffen = JSON.parse(wOffenData); // Sicheres Parsen der JSON-Daten
} catch (parseErr) {
console.error(`Fehler beim Parsen der w_offen.json: ${parseErr}`);
bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Entferne alle Wünsche des Benutzers
wOffen = wOffen.filter(wish => wish.userId !== chatId);
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Schreibe die aktualisierten Wünsche zurück in die w_offen.json
fs.writeFile(wOffenFilePath, JSON.stringify(wOffen, null, 2), 'utf8', (err) => {
if (err) {
console.error(`Fehler beim Schreiben in die Datei ${wOffenFilePath}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
return;
}
2024-10-17 22:46:38 +00:00
2024-10-22 16:27:11 +00:00
// Lösche die Datei im Wunsch-Ordner
const wunschFolderPath = path.join(__dirname, 'wunsch');
const userFilePath = path.join(wunschFolderPath, `wishes_${chatId}.json`); // Stelle sicher, dass der Dateiname korrekt ist
fs.unlink(userFilePath, (err) => {
if (err) {
console.error(`Fehler beim Löschen der Datei ${userFilePath}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
} else {
bot.sendMessage(chatId, '✅ Ihr Profil wurde erfolgreich gelöscht.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
});
});
});
} else {
bot.sendMessage(chatId, '❌ Benutzer nicht gefunden.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
2024-10-20 20:09:31 +00:00
}
2024-10-17 22:46:38 +00:00
});
2024-10-22 16:27:11 +00:00
2024-10-17 22:46:38 +00:00
const { load, dump } = require('js-yaml'); // Stelle sicher, dass js-yaml installiert ist
// Funktion zum Escapen von Markdown V2-Sonderzeichen
function escapeMarkdownV2(text) {
return text.replace(/([_*[\]()~>#+\-=.])/g, '\\$1'); // Escape-Zeichen
}
// Funktion zum Formatieren des Datums in DD-MM-YYYY
function formatDate(dateString) {
const [year, month, day] = dateString.split('-'); // Datum in Jahr, Monat, Tag zerlegen
return `${day}-${month}-${year}`; // DD-MM-YYYY Format zurückgeben
}
// Funktion zum Bestimmen des Benutzerlevels
2024-10-20 20:09:31 +00:00
function getUserLevel(commandCount) {
2024-10-17 22:46:38 +00:00
let level = 'Neuling';
// Kriterien für die Vergabe des Benutzerlevels
2024-10-20 20:09:31 +00:00
if (commandCount >= 6000) {
level = 'Legendärer Benutzer';
} else if (commandCount >= 3000) {
level = 'Meister Benutzer';
} else if (commandCount >= 1600) {
level = 'Fortgeschrittener Benutzer';
} else if (commandCount >= 800) {
2024-10-17 22:46:38 +00:00
level = 'Erfahrener Benutzer';
2024-10-20 20:09:31 +00:00
} else if (commandCount >= 400) {
level = 'VIP Benutzer';
} else if (commandCount >= 200) {
2024-10-17 22:46:38 +00:00
level = 'Aktiver Benutzer';
2024-10-20 20:09:31 +00:00
} else if (commandCount >= 100) {
level = 'Gelegentlicher Benutzer';
} else if (commandCount >= 30) {
level = 'Neuling';
2024-10-17 22:46:38 +00:00
}
return level;
}
// Funktion zum Aktualisieren des Benutzerlevels
function updateUserLevel(chatId) {
const userFilePath = path.join(__dirname, 'user.yml');
// Benutzerinformationen aus user.yml lesen
fs.readFile(userFilePath, 'utf8', (err, userData) => {
if (err) {
console.error(`Fehler beim Lesen der Datei ${userFilePath}: ${err}`);
return;
}
const users = load(userData);
const user = users[chatId];
if (user) {
// Benutzerlevel bestimmen
const commandCount = user.commandCount || 0;
const wishCount = user.wishCount || 0;
user.userLevel = getUserLevel(commandCount, wishCount); // Benutzerlevel aktualisieren
// Benutzerinformationen zurück in die Datei schreiben
const updatedUserData = dump(users);
fs.writeFile(userFilePath, updatedUserData, 'utf8', (err) => {
if (err) {
console.error(`Fehler beim Schreiben der Datei ${userFilePath}: ${err}`);
}
});
}
});
}
// Befehl zum Aktualisieren des Benutzerlevels bei jeder Nachricht
bot.on('message', (msg) => {
const chatId = msg.chat.id;
const userFilePath = path.join(__dirname, 'user.yml');
// Hier kannst du die Anzahl der Befehle erhöhen
fs.readFile(userFilePath, 'utf8', (err, userData) => {
if (!err) {
const users = load(userData);
if (users[chatId]) {
users[chatId].commandCount = (users[chatId].commandCount || 0) + 1;
const updatedUserData = dump(users);
fs.writeFile(userFilePath, updatedUserData, 'utf8', (err) => {
if (err) {
console.error(`Fehler beim Schreiben der Datei ${userFilePath}: ${err}`);
} else {
// Benutzerlevel aktualisieren, nachdem die Anzahl der Befehle erhöht wurde
updateUserLevel(chatId);
}
});
}
}
});
});
// Befehl zum Sichern der Dateien
bot.onText(/\/backup/, (msg) => {
const chatId = msg.chat.id;
// Überprüfen, ob die Nachricht vom Dev kommt
if (msg.from.id.toString() === process.env.DEV_CHAT_ID) {
const filesToBackup = [
'user.yml',
'faq.json',
'subscribers.json',
'w_offen.json',
'feedback.log',
'command_history.json',
'dev_reports.json'
];
const backupFolder = path.join(__dirname, 'wunsch'); // Pfad zum Wunsch-Ordner
const zipFilePath = path.join(__dirname, 'backup.zip'); // Speicherort für die ZIP-Datei
// Erstelle einen ZIP-Stream
const output = fs.createWriteStream(zipFilePath);
const archive = archiver('zip');
output.on('close', () => {
console.log(`Backup abgeschlossen, ${archive.pointer()} total bytes.`);
bot.sendDocument(chatId, zipFilePath, { caption: '📦 Hier ist dein Backup!' }) // Sende die ZIP-Datei an den Developer
.then(() => {
fs.unlinkSync(zipFilePath); // Lösche die ZIP-Datei nach dem Senden
})
.catch(err => {
console.error(`Fehler beim Senden der Backup-Datei: ${err.message}`);
bot.sendMessage(chatId, `❌ Fehler beim Senden der Backup-Datei: ${err.message}`);
});
});
archive.on('error', (err) => {
console.error(`Fehler beim Erstellen des Backups: ${err}`);
bot.sendMessage(chatId, `❌ Fehler beim Erstellen des Backups: ${err.message}`);
});
archive.pipe(output);
// Füge die Dateien hinzu
filesToBackup.forEach(file => {
const filePath = path.join(__dirname, file);
if (fs.existsSync(filePath)) {
archive.file(filePath, { name: file });
}
});
// Füge den Wunsch-Ordner hinzu, wenn er existiert
if (fs.existsSync(backupFolder)) {
archive.directory(backupFolder + '/', 'wunsch/'); // Füge den Inhalt des Wunsch-Ordners hinzu
}
archive.finalize(); // Beende die Archivierung
} else {
bot.sendMessage(chatId, '🚫 Dieser Befehl ist nur für den Developer verfügbar.');
}
});
let debugMode = false;
bot.onText(/\/setdebug/, (msg) => {
const chatId = msg.chat.id;
if (msg.from.id !== parseInt(process.env.DEV_CHAT_ID)) {
return bot.sendMessage(chatId, "🚫 Dieser Befehl ist nur für den Entwickler zugänglich.");
}
debugMode = !debugMode;
const status = debugMode ? "aktiviert" : "deaktiviert";
bot.sendMessage(chatId, `🐞 Debug-Modus wurde ${status}.`);
});
const os = require('os');
bot.onText(/\/serverinfo/, (msg) => {
const chatId = msg.chat.id;
if (msg.from.id !== parseInt(process.env.DEV_CHAT_ID)) {
return bot.sendMessage(chatId, "🚫 Dieser Befehl ist nur für den Entwickler zugänglich.");
}
const totalMemory = os.totalmem();
const freeMemory = os.freemem();
// Umrechnung in Gigabyte
const totalMemoryGB = (totalMemory / (1024 ** 3)).toFixed(2); // Umrechnen in GB
const freeMemoryGB = (freeMemory / (1024 ** 3)).toFixed(2); // Umrechnen in GB
const info = `🖥️ *Server-Info:*\n\n\n` +
`🔹 Plattform: ${os.platform()}\n\n` +
`🔹 Architektur: ${os.arch()}\n\n` +
`🔹 Gesamter Speicher: ${totalMemoryGB} GB\n\n` +
`🔹 Freier Speicher: ${freeMemoryGB} GB`;
bot.sendMessage(chatId, info);
});
bot.onText(/\/healthcheck/, async (msg) => {
const chatId = msg.chat.id;
if (msg.from.id !== parseInt(process.env.DEV_CHAT_ID)) {
return bot.sendMessage(chatId, "🚫 Dieser Befehl ist nur für den Entwickler zugänglich.");
}
let responseMessages = [];
responseMessages.push("🖥️ *Bot-Status:*\n\n");
// 1. Überprüfung, ob der Bot online ist
responseMessages.push("✅ *Bot ist online und funktionsfähig.*\n");
// 2. Überprüfung der Verbindung zur Plex API
try {
const plexResponse = await axios.get(`${process.env.PLEX_DOMAIN}/status`, {
headers: {
'X-Plex-Token': process.env.PLEX_TOKEN
}
});
responseMessages.push("✅ *Verbindung zur Plex API ist erfolgreich.*\n\n\n");
} catch (error) {
responseMessages.push("❌ *Verbindung zur Plex API fehlgeschlagen.*\n\n\n");
}
// 3. Überprüfung, ob wichtige Dateien vorhanden sind
responseMessages.push("📂 *Dateiüberprüfung:*\n\n");
const requiredFiles = ['user.yml', 'faq.json', 'subscribers.json', 'dev_reports.json', 'w_offen.json', 'feedback.log', 'command_history.json', 'error.log', 'Cache/cache-series.json', 'Cache/cache.json', 'Log/message.log', 'wunsch', 'backups'];
for (const file of requiredFiles) {
if (fs.existsSync(file)) {
responseMessages.push(`✅ *Datei ${file} ist vorhanden.*\n`);
} else {
responseMessages.push(`❌ *Datei ${file} fehlt.*\n`);
}
}
// Sende die gesammelten Antworten als Nachricht
bot.sendMessage(chatId, responseMessages.join(''), { parse_mode: 'Markdown' });
});
const commandHistoryFilePath = './command_history.json'; // Pfad zur Datei
let commandHistory = [];
// Lade die Historie aus der Datei, falls vorhanden
if (fs.existsSync(commandHistoryFilePath)) {
try {
const data = fs.readFileSync(commandHistoryFilePath, 'utf8'); // Stelle sicher, dass die Datei als UTF-8 gelesen wird
commandHistory = JSON.parse(data);
} catch (error) {
console.error("Fehler beim Laden der Kommando-Historie:", error.message);
commandHistory = []; // Setze die Historie zurück, wenn ein Fehler auftritt
}
}
// Funktion zum Protokollieren der Befehle
function logCommand(command, username) {
const timestamp = new Date(); // Aktuelles Datum und Uhrzeit
const formattedDate = timestamp.toLocaleString(); // Formatierung des Datums
// Füge den Befehl zur Historie hinzu
commandHistory.push(`${formattedDate} - @${username} - ${command}`);
if (commandHistory.length > 30) {
commandHistory.shift(); // Behalte nur die letzten 10 Befehle
}
// Speichere die Historie in der Datei
fs.writeFileSync(commandHistoryFilePath, JSON.stringify(commandHistory, null, 2));
}
// Funktion zum Formatieren der Historie
function formatCommandHistory(history) {
return history.map(entry => {
const [date, time, username, command] = entry.split(' - ');
return `${date} ${time} | ${username} | ${command}`;
}).join('\n'); // Jeder Eintrag wird in eine neue Zeile geschrieben
}
bot.onText(/\/command_history/, (msg) => {
const chatId = msg.chat.id;
if (msg.from.id !== parseInt(process.env.DEV_CHAT_ID)) {
return bot.sendMessage(chatId, "🚫 Dieser Befehl ist nur für den Entwickler zugänglich.");
}
if (commandHistory.length === 0) {
return bot.sendMessage(chatId, "📜 Keine Befehle in der Historie gefunden.");
}
const historyMessage = `🗃️ Kommando-Historie:\n\n` +
`Datum - Uhrzeit | Benutzername | Befehl\n` +
`-----------------------------------------\n` +
formatCommandHistory(commandHistory).replace(/,/g, ''); // Entferne Kommas und füge neue Zeilen hinzu
bot.sendMessage(chatId, historyMessage);
});
// Beispiel für andere Befehle
bot.onText(/\/start/, (msg) => {
logCommand('/update', msg.from.username);
// Logik für den Update-Befehl...
});
bot.onText(/\/notification_on/, (msg) => {
logCommand('/notification_on', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/notification_off/, (msg) => {
logCommand('/notification_off', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/serien/, (msg) => {
logCommand('/serien', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/latestmovie/, (msg) => {
logCommand('/latestmovie', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/latest10movies/, (msg) => {
logCommand('/latest10movies', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/top_rated/, (msg) => {
logCommand('/top_rated', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/wunsch/, (msg) => {
logCommand('/wunsch', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/trailer/, (msg) => {
logCommand('/trailer', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/empfehlung/, (msg) => {
logCommand('/empfehlung', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/newsletter/, (msg) => {
logCommand('/newsletter', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/help/, (msg) => {
logCommand('/help', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/profil/, (msg) => {
logCommand('/profil', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/w_list/, (msg) => {
logCommand('/w_list', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/dev/, (msg) => {
logCommand('/dev', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/feedback/, (msg) => {
logCommand('/feedback', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/faq/, (msg) => {
logCommand('/faq', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/info/, (msg) => {
logCommand('/info', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/bot/, (msg) => {
logCommand('/bot', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/admin/, (msg) => {
logCommand('/admin', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/open_wishes/, (msg) => {
logCommand('/open_wishes', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/user/, (msg) => {
logCommand('/user', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/update/, (msg) => {
logCommand('/update', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/logs/, (msg) => {
logCommand('/logs', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/logs_delete/, (msg) => {
logCommand('/logs_delete', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/f_log/, (msg) => {
logCommand('/f_log', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/add_faq/, (msg) => {
logCommand('/add_faq', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/del_faq/, (msg) => {
logCommand('/del_faq', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/command_history/, (msg) => {
logCommand('/command_history', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/backup/, (msg) => {
logCommand('/backup', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/serverinfo/, (msg) => {
logCommand('/serverinfo', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/healthcheck/, (msg) => {
logCommand('/healthcheck', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/setdebug/, (msg) => {
logCommand('/setdebug', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/support/, (msg) => {
logCommand('/support', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/night/, (msg) => {
logCommand('/night', msg.from.username);
// Logik für den Befehl...
});
bot.onText(/\/passwd/, (msg) => {
logCommand('/passwd', msg.from.username);
// Logik für den Befehl...
});
2024-10-22 16:27:11 +00:00
bot.onText(/\/key/, (msg) => {
logCommand('/key', msg.from.username);
// Logik für den Befehl...
});
2024-10-18 23:49:19 +00:00
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
bot.onText(/\/support/, (msg) => {
const chatId = msg.chat.id;
// Direkt die Telegram-ID verwenden
const adminId = 5507179337;
// Überprüfen, ob die Benutzer-ID in den autorisierten IDs enthalten ist
if (msg.from.id !== userId1 && msg.from.id !== userId2) {
return bot.sendMessage(chatId, "🚫 Dieser Befehl ist nur für autorisierte Benutzer zugänglich.");
}
bot.sendMessage(chatId, "💬 Bitte gib zusätzliche Informationen für den Support an:");
// Setze einen Listener für die nächste Nachricht des Benutzers
bot.once('message', async (reply) => {
const additionalText = reply.text || "Keine zusätzlichen Informationen bereitgestellt.";
const filesToZip = [
'error.log',
'command_history.json',
'user.yml',
'subscribers.json',
];
const logFolder = 'Log';
const zipPath = 'support.zip';
const output = fs.createWriteStream(zipPath);
const archive = archiver('zip');
output.on('close', async () => {
const botName = process.env.BOT_NAME || "Unbekannter Bot"; // Bot-Namen aus der .env
const adminNames = `${userId1}, ${userId2}`; // Namen der Administratoren
const supportMessage = `🛠️ *Externe Support-Anfrage* \n\n\n` +
`🔧 Bot-Name: @${botName}\n\n` +
`👨‍💻 Administratoren:\n ${adminNames}\n\n\n` +
`💬 Zusätzliche Informationen:\n\n ${additionalText}`;
await bot.sendMessage(adminId, supportMessage, { parse_mode: 'Markdown' });
await bot.sendDocument(adminId, zipPath);
fs.unlinkSync(zipPath); // Löscht die ZIP-Datei nach dem Senden
});
archive.on('error', (err) => {
throw err;
});
archive.pipe(output);
// Füge die Dateien zum ZIP-Archiv hinzu
filesToZip.forEach((file) => {
if (fs.existsSync(file)) {
archive.file(file, { name: file });
} else {
console.warn(`Datei ${file} nicht gefunden.`);
}
});
// Füge den Log-Ordner hinzu
if (fs.existsSync(logFolder)) {
archive.directory(logFolder + '/', logFolder + '/');
}
await archive.finalize(); // Warte, bis das Archiv abgeschlossen ist
});
2024-10-17 22:46:38 +00:00
});
2024-10-18 23:49:19 +00:00
2024-10-17 22:46:38 +00:00
// Handler für den /admin-Befehl
bot.onText(/\/admin/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
// Prüfe, ob der Benutzer autorisiert ist
if (userId.toString() === USER1_ID || userId.toString() === USER2_ID) {
bot.sendMessage(chatId, 'Bitte gib die Nachricht ein, die du an alle Benutzer senden möchtest:', {
reply_markup: {
force_reply: true
}
}).then(() => {
bot.once('message', async (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}`);
});
}).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 Nachrichteneingabeaufforderung an chatId ${chatId}: ${error.message}`);
});
} else {
bot.sendMessage(chatId, '❌ Du bist nicht autorisiert, diesen Befehl auszuführen.');
}
});
// Pfad zur Cache-Datei
const CACHE_FILE_PATH = path.join('Cache', 'cache-series.json');
// Funktion zum Speichern des Caches in eine Datei
function saveSeriesCache(series) {
fs.writeFileSync(CACHE_FILE_PATH, JSON.stringify(series, null, 2));
}
// Funktion zum Laden des Caches aus einer Datei
function loadSeriesCache() {
if (fs.existsSync(CACHE_FILE_PATH)) {
return JSON.parse(fs.readFileSync(CACHE_FILE_PATH));
}
return null;
}
// Funktion zum Abrufen aller Serien
async function fetchAllSeries() {
try {
const sectionsData = await fetchPlexData(PLEX_LIBRARY_URL);
const sections = sectionsData.MediaContainer.Directory;
let series = [];
for (const section of sections) {
const sectionUrl = `${PLEX_DOMAIN}/library/sections/${section.key}/all?X-Plex-Token=${PLEX_TOKEN}`;
const sectionData = await fetchPlexData(sectionUrl);
if (sectionData.MediaContainer && sectionData.MediaContainer.Metadata) {
const metadata = sectionData.MediaContainer.Metadata;
series = series.concat(metadata.filter(media => media.type === 'show'));
}
}
series.sort((a, b) => (b.addedAt || 0) - (a.addedAt || 0));
return series;
} catch (error) {
logError(`Error fetching all series: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen der Serien mit Caching
async function fetchSeriesWithCache() {
const cachedSeries = loadSeriesCache();
if (cachedSeries) {
logMessage('Series fetched from cache');
return cachedSeries;
}
try {
const series = await fetchAllSeries();
saveSeriesCache(series);
logMessage('Series fetched from API and cached');
return series;
} catch (error) {
logError(`Error fetching series: ${error.message}`);
throw error;
}
}
// Automatische Cache-Aktualisierung jede Stunde
schedule.scheduleJob('0 * * * *', async () => {
try {
const series = await fetchAllSeries();
saveSeriesCache(series);
logMessage('Series cache updated automatically');
} catch (error) {
logError(`Error updating series cache: ${error.message}`);
}
});
// Handler für den /serien-Befehl
bot.onText(/\/serien/, async (msg) => {
const chatId = msg.chat.id;
try {
const series = await fetchSeriesWithCache();
const seriesList = series.map((s, index) => `${index + 1}. ${s.title}`).join('\n');
bot.sendMessage(chatId, `Hier sind die Serien in deiner Plex-Mediathek:\n\n${seriesList}`, {
reply_markup: {
inline_keyboard: [
[{ text: 'Weitere Informationen', callback_data: 'get_series_info' }]
]
}
});
} catch (error) {
bot.sendMessage(chatId, 'Fehler beim Abrufen der Serien. Bitte versuche es später erneut.');
logError(`Error handling /serien command: ${error.message}`);
}
});
// Handler für die Callback-Abfragen von Inline-Buttons
bot.on('callback_query', async (query) => {
const chatId = query.message.chat.id;
if (query.data.startsWith('get_series_info')) {
try {
const series = await fetchSeriesWithCache();
const responseMessage = `Bitte gib die Nummer der Serie ein, um weitere Informationen zu erhalten.`;
bot.sendMessage(chatId, responseMessage, {
reply_markup: {
force_reply: true
}
}).then(() => {
bot.once('message', async (msg) => {
if (msg.chat.id === chatId && msg.text) {
const seriesNumber = parseInt(msg.text, 10);
if (!isNaN(seriesNumber) && seriesNumber > 0 && seriesNumber <= series.length) {
const seriesInfo = series[seriesNumber - 1];
const { title, summary, thumb, addedAt } = seriesInfo;
2024-10-18 23:49:19 +00:00
const imageUrl = `${PLEX_DOMAIN}${thumb}?X-Plex-Token=${PLEX_TOKEN}`; // Beispiel-URL anpassen
2024-10-17 22:46:38 +00:00
// Debugging-Ausgabe
console.log(`Image URL: ${imageUrl}`);
// Formatieren des Hinzufügungsdatums
const addedDate = addedAt ? dayjs(addedAt * 1000).format('DD.MM.YYYY') : 'Unbekannt';
const caption = `📺 *Titel:* ${title}\n\n` +
`📝 *Beschreibung:* \n${summary}\n\n` +
`📅 *Hinzugefügt am:* ${addedDate}`;
// Bild herunterladen und lokal speichern
const imagePath = path.join(__dirname, 'temp_image.jpg');
const writer = fs.createWriteStream(imagePath);
const response = await axios({
url: imageUrl,
method: 'GET',
responseType: 'stream'
});
response.data.pipe(writer);
writer.on('finish', async () => {
// Senden des Bildes
try {
await bot.sendPhoto(chatId, imagePath, { caption, parse_mode: 'Markdown' });
// Optional: Nach dem Senden das Bild löschen
fs.unlinkSync(imagePath);
} catch (sendPhotoError) {
logError(`Fehler beim Senden des Fotos: ${sendPhotoError.message}`);
bot.sendMessage(chatId, 'Fehler beim Senden des Bildes. Bitte versuche es später erneut.');
}
});
writer.on('error', (error) => {
logError(`Fehler beim Schreiben der Bilddatei: ${error.message}`);
bot.sendMessage(chatId, 'Fehler beim Abrufen des Bildes. Bitte versuche es später erneut.');
});
} else {
bot.sendMessage(chatId, 'Ungültige Nummer. Bitte gib eine gültige Nummer ein.');
}
}
});
}).catch(error => {
logError(`Fehler beim Senden der Eingabeaufforderung: ${error.message}`);
});
} catch (error) {
bot.sendMessage(chatId, 'Fehler beim Abrufen der Serieninformationen. Bitte versuche es später erneut.');
logError(`Error handling callback query: ${error.message}`);
}
}
});
// Log-Error-Funktion (Optional)
function logError(message) {
const timestamp = new Date().toISOString();
fs.appendFileSync('error.log', `${timestamp} - ${message}\n`);
}
2024-10-18 13:02:39 +00:00
2024-10-17 22:46:38 +00:00
// Umgebungsvariable für die Chat-ID der Entwickler
const DEV_CHAT_ID = parseInt(process.env.DEV_CHAT_ID, 10);
// Der Pfad zur Datei, in der die Dev Reports gespeichert werden
const DEV_REPORTS_FILE_PATH = path.join(__dirname, 'dev_reports.json');
// Funktion zum Erstellen der Datei, wenn sie nicht vorhanden ist
function createDevReportsFile() {
if (!fs.existsSync(DEV_REPORTS_FILE_PATH)) {
fs.writeFileSync(DEV_REPORTS_FILE_PATH, JSON.stringify([])); // Leeres Array initialisieren
console.log('Dev Reports Datei erstellt.');
}
}
// Funktion zum Erstellen des Inline-Keyboards
function getDevOptionsKeyboard() {
return {
reply_markup: {
inline_keyboard: [
[{ text: '💡 Funktionswunsch', callback_data: 'dev_request' }],
2024-10-18 13:02:39 +00:00
[{ text: '🐞 Bug melden', callback_data: 'dev_bug' }],
[{ text: '🎬 Film Report', callback_data: 'film_report' }]
2024-10-17 22:46:38 +00:00
]
}
};
}
// Handler für den /dev-Befehl
bot.onText(/\/dev/, (msg) => {
const chatId = msg.chat.id;
const message = '🔧 *Dev-Feedback* - Bitte wählen Sie eine der folgenden Optionen, um Ihr Feedback zu übermitteln:';
bot.sendMessage(chatId, message, {
parse_mode: 'Markdown',
...getDevOptionsKeyboard()
});
});
// Handler für Callback-Queries im /dev-Befehl
bot.on('callback_query', (query) => {
console.log('Callback-Query-Daten:', query.data); // Debugging-Ausgabe
const chatId = query.message.chat.id;
const data = query.data;
let responseText = '';
let replyMarkup;
switch (data) {
case 'dev_request':
responseText = '✏️ *Bitte geben Sie Ihren Funktionswunsch ein:*';
replyMarkup = {
reply_markup: {
force_reply: true
}
};
break;
case 'dev_bug':
responseText = '✏️ *Bitte beschreiben Sie den Bug, den Sie melden möchten:*';
replyMarkup = {
reply_markup: {
force_reply: true
}
};
break;
2024-10-18 13:02:39 +00:00
case 'film_report':
responseText = '🎬 *Bitte geben Sie den Film Report ein:* \n\nTitel & Fehlerbeschreibung:';
replyMarkup = {
reply_markup: {
force_reply: true
}
};
break;
2024-10-17 22:46:38 +00:00
default:
// Kein Popup oder Nachricht senden, wenn die Auswahl unbekannt ist
return;
}
bot.sendMessage(chatId, responseText, { parse_mode: 'Markdown', ...replyMarkup });
});
// Handler für die Antworten auf die Feedback-Anfrage
bot.on('message', async (msg) => {
if (msg.reply_to_message && (msg.reply_to_message.text.includes('Bitte geben Sie Ihren Funktionswunsch ein:') ||
2024-10-18 13:02:39 +00:00
msg.reply_to_message.text.includes('Bitte beschreiben Sie den Bug, den Sie melden möchten:') ||
msg.reply_to_message.text.includes('Bitte geben Sie den Film Report ein:'))) {
2024-10-17 22:46:38 +00:00
const chatId = msg.chat.id;
const text = msg.text;
const userName = msg.from.first_name + (msg.from.last_name ? ` ${msg.from.last_name}` : '');
const userId = msg.from.id;
2024-10-18 13:02:39 +00:00
let messageType;
let report;
if (msg.reply_to_message.text.includes('Funktionswunsch')) {
messageType = 'Funktionswunsch';
report = { type: messageType, user: { name: userName, id: userId }, message: text };
} else if (msg.reply_to_message.text.includes('Bug')) {
messageType = 'Bug';
report = { type: messageType, user: { name: userName, id: userId }, message: text };
} else if (msg.reply_to_message.text.includes('Film Report')) {
// Hier wird der gesamte Text für Titel und Fehlerbeschreibung verwendet
const userMessage = text.trim(); // Benutzertext
messageType = 'Film Report';
report = {
type: messageType,
user: { name: userName, id: userId },
message: userMessage // Der gesamte Benutzertext wird als Nachricht verwendet
};
}
2024-10-17 22:46:38 +00:00
// Dev Report in die Datei schreiben
try {
2024-10-18 13:02:39 +00:00
// Nur die DEV_CHAT_ID für Bug und Funktionswunsch
if (messageType === 'Bug' || messageType === 'Funktionswunsch') {
console.log('Sende Nachricht an Entwickler-Chat-ID:', DEV_CHAT_ID); // Debugging-Ausgabe
await bot.sendMessage(DEV_CHAT_ID, formatDevMessage(report), { parse_mode: 'Markdown' });
}
// DEV_CHAT_ID und USER2_ID für Film Reports
else if (messageType === 'Film Report') {
console.log('Sende Nachricht an Entwickler-Chat-ID und USER2_ID:', DEV_CHAT_ID, USER2_ID); // Debugging-Ausgabe
await bot.sendMessage(DEV_CHAT_ID, formatDevMessage(report), { parse_mode: 'Markdown' });
await bot.sendMessage(USER2_ID, formatDevMessage(report), { parse_mode: 'Markdown' });
}
2024-10-17 22:46:38 +00:00
console.log('Nachricht erfolgreich gesendet.');
// Dev Report in die JSON-Datei speichern
2024-10-18 13:02:39 +00:00
saveDevReport(report);
2024-10-17 22:46:38 +00:00
bot.sendMessage(chatId, '✅ Ihre Nachricht wurde erfolgreich gesendet! Vielen Dank.');
} catch (error) {
console.error('Fehler beim Senden der Nachricht:', error);
bot.sendMessage(chatId, '🚫 Etwas ist schiefgelaufen. Ihre Nachricht konnte nicht gesendet werden.');
}
}
});
// Funktion zur Formatierung der Dev-Nachricht
function formatDevMessage(report) {
return `📩 *${report.type}*\n\n` +
`von: ${report.user.name} (${report.user.id})\n\n` +
`"${report.message}"`;
}
// Funktion zum Speichern des Dev Reports in die JSON-Datei
function saveDevReport(report) {
const reports = JSON.parse(fs.readFileSync(DEV_REPORTS_FILE_PATH));
report.id = reports.length; // ID basierend auf der aktuellen Länge des Arrays zuweisen
reports.push(report);
fs.writeFileSync(DEV_REPORTS_FILE_PATH, JSON.stringify(reports, null, 2)); // Schön formatieren
}
// Starte den Bot und erstelle die Datei
createDevReportsFile();
2024-10-18 13:02:39 +00:00
2024-10-17 22:46:38 +00:00
// Handler für den /bot-Befehl
bot.onText(/\/bot/, (msg) => {
const chatId = msg.chat.id;
try {
// Bot-Version dynamisch aus der .env-Datei
const botVersion = process.env.BOT_VERSION || "1.7.0";
// Laufzeit des Prozesses in Sekunden
const uptime = process.uptime();
const hours = Math.floor(uptime / 3600);
const minutes = Math.floor((uptime % 3600) / 60);
const seconds = Math.floor(uptime % 60);
const runtime = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
// Benutzeranzahl aus user.yml
const users = yaml.load(USER_YML_PATH);
const userCount = Object.keys(users).length;
// Abonnentenanzahl aus subscribers.json
const subscribers = JSON.parse(fs.readFileSync('subscribers.json', 'utf8'));
const subscriberCount = subscribers.length;
// Letzter Neustart des Bots
const lastRestart = dayjs().format('YYYY-MM-DD HH:mm:ss');
// Speicherbelegung
const memoryUsage = process.memoryUsage();
const memoryStats = `Heap Total: ${Math.round(memoryUsage.heapTotal / 1024 / 1024)} MB, Heap Used: ${Math.round(memoryUsage.heapUsed / 1024 / 1024)} MB`;
// Cache-Status
const cacheKeys = cache.keys().length;
const cacheStats = cache.getStats(); // Hole die vollständigen Cache-Stats
const cacheTTL = cacheStats.stdTTL || 0; // Setze Default-Wert auf 0, falls nicht definiert
// Fehlerprotokoll-Status
const errorLogCount = fs.existsSync(ERROR_LOG_PATH) ? fs.readFileSync(ERROR_LOG_PATH, 'utf8').split('\n').length - 1 : 0;
// Aktuelle Aufgaben
const currentTasks = `
- Cache wird jede Stunde aktualisiert \n
- Geplante Überprüfungen neuer Filme alle 1 Minute \n
- Newsletter Versand jeden Sonntag \n
`;
// Bot Token und Webhook URL (falls vorhanden)
const botToken = BOT_TOKEN;
const webhookStatus = WEBHOOK_URL ? "Aktiv" : "Inaktiv";
// Nachricht erstellen
const infoMessage = `
📊 *Bot Informationen* \n\n
🆙 *Version:* ${botVersion} \n
*Laufzeit:* ${runtime} \n
👥 *Benutzeranzahl:* ${userCount} \n
📰 *Abonnentenanzahl:* ${subscriberCount} \n
🔄 *Letzter Neustart:* ${lastRestart} \n
💾 *Speicherbelegung:* ${memoryStats} \n
🔑 *Bot Token:* ${botToken.slice(0, 0)}... (Ausgeblendet für Sicherheit) \n
🌐 *Webhook URL:* ${webhookStatus} \n
🔑 *Cache Keys:* ${cacheKeys} \n
*Cache TTL:* ${cacheTTL} Sekunden \n
📝 *Fehlerprotokoll-Anzahl:* ${errorLogCount} \n\n
🛠 *Aktuelle Aufgaben:* \n
${currentTasks.trim()}
`;
// Inline-Button erstellen
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: "Kontakt",
url: process.env.CONTACT_LINK // Link aus der .env-Datei
}
]
]
},
parse_mode: 'Markdown'
};
// Nachricht senden
bot.sendMessage(chatId, infoMessage, options).catch(error => {
logError(`Fehler beim Senden der Bot-Informationen an chatId ${chatId}: ${error.message}`);
});
} catch (error) {
// Fehlerprotokollierung für unerwartete Fehler
logError(`Fehler beim Abrufen von Bot-Informationen: ${error.message}`);
bot.sendMessage(chatId, 'Fehler beim Abrufen der Bot-Informationen.').catch(err => {
logError(`Fehler beim Senden der Fehlermeldung an chatId ${chatId}: ${err.message}`);
});
}
});
// Handler für den /logs-Befehl
bot.onText(/\/logs(?: (\d+))?/, (msg, match) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
if (userId.toString() === USER1_ID || userId.toString() === USER2_ID) {
const count = match[1] ? parseInt(match[1], 10) : 10;
const recentErrors = getRecentErrors(count).join('\n');
const message = recentErrors.length > 0 ? `Fehlermeldungen:\n${recentErrors}` : 'Keine Fehlermeldungen vorhanden.';
bot.sendMessage(chatId, message).catch(error => {
logError(`Fehler beim Senden der Logs an chatId ${chatId}: ${error.message}`);
});
} else {
bot.sendMessage(chatId, '❌ Du bist nicht autorisiert, diesen Befehl auszuführen.');
}
});
// Definiere den Pfad zur feedback.yml
const FEEDBACK_FILE_PATH = path.resolve(__dirname, 'Log', 'feedback.yml');
// Handler für den /log_delete-Befehl
bot.onText(/\/log_delete/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
if (userId.toString() === USER1_ID || userId.toString() === USER2_ID) {
const inlineKeyboard = [
[{ text: 'Error Log Löschen', callback_data: 'delete_error_log' }],
[{ text: 'User Log Löschen', callback_data: 'delete_user_log' }],
[{ text: 'Feedback Log Löschen', callback_data: 'delete_feedback_log' }] // Neuer Button
];
bot.sendMessage(chatId, 'Wähle, welches Log du löschen möchtest:', {
reply_markup: {
inline_keyboard: inlineKeyboard
}
}).catch(error => {
logError(`Fehler beim Senden der Log-Lösch-Nachricht an chatId ${chatId}: ${error.message}`);
});
} else {
bot.sendMessage(chatId, '❌ Du bist nicht autorisiert, diesen Befehl auszuführen.');
}
});
// Handler für Inline-Button-Callbacks
bot.on('callback_query', async (callbackQuery) => {
const chatId = callbackQuery.message.chat.id;
const userId = callbackQuery.from.id;
const data = callbackQuery.data;
if (data === 'delete_error_log') {
// Lösche das gesamte Error Log
if (fs.existsSync(ERROR_LOG_PATH)) {
fs.unlinkSync(ERROR_LOG_PATH); // Lösche die Error Log Datei komplett
bot.answerCallbackQuery(callbackQuery.id, { text: 'Error Log wurde gelöscht.' });
bot.sendMessage(chatId, 'Das Error Log wurde erfolgreich gelöscht.').catch(error => {
logError(`Fehler beim Senden der Bestätigung für das Löschen des Error Logs an chatId ${chatId}: ${error.message}`);
});
} else {
bot.answerCallbackQuery(callbackQuery.id, { text: 'Error Log existiert nicht.' });
}
} else if (data === 'delete_user_log') {
// Lösche alle User Logs im LOG_DIR
try {
const files = fs.readdirSync(LOG_DIR);
const userLogFiles = files.filter(file => /^\d{4}-\d{2}-\d{2}\.log$/.test(file));
if (userLogFiles.length > 0) {
userLogFiles.forEach(file => fs.unlinkSync(path.join(LOG_DIR, file))); // Lösche jede User Log Datei
bot.answerCallbackQuery(callbackQuery.id, { text: 'User Logs wurden gelöscht.' });
bot.sendMessage(chatId, 'Alle User Logs wurden erfolgreich gelöscht.').catch(error => {
logError(`Fehler beim Senden der Bestätigung für das Löschen der User Logs an chatId ${chatId}: ${error.message}`);
});
} else {
bot.answerCallbackQuery(callbackQuery.id, { text: 'Keine User Logs zum Löschen gefunden.' });
}
} catch (error) {
bot.answerCallbackQuery(callbackQuery.id, { text: 'Fehler beim Löschen der User Logs.' });
logError(`Fehler beim Löschen der User Logs: ${error.message}`);
}
} else if (data === 'delete_feedback_log') {
// Lösche die Feedback-Datei
if (fs.existsSync(FEEDBACK_FILE_PATH)) {
fs.unlinkSync(FEEDBACK_FILE_PATH); // Lösche die Feedback-Datei komplett
bot.answerCallbackQuery(callbackQuery.id, { text: 'Feedback Log wurde gelöscht.' });
bot.sendMessage(chatId, 'Das Feedback Log wurde erfolgreich gelöscht.').catch(error => {
logError(`Fehler beim Senden der Bestätigung für das Löschen des Feedback Logs an chatId ${chatId}: ${error.message}`);
});
} else {
bot.answerCallbackQuery(callbackQuery.id, { text: 'Feedback Log existiert nicht.' });
}
} else {
bot.answerCallbackQuery(callbackQuery.id, { text: 'Unbekannte Auswahl.' });
}
});
// Handler für den /user-Befehl
bot.onText(/\/user/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
// Überprüfen, ob der Benutzer autorisiert ist
if (userId.toString() === USER1_ID || userId.toString() === USER2_ID) {
try {
// Lade die Benutzer aus der YAML-Datei
const users = yaml.load(USER_YML_PATH);
let responseMessage = "Benutzerinformationen:\n\n";
// Gehe durch die Benutzer und baue die Antwortnachricht auf
for (const [id, user] of Object.entries(users)) {
const name = user.username || 'Unbekannt';
const notificationsStatus = user.notifications ? 'Aktiv' : 'Inaktiv';
responseMessage += `Name: ${name}\nID: ${id}\nBenachrichtigung Status: ${notificationsStatus}\n\n`; // Zwei Leerzeilen für Abstand
}
// Sende die Antwortnachricht
bot.sendMessage(chatId, responseMessage.trim()).catch(error => {
logError(`Fehler beim Senden der Benutzerinformationen an chatId ${chatId}: ${error.message}`);
});
} catch (error) {
// Fehlerprotokollierung für unerwartete Fehler
logError(`Fehler beim Abrufen der Benutzerinformationen: ${error.message}`);
bot.sendMessage(chatId, 'Fehler beim Abrufen der Benutzerinformationen.').catch(err => {
logError(`Fehler beim Senden der Fehlermeldung an chatId ${chatId}: ${err.message}`);
});
}
} else {
bot.sendMessage(chatId, '❌ Du bist nicht autorisiert, diesen Befehl auszuführen.');
}
});
// Maximale Länge einer Telegram-Nachricht in Zeichen
const MAX_MESSAGE_LENGTH = 4096;
// Hilfsfunktion zum Aufteilen einer Nachricht in kleinere Teile
function splitMessage(message) {
const messages = [];
while (message.length > MAX_MESSAGE_LENGTH) {
let splitIndex = message.lastIndexOf('\n', MAX_MESSAGE_LENGTH);
if (splitIndex === -1) {
splitIndex = MAX_MESSAGE_LENGTH; // Wenn kein neuer Zeilenumbruch gefunden wird, einfach am Limit aufteilen
}
messages.push(message.substring(0, splitIndex));
message = message.substring(splitIndex);
}
if (message.length > 0) {
messages.push(message);
}
return messages;
}
// Handler für den /top_rated-Befehl
bot.onText(/\/top_rated/, async (msg) => {
const chatId = msg.chat.id;
try {
const movies = await fetchTopRatedMovies();
if (movies.length > 0) {
// Begrenze die Anzahl der angezeigten Filme auf 20
const topMovies = movies.slice(0, 15);
let message = '🌟 *Top 15 Am besten bewertete Filme:*\n\n';
topMovies.forEach((movie, index) => {
message += `🎬 *${index + 1}. ${movie.title}* \n` +
`⭐ Bewertung: ${movie.rating.toFixed(1)} \n\n`;
});
// Teile die Nachricht in kleinere Teile auf, wenn sie zu lang ist
const messageParts = splitMessage(message);
for (const part of messageParts) {
await bot.sendMessage(chatId, part, { parse_mode: 'Markdown' });
}
} else {
await bot.sendMessage(chatId, '🚫 Keine gut bewerteten Filme gefunden.');
}
} catch (error) {
logError(`Fehler beim Abrufen der besten Filme für chatId ${chatId}: ${error.message}`);
await bot.sendMessage(chatId, 'Beim Abrufen der besten Filme ist ein Fehler aufgetreten.');
}
});
// Handler für Inline-Button-Callbacks
bot.on('callback_query', (callbackQuery) => {
const chatId = callbackQuery.message.chat.id;
const userId = callbackQuery.from.id;
const data = callbackQuery.data;
if (data.startsWith('delete_log_')) {
const index = parseInt(data.split('_')[2], 10);
const recentErrors = getRecentErrors();
if (index >= 0 && index < recentErrors.length) {
recentErrors.splice(index, 1); // Lösche den ausgewählten Eintrag
fs.writeFileSync(ERROR_LOG_PATH, recentErrors.join('\n'), 'utf8');
bot.answerCallbackQuery(callbackQuery.id, { text: 'Fehlermeldung gelöscht.' });
bot.sendMessage(chatId, 'Die Fehlermeldung wurde gelöscht.').catch(error => {
logError(`Fehler beim Senden der Bestätigungsnachricht über das Löschen der Fehlermeldung an chatId ${chatId}: ${error.message}`);
});
} else {
bot.answerCallbackQuery(callbackQuery.id, { text: 'Ungültiger Index.' });
}
}
});
// Funktion zum Abrufen der letzten Fehlermeldungen
function getRecentErrors(count = 10) {
if (!fs.existsSync(ERROR_LOG_PATH)) return [];
const logLines = fs.readFileSync(ERROR_LOG_PATH, 'utf8').trim().split('\n');
return logLines.slice(-count);
}
// Funktion zum Protokollieren von Fehlern
function logError(error) {
const errorMessage = `${dayjs().format('HH:mm:ss')} - Error: ${error}\n`;
fs.appendFileSync(ERROR_LOG_PATH, errorMessage);
}
// /start-Befehl verarbeiten
bot.onText(/\/start/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
const username = msg.from.username || 'Unbekannt'; // Benutzername, falls vorhanden, sonst 'Unbekannt'
// Aktuelles Datum im ISO-Format
const firstUsedDate = new Date().toISOString().split('T')[0]; // Format: YYYY-MM-DD
// Benutzerdaten in user.yml speichern
let users = yaml.load(USER_YML_PATH);
users[chatId] = {
userId: userId,
username: username,
notifications: true, // Standardmäßig Benachrichtigungen aktiviert
firstUsed: firstUsedDate, // Datum des ersten Gebrauchs
favoriteGenre: "Nicht festgelegt" // Standardwert für das Lieblingsgenre
};
fs.writeFileSync(USER_YML_PATH, yaml.stringify(users, 4));
// Bot-Start-Nachricht
const welcomeMessage = `👋 Willkommen ${username}!
Dein Zugang zum Bot wurde erfolgreich eingerichtet.
Um die verfügbaren Befehle anzuzeigen, tippe 👉 /help.
🔔 Hinweis: Benachrichtigungen über neue Filme sind standardmäßig aktiviert.
Um sie zu deaktivieren, tippe 👉 /notification_off.
👤 Möchtest du dein Profil sehen? Tippe 👉 /profil.`;
2024-10-18 23:49:19 +00:00
// Inline-Button zu einer Webadresse, basierend auf der Umgebungsvariable
2024-10-17 22:46:38 +00:00
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: 'zur Web Oberfläche',
2024-10-18 23:49:19 +00:00
url: process.env.PANEL_LINK // Verwendung der PANEL_LINK-Umgebungsvariable
2024-10-17 22:46:38 +00:00
}
]
]
}
};
bot.sendMessage(chatId, welcomeMessage, options);
// /start-Befehl protokollieren
logMessage(`Received /start command from chatId ${chatId} (userId ${userId}, username ${username})`);
});
// /notification-on-Befehl verarbeiten
bot.onText(/\/notification_on/, (msg) => {
const chatId = msg.chat.id;
// Benutzerdaten in user.yml laden
let users = yaml.load(USER_YML_PATH);
if (users[chatId]) {
users[chatId].notifications = true;
fs.writeFileSync(USER_YML_PATH, yaml.stringify(users, 4));
bot.sendMessage(chatId, 'Benachrichtigungen wurden aktiviert.');
} else {
bot.sendMessage(chatId, 'Du musst den Bot zuerst mit /start aktivieren.');
}
});
// /notification-off-Befehl verarbeiten
bot.onText(/\/notification_off/, (msg) => {
const chatId = msg.chat.id;
// Benutzerdaten in user.yml laden
let users = yaml.load(USER_YML_PATH);
if (users[chatId]) {
users[chatId].notifications = false;
fs.writeFileSync(USER_YML_PATH, yaml.stringify(users, 4));
bot.sendMessage(chatId, 'Benachrichtigungen wurden deaktiviert.');
} else {
bot.sendMessage(chatId, 'Du musst den Bot zuerst mit /start aktivieren.');
}
});
// /update Befehl
bot.onText(/\/update/, async (msg) => {
const chatId = msg.chat.id;
// Überprüfen, ob der Benutzer berechtigt ist
if (chatId.toString() !== process.env.DEV_CHAT_ID) {
bot.sendMessage(chatId, '❌ Du hast keine Berechtigung, diesen Befehl auszuführen.');
return;
}
try {
// Benutzer.yml laden
const userYmlData = yaml.load(USER_YML_PATH);
// Aktuelles Datum im Format 'YYYY-MM-DD'
const currentDate = dayjs().format('YYYY-MM-DD');
// Durchlaufe alle Benutzer und aktualisiere das Datum, falls es fehlt
for (const userId in userYmlData) {
if (!userYmlData[userId].firstUsed) {
userYmlData[userId].firstUsed = currentDate; // Setze das aktuelle Datum
}
// Überprüfen, ob das Feld favoriteGenre existiert
if (!userYmlData[userId].favoriteGenre) {
userYmlData[userId].favoriteGenre = "Nicht festgelegt"; // Setze Standardwert, wenn das Genre fehlt
}
}
// Benutzer.yml speichern
fs.writeFileSync(USER_YML_PATH, yaml.stringify(userYmlData, 4));
bot.sendMessage(chatId, '✅ Die user.yml wurde erfolgreich aktualisiert.');
} catch (error) {
logError(`Fehler beim Aktualisieren der user.yml: ${error.message}`);
bot.sendMessage(chatId, `❌ Fehler beim Aktualisieren der user.yml: ${error.message}`);
}
});
let lastAddedMovieTime = null; // Variable zum Speichern des Zeitpunkts des letzten Films
// Funktion zum Abrufen der letzten hinzugefügten Filme
async function fetchLatestMovies() {
try {
const response = await axios.get(`${PLEX_DOMAIN}/library/recentlyAdded?X-Plex-Token=${PLEX_TOKEN}`);
const movies = response.data.MediaContainer.Metadata;
if (movies && movies.length > 0) {
return movies;
}
return [];
} catch (error) {
console.error(`Error fetching latest movies: ${error.message}`);
return [];
}
}
// Funktion zum Überprüfen und Benachrichtigen über neue Filme
async function checkForNewMovies() {
try {
const movies = await fetchLatest10Movies(); // Verwende fetchLatest10Movies, um die letzten 10 Filme zu erhalten
if (movies.length > 0) {
const latestMovie = movies[0];
if (!lastAddedMovieTime || dayjs.unix(latestMovie.addedAt).isAfter(lastAddedMovieTime)) {
// Neuer Film wurde hinzugefügt und ist neuer als der zuletzt gesendete Film
lastAddedMovieTime = dayjs.unix(latestMovie.addedAt); // Update the last added movie time
const movieTitle = latestMovie.title || 'Unbekannt';
const movieSummary = latestMovie.summary || 'Keine Zusammenfassung verfügbar';
const movieThumb = latestMovie.thumb ? `${PLEX_DOMAIN}${latestMovie.thumb}?X-Plex-Token=${PLEX_TOKEN}` : '';
// Kürze die Zusammenfassung, wenn sie zu lang ist
const maxSummaryLength = 200; // Maximale Länge der Zusammenfassung
const truncatedSummary = movieSummary.length > maxSummaryLength
? `${movieSummary.substring(0, maxSummaryLength)}...`
: movieSummary;
const message = `Ein neuer Film wurde hinzugefügt:\n\nTitel: ${movieTitle}\n\nZusammenfassung:\n${truncatedSummary}`;
const users = yaml.load(USER_YML_PATH);
const sendMessages = Object.keys(users).map(chatId => {
if (users[chatId].notifications) {
if (movieThumb) {
// Wenn ein Bild vorhanden ist, sende es mit der Nachricht
return bot.sendPhoto(chatId, movieThumb, { caption: message }).catch(error => {
console.error(`Error sending photo to chatId ${chatId}: ${error.message}`);
});
} else {
// Wenn kein Bild vorhanden ist, sende nur die Nachricht
return bot.sendMessage(chatId, message).catch(error => {
console.error(`Error sending message to chatId ${chatId}: ${error.message}`);
});
}
}
}).filter(promise => promise !== undefined);
await Promise.all(sendMessages);
console.log(`Sent new movie message to all users`);
// Speichern der letzten gesendeten Zeit in einer Datei, um Wiederholungen zu vermeiden
fs.writeFileSync('lastAddedMovieTime.json', JSON.stringify({ time: lastAddedMovieTime.unix() }));
}
}
} catch (error) {
logError(`Error checking for new movies: ${error.message}`);
}
}
// Lade den letzten gesendeten Film-Zeitstempel beim Start des Bots
if (fs.existsSync('lastAddedMovieTime.json')) {
const lastAddedMovieData = JSON.parse(fs.readFileSync('lastAddedMovieTime.json'));
lastAddedMovieTime = dayjs.unix(lastAddedMovieData.time);
}
// Plane die kontinuierliche Überprüfung alle 1 Minute
schedule.scheduleJob('*/1 * * * *', checkForNewMovies);
// Initiale Überprüfung beim Start
checkForNewMovies();
// /latestmovie-Befehl verarbeiten
bot.onText(/\/latestmovie/, async (msg) => {
const chatId = msg.chat.id;
try {
const movies = await fetchAllMovies();
const sortedMovies = movies
.filter(movie => movie.addedAt)
.sort((a, b) => b.addedAt - a.addedAt);
const latestMovie = sortedMovies[0];
if (latestMovie) {
const movieTitle = latestMovie.title || 'Unbekannt';
const movieSummary = latestMovie.summary || 'Keine Zusammenfassung verfügbar';
const addedAtDate = new Date((latestMovie.addedAt || 0) * 1000).toLocaleString(); // Konvertierung von Unix-Zeitstempel in lesbares Datum
const movieThumb = latestMovie.thumb ? `${PLEX_DOMAIN}${latestMovie.thumb}?X-Plex-Token=${PLEX_TOKEN}` : '';
// Trailer-URL abrufen
const trailerUrl = await fetchTrailerUrl(latestMovie); // Funktion zum Abrufen des Trailer-Links
const message = `Der zuletzt hinzugefügte Film ist:\n\nTitel: ${movieTitle}\n\nZusammenfassung: \n${movieSummary}\n\nHinzugefügt am: ${addedAtDate}`;
// Erstelle den Inline-Button für den Trailer
const replyMarkup = {
inline_keyboard: [
[{ text: "Trailer ansehen", url: trailerUrl || '#' }] // Fallback-URL falls kein Trailer vorhanden
]
};
// 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}`);
});
} else {
bot.sendMessage(chatId, message, { reply_markup: replyMarkup }).catch(error => {
logError(`Error sending message to chatId ${chatId}: ${error.message}`);
});
}
logMessage(`Sent latest movie info to chatId ${chatId}`);
} else {
bot.sendMessage(chatId, 'Keine Filme gefunden.').catch(error => {
logError(`Error sending no movies message to chatId ${chatId}: ${error.message}`);
});
logMessage(`No movies found for chatId ${chatId}`);
}
} catch (error) {
if (error.response) {
bot.sendMessage(chatId, `Fehler beim Abrufen der neuesten Filme. Statuscode: ${error.response.status}`).catch(err => {
logError(`Error sending error message to chatId ${chatId}: ${err.message}`);
});
logError(`Error fetching latest movie: ${error.response.status} - ${error.response.statusText}`);
} else if (error.request) {
bot.sendMessage(chatId, 'Fehler beim Abrufen der neuesten Filme. Keine Antwort vom Server.').catch(err => {
logError(`Error sending no response message to chatId ${chatId}: ${err.message}`);
});
logError(`Error fetching latest movie: No response from server`);
} else {
logError(`Error fetching latest movie: ${error.message}`);
}
}
});
// /info-Befehl verarbeiten
bot.onText(/\/info/, async (msg) => {
const chatId = msg.chat.id;
const messageId = msg.message_id;
const plexDomain = PLEX_DOMAIN;
try {
// Überprüfe den Serverstatus
const serverStatus = await checkServerStatus();
const {
movieCount,
showCount,
episodeCount,
seasonCount,
topGenre,
totalSize,
oldestMovie,
newestMovie
} = await fetchAllMedia();
// Serverstatus Text
const serverStatusText = serverStatus
? '🟢 Server Status: Online'
: '🔴 Server Status: Offline';
const message = `${serverStatusText}\n\n` +
`*In der Bibliothek befinden sich derzeit:*\n\n` +
`📽️ Filme: ${movieCount}\n\n` +
`📺 Serien: ${showCount}\n\n` +
`🎞️ 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` +
`⏳ Ältester Film: ${oldestMovie.title} (${oldestMovie.year})\n\n` +
`🆕 Neuester Film: ${newestMovie.title} (${newestMovie.year})\n\n\n` +
`© 2024 M_Viper`;
const options = {
reply_markup: JSON.stringify({
inline_keyboard: [
[{ text: 'Zu Plex gehen', url: plexDomain }]
]
})
};
await bot.sendMessage(chatId, message, options).catch(error => {
logError(`Error sending message to chatId ${chatId}: ${error.message}`);
});
// Ursprüngliche Nachricht löschen (den /info-Befehl)
await bot.deleteMessage(chatId, messageId).catch(error => {
logError(`Error deleting message from chatId ${chatId}: ${error.message}`);
});
logMessage(`Sent detailed media info, copyright, and Plex button to chatId ${chatId}`);
} catch (error) {
logError(`Error fetching media info: ${error.message}`);
await bot.sendMessage(chatId, 'Fehler beim Abrufen der Medieninformationen.').catch(err => {
logError(`Error sending media info error message to chatId ${chatId}: ${err.message}`);
});
}
});
// Funktion zum Überprüfen des Serverstatus
async function checkServerStatus() {
try {
const response = await axios.get(`${PLEX_DOMAIN}/status`, {
headers: { 'X-Plex-Token': PLEX_TOKEN }
});
return response.status === 200; // Server ist online, wenn Status 200 zurückgegeben wird
} catch (error) {
console.error(`Server is offline or unreachable: ${error.message}`);
return false; // Server ist offline oder nicht erreichbar
}
}
// Funktion zum Abrufen von Plex-Daten
async function fetchPlexData(url) {
try {
const response = await axios.get(url, {
headers: { 'X-Plex-Token': PLEX_TOKEN }
});
return response.data;
} catch (error) {
logError(`Error fetching Plex data from ${url}: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen der erweiterten Medieninformationen
async function fetchAllMedia() {
try {
const movies = await fetchAllMovies();
const shows = await fetchAllShows();
const episodeCount = shows.reduce((sum, show) => sum + (show.leafCount || 0), 0);
const seasonCount = shows.reduce((sum, show) => sum + (show.childCount || 0), 0);
const topGenre = findTopGenre(movies.concat(shows));
const totalSize = await calculateTotalSize(movies.concat(shows));
const oldestMovie = findOldestMedia(movies);
const newestMovie = findNewestMedia(movies);
return {
movieCount: movies.length,
showCount: shows.length,
episodeCount: episodeCount,
seasonCount: seasonCount,
topGenre: topGenre,
totalSize: totalSize,
oldestMovie: oldestMovie,
newestMovie: newestMovie
};
} catch (error) {
logError(`Error fetching all media: ${error.message}`);
throw error;
}
}
// Funktion zur Ermittlung des am häufigsten vorkommenden Genres
function findTopGenre(mediaArray) {
const genreCount = {};
mediaArray.forEach(media => {
if (media.Genre) {
media.Genre.forEach(genre => {
genreCount[genre.tag] = (genreCount[genre.tag] || 0) + 1;
});
}
});
return Object.keys(genreCount).reduce((a, b) => genreCount[a] > genreCount[b] ? a : b, '');
}
// Funktion zur Berechnung der Gesamtgröße der Mediendateien
async function calculateTotalSize(mediaArray) {
let totalSizeBytes = 0;
for (const media of mediaArray) {
if (media.Media && media.Media.length > 0) {
media.Media.forEach(mediaItem => {
if (mediaItem.Part && mediaItem.Part.length > 0) {
mediaItem.Part.forEach(part => {
if (part.size) {
const sizeInBytes = parseInt(part.size, 10);
totalSizeBytes += sizeInBytes;
}
});
}
});
}
}
// Log total size in bytes for debugging
console.log(`Total size in bytes: ${totalSizeBytes}`);
// Convert bytes to terabytes (TB) and gigabytes (GB)
const totalSizeTB = totalSizeBytes / (1024 * 1024 * 1024 * 1024);
const totalSizeGB = totalSizeBytes / (1024 * 1024 * 1024);
// Log sizes in GB and TB
console.log(`Total size in TB: ${totalSizeTB}`);
console.log(`Total size in GB: ${totalSizeGB}`);
// Determine the appropriate size unit to display
if (totalSizeTB >= 1) {
return `${totalSizeTB.toFixed(2)} TB`;
} else {
return `${totalSizeGB.toFixed(2)} GB`;
}
}
// Funktion zum Finden des ältesten Mediums
function findOldestMedia(mediaArray) {
return mediaArray.reduce((oldest, media) => {
if (!oldest || (media.year && media.year < oldest.year)) {
return media;
}
return oldest;
}, null);
}
// Funktion zum Finden des neuesten Mediums
function findNewestMedia(mediaArray) {
return mediaArray.reduce((newest, media) => {
if (!newest || (media.year && media.year > newest.year)) {
return media;
}
return newest;
}, null);
}
// Funktion zum Abrufen aller Filme
async function fetchAllMovies() {
try {
const sectionsData = await fetchPlexData(`${PLEX_DOMAIN}/library/sections?X-Plex-Token=${PLEX_TOKEN}`);
const sections = sectionsData.MediaContainer.Directory;
let movies = [];
for (const section of sections) {
const sectionUrl = `${PLEX_DOMAIN}/library/sections/${section.key}/all?X-Plex-Token=${PLEX_TOKEN}`;
const sectionData = await fetchPlexData(sectionUrl);
if (sectionData.MediaContainer && sectionData.MediaContainer.Metadata) {
const metadata = sectionData.MediaContainer.Metadata;
movies = movies.concat(metadata.filter(media => media.type === 'movie'));
}
}
return movies;
} catch (error) {
logError(`Error fetching all movies: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen aller Serien
async function fetchAllShows() {
try {
const sectionsData = await fetchPlexData(`${PLEX_DOMAIN}/library/sections?X-Plex-Token=${PLEX_TOKEN}`);
const sections = sectionsData.MediaContainer.Directory;
let shows = [];
for (const section of sections) {
const sectionUrl = `${PLEX_DOMAIN}/library/sections/${section.key}/all?X-Plex-Token=${PLEX_TOKEN}`;
const sectionData = await fetchPlexData(sectionUrl);
if (sectionData.MediaContainer && sectionData.MediaContainer.Metadata) {
const metadata = sectionData.MediaContainer.Metadata;
shows = shows.concat(metadata.filter(media => media.type === 'show'));
}
}
return shows;
} catch (error) {
logError(`Error fetching all shows: ${error.message}`);
throw error;
}
}
// Fehlerprotokollierung
function logError(message) {
fs.appendFile(path.join(__dirname, 'Log', 'error.log'), `${new Date().toISOString()} - ${message}\n`, err => {
if (err) {
console.error(`Failed to log error: ${err.message}`);
}
});
}
// Erfolgsprotokollierung
function logMessage(message) {
fs.appendFile(path.join(__dirname, 'Log', 'message.log'), `${new Date().toISOString()} - ${message}\n`, err => {
if (err) {
console.error(`Failed to log message: ${err.message}`);
}
});
}
// Hilfsfunktion zum Abrufen von Plex-Daten
async function fetchPlexData(url) {
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
logError(`Error fetching Plex data: ${error.message}`);
throw error;
}
}
2024-10-20 20:09:31 +00:00
const usersNightMode = {}; // Temporärer Speicher für Nachtmodus
// 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 zum Anheften der Nachtmodus-Nachricht
function pinNightModeMessage(chatId, messageId) {
bot.pinChatMessage(chatId, messageId).catch(err => console.error('Fehler beim Anheften der Nachricht:', err));
}
// Funktion zum Entfernen der angehefteten Nachricht
function unpinNightModeMessage(chatId) {
bot.unpinChatMessage(chatId).catch(err => console.error('Fehler beim Entfernen der angehefteten Nachricht:', err));
}
// /night Befehl
bot.onText(/\/night/, (msg) => {
const chatId = msg.chat.id;
const userData = loadUserData(); // Lade die Benutzerdaten
const userId = chatId.toString();
// Standard-Buttons
const buttons = [];
// Überprüfen, ob der Benutzer bereits Nachtmodi hat
if (!userData[userId] || !userData[userId].nightModes || userData[userId].nightModes.length === 0) {
buttons.push([{ text: '🌙 Nachtmodus eingeben', callback_data: 'input_night_mode' }]);
} else {
buttons.push(
[
{ text: '🛠️ Nachtmodus bearbeiten', callback_data: 'edit_night_mode' },
{ text: ' Weiteren Nachtmodus eingeben', callback_data: 'add_night_mode' }
],
[{ text: '🗑️ Nachtmodus löschen', callback_data: 'delete_night_mode' }]
);
}
// Zeige die Inline-Buttons an
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', (query) => {
const chatId = query.message.chat.id;
const userId = chatId.toString();
const userData = loadUserData(); // Lade die Benutzerdaten
if (query.data === 'input_night_mode') {
// Eingabe eines neuen Nachtmodus
bot.sendMessage(chatId, 'Bitte geben Sie die Startzeit des Nachtmodus im Format HH:mm ein (z.B. 22:00):');
bot.once('message', (msg) => {
const startTime = msg.text;
// Sicherstellen, dass msg.text existiert und gültig ist
if (!startTime || !/^\d{2}:\d{2}$/.test(startTime)) {
return bot.sendMessage(chatId, 'Ungültiges Zeitformat. Bitte geben Sie die Zeit im Format HH:mm ein.');
}
bot.sendMessage(chatId, 'Bitte geben Sie die Endzeit des Nachtmodus im Format HH:mm ein (z.B. 06:00):');
bot.once('message', (msg) => {
const endTime = msg.text;
// Sicherstellen, dass msg.text existiert und gültig ist
if (!endTime || !/^\d{2}:\d{2}$/.test(endTime)) {
return bot.sendMessage(chatId, 'Ungültiges Zeitformat. Bitte geben Sie die Zeit im Format HH:mm ein.');
}
// Speichere die Nachtmodus-Daten
userData[userId] = userData[userId] || {};
userData[userId].nightModes = userData[userId].nightModes || [];
userData[userId].nightModes.push({ startTime, endTime });
saveUserData(userData); // Speichere die Daten in die yml-Datei
bot.sendMessage(chatId, `🌓 Nachtmodus geplant von ${startTime} bis ${endTime}.`);
});
});
} else if (query.data === 'edit_night_mode') {
// Bearbeiten eines bestehenden Nachtmodus
if (userData[userId] && userData[userId].nightModes && userData[userId].nightModes.length > 0) {
const nightModes = userData[userId].nightModes;
let nightModesText = 'Aktuelle Nachtmodi:\n';
nightModes.forEach((mode, index) => {
nightModesText += `${index + 1}: ${mode.startTime} bis ${mode.endTime}\n`;
});
nightModesText += 'Geben Sie die Nummer des Nachtmodus ein, den Sie bearbeiten möchten:';
bot.sendMessage(chatId, nightModesText);
bot.once('message', (msg) => {
const modeIndex = parseInt(msg.text) - 1;
if (isNaN(modeIndex) || modeIndex < 0 || modeIndex >= nightModes.length) {
return bot.sendMessage(chatId, 'Ungültige Auswahl.');
}
bot.sendMessage(chatId, 'Bitte geben Sie die neue Startzeit im Format HH:mm ein (z.B. 22:00):');
bot.once('message', (msg) => {
const newStartTime = msg.text;
// Sicherstellen, dass msg.text existiert und gültig ist
if (!newStartTime || !/^\d{2}:\d{2}$/.test(newStartTime)) {
return bot.sendMessage(chatId, 'Ungültiges Zeitformat. Bitte geben Sie die Zeit im Format HH:mm ein.');
}
bot.sendMessage(chatId, 'Bitte geben Sie die neue Endzeit im Format HH:mm ein (z.B. 06:00):');
bot.once('message', (msg) => {
const newEndTime = msg.text;
// Sicherstellen, dass msg.text existiert und gültig ist
if (!newEndTime || !/^\d{2}:\d{2}$/.test(newEndTime)) {
return bot.sendMessage(chatId, 'Ungültiges Zeitformat. Bitte geben Sie die Zeit im Format HH:mm ein.');
}
// Aktualisiere den Nachtmodus
userData[userId].nightModes[modeIndex] = { startTime: newStartTime, endTime: newEndTime };
saveUserData(userData); // Speichere die Änderungen
bot.sendMessage(chatId, `🌓 Nachtmodus aktualisiert auf ${newStartTime} bis ${newEndTime}.`);
});
});
});
} else {
bot.sendMessage(chatId, 'Es sind keine Nachtmodi zum Bearbeiten vorhanden.');
}
} else if (query.data === 'add_night_mode') {
// Eingabe eines weiteren Nachtmodus
bot.sendMessage(chatId, 'Bitte geben Sie die Startzeit des Nachtmodus im Format HH:mm ein (z.B. 22:00):');
bot.once('message', (msg) => {
const startTime = msg.text;
// Sicherstellen, dass msg.text existiert und gültig ist
if (!startTime || !/^\d{2}:\d{2}$/.test(startTime)) {
return bot.sendMessage(chatId, 'Ungültiges Zeitformat. Bitte geben Sie die Zeit im Format HH:mm ein.');
}
bot.sendMessage(chatId, 'Bitte geben Sie die Endzeit des Nachtmodus im Format HH:mm ein (z.B. 06:00):');
bot.once('message', (msg) => {
const endTime = msg.text;
// Sicherstellen, dass msg.text existiert und gültig ist
if (!endTime || !/^\d{2}:\d{2}$/.test(endTime)) {
return bot.sendMessage(chatId, 'Ungültiges Zeitformat. Bitte geben Sie die Zeit im Format HH:mm ein.');
}
// Speichere den neuen Nachtmodus
userData[userId].nightModes.push({ startTime, endTime });
saveUserData(userData); // Speichere die Daten in die yml-Datei
bot.sendMessage(chatId, `🌓 Weiterer Nachtmodus geplant von ${startTime} bis ${endTime}.`);
});
});
} else if (query.data === 'delete_night_mode') {
// Zeige Liste der Nachtmodi zum Löschen
if (userData[userId] && userData[userId].nightModes && userData[userId].nightModes.length > 0) {
const nightModes = userData[userId].nightModes;
let nightModesText = '🔄 **Bitte wählen Sie einen Nachtmodus zum Löschen:**\n\n';
nightModes.forEach((mode, index) => {
nightModesText += `🕒 **${index + 1}:** ${mode.startTime} bis ${mode.endTime}\n`;
});
nightModesText += '\n🗑 *Geben Sie die Nummer des Nachtmodus ein, den Sie löschen möchten:*';
bot.sendMessage(chatId, nightModesText);
bot.once('message', (msg) => {
const modeIndex = parseInt(msg.text) - 1;
if (isNaN(modeIndex) || modeIndex < 0 || modeIndex >= nightModes.length) {
return bot.sendMessage(chatId, 'Ungültige Auswahl.');
}
// Lösche den ausgewählten Nachtmodus
userData[userId].nightModes.splice(modeIndex, 1); // Lösche den Nachtmodus an der gegebenen Indexposition
saveUserData(userData); // Speichere die Änderungen
bot.sendMessage(chatId, '🗑️ Der ausgewählte Nachtmodus wurde gelöscht.');
});
} else {
bot.sendMessage(chatId, 'Es gibt keinen Nachtmodus, der gelöscht werden kann.');
}
}
});
// Funktion zur Überprüfung, ob der Benutzer im Nachtmodus ist
function isUserInNightMode(chatId) {
const userData = loadUserData();
const userId = chatId.toString();
const userNightModes = userData[userId] && userData[userId].nightModes;
if (!userNightModes || userNightModes.length === 0) return false;
const now = moment();
return userNightModes.some(userNightMode => {
const start = moment(userNightMode.startTime, 'HH:mm');
const end = moment(userNightMode.endTime, 'HH:mm');
if (end.isBefore(start)) {
return now.isAfter(start) || now.isBefore(end); // Nachtmodus über Mitternacht
} else {
return now.isBetween(start, end); // Normaler Nachtmodus
}
});
}
// Funktion zur automatischen Aktivierung des Nachtmodus
function activateNightMode() {
const userData = loadUserData();
for (const userId in userData) {
const userNightModes = userData[userId] && userData[userId].nightModes;
if (!userNightModes) continue;
const now = moment();
userNightModes.forEach(userNightMode => {
const start = moment(userNightMode.startTime, 'HH:mm');
const end = moment(userNightMode.endTime, 'HH:mm');
// Nachtmodus über Mitternacht
if (end.isBefore(start)) {
if (now.isAfter(start) || now.isBefore(end)) {
handleNightModeActivation(userId, userData);
} else {
handleNightModeDeactivation(userId, userData);
}
}
// Normaler Nachtmodus
else {
if (now.isBetween(start, end)) {
handleNightModeActivation(userId, userData);
} else {
handleNightModeDeactivation(userId, userData);
}
}
});
}
}
// Funktion zur Aktivierung des Nachtmodus
function handleNightModeActivation(userId, userData) {
if (userData[userId].notifications !== false) {
userData[userId].originalNotifications = userData[userId].notifications;
userData[userId].notifications = false;
saveUserData(userData);
bot.sendMessage(userId, `🌓 Der Nachtmodus hat begonnen. Deine Benachrichtigungen wurden auf Stumm geschaltet.`)
.then((msg) => {
// Pin die Nachricht
pinNightModeMessage(userId, msg.message_id);
});
console.log(`Nachtmodus für Benutzer ${userId} aktiviert.`);
}
}
// Funktion zur Deaktivierung des Nachtmodus
function handleNightModeDeactivation(userId, userData) {
if (userData[userId].notifications === false) {
userData[userId].notifications = userData[userId].originalNotifications;
delete userData[userId].originalNotifications;
saveUserData(userData);
bot.sendMessage(userId, `🌓 Der Nachtmodus endet, die Benachrichtigungen sind jetzt wieder aktiv.`)
.then(() => {
// Unpin die Nachricht
unpinNightModeMessage(userId);
});
console.log(`Nachtmodus für Benutzer ${userId} deaktiviert.`);
}
}
// Automatische Nachtmodus-Aktivierung überwachen
setInterval(() => {
activateNightMode();
}, 60 * 1000); // Überprüfung alle 60 Sekunden
2024-10-17 22:46:38 +00:00
// 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
if (!fs.existsSync(filePath)) {
// Datei erstellen und leeres Array als Inhalt speichern
fs.writeFileSync(filePath, JSON.stringify([], null, 2), (err) => {
if (err) {
console.error(`Fehler beim Erstellen der Datei 'w_offen.json': ${err}`);
}
});
console.log(`Die Datei 'w_offen.json' wurde im Hauptverzeichnis erstellt.`);
} else {
console.log(`Die Datei 'w_offen.json' existiert bereits.`);
}
}
// Funktion zum Erstellen des Ordners 'wunsch', falls dieser noch nicht existiert
function ensureWunschFolderExists() {
const folderPath = path.join(__dirname, 'wunsch');
if (!fs.existsSync(folderPath)) {
fs.mkdirSync(folderPath, { recursive: true });
console.log(`Ordner 'wunsch' wurde erstellt.`);
}
}
// Funktion zum Speichern eines Wunsches in der Datei 'wishes_<chatId>.json'
function saveWish(chatId, wish, type, fulfilled = false) {
ensureWunschFolderExists(); // Ordner sicherstellen
const filePath = path.join(__dirname, 'wunsch', `wishes_${chatId}.json`);
const wishData = { type, wish, fulfilled };
fs.readFile(filePath, (err, data) => {
let wishes = [];
if (!err) {
wishes = JSON.parse(data); // Vorhandene Wünsche lesen
}
wishes.push(wishData); // Neuen Wunsch hinzufügen
fs.writeFile(filePath, JSON.stringify(wishes, null, 2), (err) => {
if (err) {
console.error(`Fehler beim Speichern des Wunsches: ${err}`);
} else {
console.log(`Wunsch von ${chatId} erfolgreich gespeichert.`);
}
});
});
}
// Funktion zum Erstellen des Inline-Keyboards für die Auswahl von Film oder Serie
function getTypeKeyboard() {
return {
reply_markup: JSON.stringify({
inline_keyboard: [
2024-10-20 20:09:31 +00:00
[{ text: '🎬 Film', callback_data: 'type_film' }],
[{ text: '📺 Serie', callback_data: 'type_serie' }]
2024-10-17 22:46:38 +00:00
]
})
};
}
// Funktion zum Senden des Wunsches an zwei Benutzer mit Inline-Buttons für 'Erfüllt' und 'Nicht erfüllt'
async function sendWish(wish, type, chatId) {
const message = `✨ Achtung! ✨\n\nEin neuer Wunsch ist eingegangen:\n\n🔹 Typ: ${type}\n\n🔹 Titel:\n${wish}`;
// Inline-Keyboard mit den zwei Buttons
const inlineKeyboard = {
reply_markup: JSON.stringify({
inline_keyboard: [
[
2024-10-20 20:09:31 +00:00
{ text: '✅ Wunsch erfüllt', callback_data: `wish_fulfilled_${chatId}` },
{ text: '❌ Wunsch nicht erfüllt', callback_data: `wish_not_fulfilled_${chatId}` }
2024-10-17 22:46:38 +00:00
]
]
})
};
try {
2024-10-20 20:09:31 +00:00
const [msg1, msg2] = await Promise.all([
2024-10-17 22:46:38 +00:00
bot.sendMessage(USER1_ID, message, inlineKeyboard),
bot.sendMessage(USER2_ID, message, inlineKeyboard),
]);
console.log(`Wunsch von Typ ${type} wurde an ${USER1_ID} und ${USER2_ID} gesendet.`);
2024-10-20 20:09:31 +00:00
return { messageId1: msg1.message_id, messageId2: msg2.message_id }; // Rückgabe der Nachricht IDs
2024-10-17 22:46:38 +00:00
} catch (error) {
console.error(`Fehler beim Senden des Wunsches: ${error.message}`);
}
// Speichern des Wunsches in der Datei
saveWish(chatId, wish, type);
}
// Verarbeite Callback Queries (für die Inline-Buttons)
bot.on('callback_query', async (query) => {
const chatId = query.message.chat.id;
const data = query.data;
if (data.startsWith('type_')) {
// Benutzer hat den Typ ausgewählt (Film oder Serie)
const type = data === 'type_film' ? 'Film' : 'Serie';
2024-10-20 20:09:31 +00:00
await bot.sendMessage(chatId, `Du hast ${type} ausgewählt. Bitte gib den Titel des ${type} ein.`)
2024-10-17 22:46:38 +00:00
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
2024-10-20 20:09:31 +00:00
// Lösche die Nachricht der Kategorieauswahl
await bot.deleteMessage(chatId, query.message.message_id).catch(error => console.error(`Fehler beim Löschen der Nachricht: ${error.message}`));
2024-10-17 22:46:38 +00:00
userStates[chatId] = { type, waitingForWish: true }; // Setze den Status auf "wartend auf Wunsch"
}
if (data.startsWith('wish_fulfilled_')) {
const userId = data.split('_')[2]; // Der Ersteller des Wunsches
const messageText = query.message.text; // Der Text des Wunsches
const wishTitle = messageText.split('Titel:\n')[1].trim(); // Titel korrekt extrahieren
2024-10-20 20:09:31 +00:00
await bot.sendMessage(userId, '🎉 Dein Wunsch wurde erfüllt!')
2024-10-17 22:46:38 +00:00
.catch(error => console.error(`Fehler beim Senden der Nachricht: ${error.message}`));
2024-10-20 20:09:31 +00:00
2024-10-17 22:46:38 +00:00
// Wunsch in der Datei 'wishes_<chatId>.json' als erfüllt markieren
const filePath = path.join(__dirname, 'wunsch', `wishes_${userId}.json`);
fs.readFile(filePath, (err, data) => {
if (!err) {
let wishes = JSON.parse(data);
// Suche den spezifischen Wunsch und markiere ihn als erfüllt
wishes = wishes.map(wish => {
if (wish.wish === wishTitle) {
return { ...wish, fulfilled: true }; // Nur den spezifischen Wunsch als erfüllt markieren
}
return wish; // Alle anderen Wünsche unverändert lassen
});
2024-10-20 20:09:31 +00:00
2024-10-17 22:46:38 +00:00
fs.writeFile(filePath, JSON.stringify(wishes, null, 2), (err) => {
if (err) {
console.error(`Fehler beim Aktualisieren des Wunsches: ${err}`);
}
});
}
});
2024-10-20 20:09:31 +00:00
// Lösche die Wunschnachricht
await bot.deleteMessage(chatId, query.message.message_id);
2024-10-17 22:46:38 +00:00
}
2024-10-20 20:09:31 +00:00
2024-10-17 22:46:38 +00:00
if (data.startsWith('wish_not_fulfilled_')) {
const userId = query.message.chat.id; // Nutze die Chat-ID des Nachrichtenautors
2024-10-20 20:09:31 +00:00
await bot.sendMessage(userId, '😢 Dein Wunsch wurde leider nicht erfüllt.')
.catch(error => console.error(`Fehler beim Senden der Nachricht: ${error.message}`));
2024-10-17 22:46:38 +00:00
// Wunsch in der Datei 'w_offen.json' speichern
const filePath = path.join(__dirname, 'w_offen.json');
const wishDetails = {
2024-10-20 20:09:31 +00:00
userId: userId, // Chat-ID als userId speichern
message: query.message.text, // Nachricht als Wunsch speichern
2024-10-17 22:46:38 +00:00
};
fs.readFile(filePath, (err, data) => {
2024-10-20 20:09:31 +00:00
let openWishes = [];
if (!err && data.length > 0) {
openWishes = JSON.parse(data); // Vorhandene offene Wünsche lesen
2024-10-17 22:46:38 +00:00
}
2024-10-20 20:09:31 +00:00
openWishes.push(wishDetails); // Neuen offenen Wunsch hinzufügen
fs.writeFile(filePath, JSON.stringify(openWishes, null, 2), (err) => {
if (err) {
console.error(`Fehler beim Speichern des offenen Wunsches: ${err}`);
} else {
console.log('Der nicht erfüllte Wunsch wurde in der Datei "w_offen.json" gespeichert.');
}
});
2024-10-17 22:46:38 +00:00
});
2024-10-20 20:09:31 +00:00
// Lösche die Wunschnachricht
await bot.deleteMessage(chatId, query.message.message_id);
2024-10-17 22:46:38 +00:00
}
bot.answerCallbackQuery(query.id).catch(error => {
console.error(`Fehler bei der Callback-Abfrage: ${error.message}`);
});
});
// Verarbeite eingehende Nachrichten
bot.on('message', async (msg) => {
const chatId = msg.chat.id;
2024-10-20 20:09:31 +00:00
const text = msg.text || ''; // Sicherstellen, dass text definiert ist
2024-10-17 22:46:38 +00:00
if (userStates[chatId] && userStates[chatId].waitingForWish) {
const wish = text.trim();
if (wish) {
const type = userStates[chatId].type;
await sendWish(wish, type, chatId);
2024-10-20 20:09:31 +00:00
await bot.sendMessage(chatId, `✅ Dein ${type}-Wunsch wurde übermittelt.`)
2024-10-17 22:46:38 +00:00
.catch(error => console.error(`Fehler bei der Bestätigungsnachricht: ${error.message}`));
userStates[chatId].waitingForWish = false;
} else {
2024-10-20 20:09:31 +00:00
await bot.sendMessage(chatId, `✍️ Bitte gib den Titel des ${userStates[chatId].type} ein.`)
2024-10-17 22:46:38 +00:00
.catch(error => console.error(`Fehler bei der Wunsch-Nachricht: ${error.message}`));
}
return;
}
if (text.startsWith('/wunsch')) {
2024-10-20 20:09:31 +00:00
await bot.sendMessage(chatId, '🎬 Möchtest du einen Film oder eine Serie wünschen? Wähle bitte eine Option:', getTypeKeyboard())
2024-10-17 22:46:38 +00:00
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
userStates[chatId] = { waitingForType: true };
}
if (text.startsWith('/w_list')) {
// Liste der Wünsche für den Benutzer anzeigen
const filePath = path.join(__dirname, 'wunsch', `wishes_${chatId}.json`);
fs.readFile(filePath, (err, data) => {
if (err) {
bot.sendMessage(chatId, 'Es wurden keine Wünsche gefunden.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
} else {
const wishes = JSON.parse(data);
let wishList = '📜 Deine Wünsche:\n\n';
wishes.forEach((wish, index) => {
const statusEmoji = wish.fulfilled ? '🟢' : '🔴';
wishList += `${index + 1}. ${statusEmoji} ${wish.type}: ${wish.wish} \n\n`;
});
bot.sendMessage(chatId, wishList)
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
}
});
// Objekt zur Verfolgung der Benutzer, die auf eine Eingabe warten
let waitingForWishIndex = {};
2024-10-20 20:09:31 +00:00
// API-Endpunkt für offene Wünsche
app.get('/api/wishes', (req, res) => {
fs.readFile('w_offen.json', 'utf8', (err, data) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Lesen der Wünsche' });
2024-10-17 22:46:38 +00:00
}
2024-10-20 20:09:31 +00:00
res.json(JSON.parse(data));
2024-10-17 22:46:38 +00:00
});
});
// Verarbeite die Auswahl des Inline-Buttons zum Markieren eines Wunsches als erfüllt
bot.on('callback_query', (query) => {
const chatId = query.message.chat.id;
const data = query.data;
if (data === 'mark_wish_fulfilled') {
bot.sendMessage(chatId, 'Bitte gib die Nummer des Wunsches ein, den du als erfüllt markieren möchtest:')
.then(() => {
bot.once('message', (msg) => {
const wishIndex = parseInt(msg.text.trim()) - 1; // Wunschindex basierend auf der eingegebenen Zahl
// Lese die Datei 'w_offen.json' aus
const filePath = path.join(__dirname, 'w_offen.json');
fs.readFile(filePath, (err, data) => {
if (!err) {
let openWishes = JSON.parse(data);
if (wishIndex >= 0 && wishIndex < openWishes.length) {
const fulfilledWish = openWishes[wishIndex];
// Log zur Überprüfung
console.log(`Markiere Wunsch: ${fulfilledWish.message} von User ID: ${fulfilledWish.userId}`);
// Wunsch als erfüllt markieren in 'wishes_<userId>.json'
const userWishFile = path.join(__dirname, 'wunsch', `wishes_${fulfilledWish.userId}.json`);
fs.readFile(userWishFile, (err, wishData) => {
if (!err) {
let userWishes = JSON.parse(wishData);
// Suche den spezifischen Wunsch und markiere ihn als erfüllt
let wishFound = false;
// Extrahiere den Titel aus der Wunschnachricht
const wishMatch = fulfilledWish.message.match(/🔹 Titel:\s*(.*)/);
const extractedTitle = wishMatch ? wishMatch[1].trim() : '';
userWishes.forEach(wish => {
// Entferne Leerzeichen und Zeilenumbrüche vor dem Vergleich
const normalizedFileWishText = wish.wish.trim().toLowerCase();
console.log(`Wunschtext aus der Datei: "${normalizedFileWishText}"`);
console.log(`Wunschtext aus der Eingabe: "${extractedTitle.toLowerCase()}"`);
if (normalizedFileWishText === extractedTitle.toLowerCase()) {
wishFound = true;
wish.fulfilled = true; // Setze fulfilled auf true
console.log(`Wunsch "${wish.wish}" wurde erfolgreich auf 'fulfilled: true' gesetzt.`);
}
});
if (!wishFound) {
console.log(`Wunsch "${fulfilledWish.message}" nicht gefunden.`);
bot.sendMessage(chatId, 'Wunsch konnte nicht gefunden werden.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
} else {
// Schreibe die aktualisierte Wunschliste zurück in die Datei
fs.writeFile(userWishFile, JSON.stringify(userWishes, null, 2), (err) => {
if (err) {
console.error(`Fehler beim Aktualisieren des Wunsches: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Aktualisieren des Wunsches.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
} else {
// Entferne den Wunsch aus 'w_offen.json'
openWishes.splice(wishIndex, 1);
fs.writeFile(filePath, JSON.stringify(openWishes, null, 2), (err) => {
if (err) {
console.error(`Fehler beim Aktualisieren von 'w_offen.json': ${err}`);
bot.sendMessage(chatId, 'Fehler beim Aktualisieren der offenen Wünsche.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
} else {
bot.sendMessage(chatId, `Der Wunsch von User ID ${fulfilledWish.userId} wurde als erfüllt markiert.`)
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
}
});
}
} else {
console.error(`Fehler beim Lesen der Datei ${userWishFile}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Lesen der Benutzerdaten.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
} else {
bot.sendMessage(chatId, 'Ungültige Wunschnummer.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
} else {
console.error(`Fehler beim Lesen der Datei ${filePath}: ${err}`);
bot.sendMessage(chatId, 'Fehler beim Lesen der offenen Wünsche.')
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
});
});
})
.catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
}
bot.answerCallbackQuery(query.id).catch(error => {
console.error(`Fehler bei der Callback-Abfrage: ${error.message}`);
});
});
// /zufall-Befehl verarbeiten
bot.onText(/\/zufall/, async (msg) => {
const chatId = msg.chat.id;
try {
const randomMovie = await fetchRandomMovie();
if (randomMovie) {
const movieTitle = randomMovie.title || 'Unbekannt';
const movieSummary = randomMovie.summary || 'Keine Zusammenfassung verfügbar';
const movieThumb = randomMovie.thumb ? `${PLEX_DOMAIN}${randomMovie.thumb}?X-Plex-Token=${PLEX_TOKEN}` : '';
const message = `Hier ist ein zufälliger Film:\n\nTitel: ${movieTitle}\n\nZusammenfassung: \n${movieSummary}`;
// YouTube Trailer Link erstellen
const youtubeLink = `https://www.youtube.com/results?search_query=${encodeURIComponent(movieTitle + ' trailer')}`;
// Inline-Button für den Trailer hinzufügen
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: "Trailer ansehen",
url: youtubeLink,
}
]
]
}
};
// Bild anzeigen, wenn vorhanden
if (movieThumb) {
bot.sendPhoto(chatId, movieThumb, { caption: message, reply_markup: options.reply_markup }).catch(error => {
logError(`Error sending photo to chatId ${chatId}: ${error.message}`);
});
} else {
bot.sendMessage(chatId, message, options).catch(error => {
logError(`Error sending message to chatId ${chatId}: ${error.message}`);
});
}
logMessage(`Sent random movie info to chatId ${chatId}`);
} else {
bot.sendMessage(chatId, 'Keine Filme gefunden.').catch(error => {
logError(`Error sending no movies message to chatId ${chatId}: ${error.message}`);
});
logMessage(`No movies found for chatId ${chatId}`);
}
} catch (error) {
if (error.response) {
bot.sendMessage(chatId, `Fehler beim Abrufen eines zufälligen Films. Statuscode: ${error.response.status}`).catch(err => {
logError(`Error sending error message to chatId ${chatId}: ${err.message}`);
});
logError(`Error fetching random movie: ${error.response.status} - ${error.response.statusText}`);
} else if (error.request) {
bot.sendMessage(chatId, 'Fehler beim Abrufen eines zufälligen Films. Keine Antwort vom Server.').catch(err => {
logError(`Error sending no response message to chatId ${chatId}: ${err.message}`);
});
logError(`Error fetching random movie: No response from server`);
} else {
bot.sendMessage(chatId, 'Fehler beim Abrufen eines zufälligen Films. Unbekannter Fehler.').catch(err => {
logError(`Error sending unknown error message to chatId ${chatId}: ${err.message}`);
});
logError(`Error fetching random movie: ${error.message}`);
}
}
});
// Speichern des Status der Benutzerinteraktionen
const userStates = {}; // Einfache In-Memory-Datenstruktur
// /search-Befehl verarbeiten
bot.onText(/\/search/, (msg) => {
const chatId = msg.chat.id;
// Setze den Status auf "wartet auf Suchbegriff"
userStates[chatId] = { waitingForQuery: true };
const message = 'Bitte gib den Suchbegriff für die Film-Suche ein.';
bot.sendMessage(chatId, message).catch(error => {
logError(`Error sending search prompt to chatId ${chatId}: ${error.message}`);
});
logMessage(`Prompted for search query from chatId ${chatId}`);
});
// Eingehende Nachrichten verarbeiten
bot.on('message', async (msg) => {
const chatId = msg.chat.id;
const text = msg.text;
// Überprüfen, ob der Benutzer auf eine Suchabfrage wartet
if (userStates[chatId] && userStates[chatId].waitingForQuery) {
const query = text; // Suchbegriff erhalten
try {
const results = await searchMovies(query);
if (results.length === 0) {
await bot.sendMessage(chatId, 'Keine Filme gefunden, die deiner Suche entsprechen.').catch(error => {
logError(`Error sending no results message to chatId ${chatId}: ${error.message}`);
});
logMessage(`No search results found for chatId ${chatId} with query "${query}"`);
} else {
// Erstelle Nachrichten für jedes Ergebnis
const messages = results.map(async (movie) => {
const { title, summary, thumb } = movie;
const movieThumbUrl = thumb ? `${process.env.PLEX_DOMAIN}${thumb}?X-Plex-Token=${process.env.PLEX_TOKEN}` : '';
const message = `Titel: ${title}\n\nZusammenfassung: \n\n${summary}`;
try {
if (movieThumbUrl) {
await bot.sendPhoto(chatId, movieThumbUrl, { caption: message });
logMessage(`Sent photo for movie "${title}" to chatId ${chatId}`);
} else {
await bot.sendMessage(chatId, message);
logMessage(`Sent message for movie "${title}" to chatId ${chatId}`);
}
} catch (error) {
logError(`Error sending message or photo to chatId ${chatId}: ${error.message}`);
// Optional: Sende nur die Textnachricht, wenn das Bild nicht gesendet werden konnte
await bot.sendMessage(chatId, message).catch(err => {
logError(`Error sending fallback message to chatId ${chatId}: ${err.message}`);
});
}
});
// Führe alle Nachrichten-Operationen aus
await Promise.all(messages);
logMessage(`Sent search results for query "${query}" to chatId ${chatId}`);
}
} catch (error) {
let errorMessage = 'Fehler beim Durchführen der Suche.';
if (error.response) {
errorMessage += ` Statuscode: ${error.response.status}`;
logError(`Error searching movies: ${error.response.status} - ${error.response.statusText}`);
} else if (error.request) {
errorMessage += ' Keine Antwort vom Server.';
logError(`Error searching movies: No response from server`);
} else {
errorMessage += ` Unbekannter Fehler: ${error.message}`;
logError(`Error searching movies: ${error.message}`);
}
await bot.sendMessage(chatId, errorMessage).catch(err => {
logError(`Error sending search error message to chatId ${chatId}: ${err.message}`);
});
}
// Benutzerstatus zurücksetzen
userStates[chatId].waitingForQuery = false;
}
});
// Funktion zum Abrufen der Filme basierend auf der Suche
async function searchMovies(query) {
try {
// Placeholder für die tatsächliche Implementierung
// Diese Funktion sollte Filme basierend auf dem Suchbegriff abfragen und zurückgeben
const movies = await fetchMoviesFromAPI(query); // Ersetze dies durch die echte Implementierung
return movies;
} catch (error) {
logError(`Error searching movies: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen der Filme aus der API (placeholder)
async function fetchMoviesFromAPI(query) {
try {
const url = `${process.env.PLEX_DOMAIN}/search?query=${encodeURIComponent(query)}&X-Plex-Token=${process.env.PLEX_TOKEN}`;
const response = await axios.get(url);
return response.data.MediaContainer.Metadata; // Oder wie auch immer die API antwortet
} catch (error) {
logError(`Error fetching movies from API: ${error.message}`);
throw error;
}
}
// Array, um empfohlene Filme zu speichern
const recommendedMovies = [];
let dailyMovieCache = {}; // Cache für den Film des Tages
// Funktion zum Abrufen des täglichen Films basierend auf dem Datum
async function fetchDailyRecommendation() {
try {
// Berechne das heutige Datum
const today = moment().format('YYYY-MM-DD');
// Überprüfen, ob wir bereits einen Film für heute gespeichert haben
if (dailyMovieCache[today]) {
return dailyMovieCache[today];
}
// Anfrage zur Mediathek, um alle Filme abzurufen
const url = `${process.env.PLEX_DOMAIN}/library/sections/1/all?X-Plex-Token=${process.env.PLEX_TOKEN}`;
const response = await axios.get(url);
const data = response.data;
if (data && data.MediaContainer && Array.isArray(data.MediaContainer.Metadata) && data.MediaContainer.Metadata.length > 0) {
// Wähle einen zufälligen Film aus der Liste der Filme aus
const movies = data.MediaContainer.Metadata;
const randomIndex = Math.floor(Math.random() * movies.length);
const selectedMovie = movies[randomIndex];
// Speichern des Films für heute im Cache
dailyMovieCache[today] = selectedMovie;
return selectedMovie;
} else {
// Protokolliere, wenn keine Filme gefunden wurden
console.log('No movies found in API response or unexpected response format');
return null;
}
} catch (error) {
logError(`Error fetching daily recommendation from API: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen des Trailers für einen bestimmten Film
async function fetchTrailerUrl(filmTitle) {
try {
// YouTube API URL für die Suche
const url = `https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&q=${encodeURIComponent(filmTitle + ' trailer')}&key=${process.env.YOUTUBE_API_KEY}`;
const response = await axios.get(url);
const videos = response.data.items;
// Überprüfen, ob Videos gefunden wurden
if (videos.length > 0) {
const videoId = videos[0].id.videoId; // ID des ersten gefundenen Trailers
return `https://www.youtube.com/watch?v=${videoId}`; // URL des Trailers
} else {
return null; // Kein Trailer gefunden
}
} catch (error) {
logError(`Error fetching trailer URL: ${error.message}`);
return null; // Fehler beim Abrufen des Trailers
}
}
// Funktion zum Kürzen der Zusammenfassung
function truncateSummary(summary, maxLength) {
if (summary.length > maxLength) {
return summary.slice(0, maxLength) + '...'; // Kürzen und "..." hinzufügen
}
return summary;
}
// Funktion zum Erstellen der Bildunterschrift
function createCaption(title, summary) {
// Initiale Bildunterschrift ohne Kürzung
let caption = `
Hier ist der empfohlene Film des Tages:
🎬 Titel: ${title || 'Unbekannt'}
📝 Zusammenfassung:
${summary || 'Keine Zusammenfassung verfügbar'}
`;
// Überprüfen, ob die Bildunterschrift zu lang ist
if (caption.length > MAX_CAPTION_LENGTH) {
// Berechnen der maximalen Länge für die Zusammenfassung
const maxSummaryLength = MAX_CAPTION_LENGTH - (caption.length - summary.length);
// Kürzen der Zusammenfassung auf die berechnete Länge
const truncatedSummary = truncateSummary(summary, maxSummaryLength);
// Neu zusammenstellen der Bildunterschrift mit der gekürzten Zusammenfassung
caption = `
Hier ist der empfohlene Film des Tages:
🎬 Titel: ${title || 'Unbekannt'}
📝 Zusammenfassung:
${truncatedSummary}
`;
}
return caption;
}
// /empfehlung-Befehl verarbeiten
bot.onText(/\/empfehlung/, async (msg) => {
const chatId = msg.chat.id;
try {
const dailyMovie = await fetchDailyRecommendation();
if (dailyMovie) {
// Film empfehlen
const movieTitle = dailyMovie.title || 'Unbekannt';
const movieSummary = dailyMovie.summary || 'Keine Zusammenfassung verfügbar';
const movieThumb = dailyMovie.thumb ? `${process.env.PLEX_DOMAIN}${dailyMovie.thumb}?X-Plex-Token=${process.env.PLEX_TOKEN}` : '';
// Erstellen der Bildunterschrift und Kürzen, falls nötig
const message = createCaption(movieTitle, movieSummary);
// Trailer URL abrufen
const trailerUrl = await fetchTrailerUrl(movieTitle);
// Bild anzeigen, wenn vorhanden
if (movieThumb) {
const options = {
caption: message,
parse_mode: 'Markdown',
reply_markup: {
inline_keyboard: [
[
{
text: "Trailer ansehen",
url: trailerUrl || "https://www.youtube.com", // Fallback-URL, falls kein Trailer gefunden wird
}
]
]
}
};
await bot.sendPhoto(chatId, movieThumb, options).catch(error => {
logError(`Error sending photo to chatId ${chatId}: ${error.message}`);
});
} else {
const options = {
parse_mode: 'Markdown',
reply_markup: {
inline_keyboard: [
[
{
text: "Trailer ansehen",
url: trailerUrl || "https://www.youtube.com", // Fallback-URL, falls kein Trailer gefunden wird
}
]
]
}
};
await bot.sendMessage(chatId, message, options).catch(error => {
logError(`Error sending message to chatId ${chatId}: ${error.message}`);
});
}
logMessage(`Sent daily recommendation to chatId ${chatId}`);
} else {
await bot.sendMessage(chatId, 'Keine Empfehlungen verfügbar.').catch(error => {
logError(`Error sending no recommendation message to chatId ${chatId}: ${error.message}`);
});
logMessage(`No daily recommendation found for chatId ${chatId}`);
}
} catch (error) {
let errorMessage = 'Fehler beim Abrufen der Empfehlung.';
if (error.response) {
errorMessage += ` Statuscode: ${error.response.status}`;
logError(`Error fetching daily recommendation: ${error.response.status} - ${error.response.statusText}`);
} else if (error.request) {
errorMessage += ' Keine Antwort vom Server.';
logError(`Error fetching daily recommendation: No response from server`);
} else {
errorMessage += ` Unbekannter Fehler: ${error.message}`;
logError(`Error fetching daily recommendation: ${error.message}`);
}
await bot.sendMessage(chatId, errorMessage).catch(err => {
logError(`Error sending daily recommendation error message to chatId ${chatId}: ${err.message}`);
});
}
});
// Session-Management für Feedback
const feedbackSessions = {};
// Fehlerprotokollierungsfunktion
function logError(error) {
const errorMessage = `${dayjs().format('HH:mm:ss')} - Error: ${error}\n`;
fs.appendFileSync(ERROR_LOG_PATH, errorMessage);
}
// Speichert Feedback in der Datei
function saveFeedbackToFile(feedbackData) {
// Wenn die Datei nicht existiert, erstelle sie mit dem Header
if (!fs.existsSync(feedbackFilePath)) {
fs.writeFileSync(feedbackFilePath, 'timestamp - chatId: feedback\n');
}
const feedback = `${feedbackData.timestamp} - chatId ${feedbackData.chatId}: ${feedbackData.feedback}\n`;
fs.appendFileSync(feedbackFilePath, feedback);
}
// Sendet Feedback an Administratoren
function sendFeedbackToAdmins(userId, feedback) {
const adminChatIds = [USER1_ID, USER2_ID]; // Hier sollten die IDs der Administratoren festgelegt werden
const message = `📢 Neues Feedback:\n\n Von userId: "${userId}"\n\n"${feedback}"`;
adminChatIds.forEach(adminChatId => {
bot.sendMessage(adminChatId, message).catch(error => {
logError(`Fehler beim Senden von Feedback an Admin chatId ${adminChatId}: ${error.message}`);
});
});
}
const feedbackFilePath = path.join(__dirname, 'feedback.log'); // Überprüfe, ob dieser Pfad korrekt ist
// Fehlerprotokollierungsfunktion
function logError(error) {
const errorMessage = `${new Date().toISOString()} - Error: ${error.message || error}\n`;
try {
fs.appendFileSync(errorLogPath, errorMessage);
} catch (err) {
console.error('Fehler beim Schreiben in die Fehlerprotokolldatei:', err.message);
}
}
// Funktion, die überprüft, ob ein Benutzer autorisiert ist
function isUserAuthorized(userId) {
const authorizedUsers = [process.env.USER1_ID, process.env.USER2_ID];
return authorizedUsers.includes(userId.toString());
}
// Funktion, die überprüft, ob ein Benutzer autorisiert ist
function isUserAuthorized(userId) {
const authorizedUsers = [process.env.USER1_ID, process.env.USER2_ID];
return authorizedUsers.includes(userId.toString());
}
// Speichert Feedback in der Datei
function saveFeedbackToFile({ chatId, feedback, timestamp }) {
const feedbackEntry = `${timestamp} - chatId ${chatId}: ${feedback}\n`;
try {
if (!fs.existsSync(feedbackFilePath)) {
fs.writeFileSync(feedbackFilePath, 'timestamp - chatId: feedback\n');
}
fs.appendFileSync(feedbackFilePath, feedbackEntry);
} catch (err) {
logError(`Fehler beim Speichern des Feedbacks: ${err.message}`);
}
}
// Sendet Feedback an Administratoren
function sendFeedbackToAdmins(userId, feedback) {
const adminChatIds = [process.env.USER1_ID, process.env.USER2_ID];
const message = `
*Neues Feedback*
🆔 *User ID:* ${userId}
📌 *Zusammenfassung:* 📌
${feedback}
`;
adminChatIds.forEach(adminChatId => {
bot.sendMessage(adminChatId, message)
.catch(error => {
logError(`Fehler beim Senden von Feedback an Admin chatId ${adminChatId}: ${error.message}`);
});
});
}
// Handler für den /feedback Befehl
bot.onText(/\/feedback/, (msg) => {
const chatId = msg.chat.id;
// Startet eine Feedback-Sitzung
feedbackSessions[chatId] = { waitingForFeedback: true };
bot.sendMessage(chatId, '✍️ Bitte gib dein Feedback ein. Du kannst den Befehl `/cancel` verwenden, um das Feedback zu abbrechen.', { parse_mode: 'Markdown' })
.catch(error => {
logError(`Fehler beim Senden der Feedback-Aufforderung an chatId ${chatId}: ${error.message}`);
});
});
// Handler für den /cancel Befehl
bot.onText(/\/cancel/, (msg) => {
const chatId = msg.chat.id;
if (feedbackSessions[chatId]) {
delete feedbackSessions[chatId];
bot.sendMessage(chatId, 'Feedback wurde abgebrochen.', { parse_mode: 'Markdown' })
.catch(error => {
logError(`Fehler beim Senden der Abbruch-Nachricht an chatId ${chatId}: ${error.message}`);
});
}
});
// Handler für Nachrichten
bot.on('message', (msg) => {
const chatId = msg.chat.id;
if (feedbackSessions[chatId] && msg.text && msg.text !== '/cancel') {
const feedback = msg.text;
const userId = msg.from.id; // Die userId des Feedbackers
saveFeedbackToFile({ chatId, feedback, timestamp: dayjs().format('YYYY-MM-DD HH:mm:ss') });
sendFeedbackToAdmins(userId, feedback);
bot.sendMessage(chatId, '👍 Danke für dein Feedback!', { parse_mode: 'Markdown' })
.catch(error => {
logError(`Fehler beim Senden der Bestätigung an chatId ${chatId}: ${error.message}`);
});
delete feedbackSessions[chatId];
}
});
// Beispiel zur erweiterten Fehlerbehandlung im Bot
bot.on('polling_error', (error) => {
logError(`Polling Error: ${error.code} - ${error.message}`);
});
// Handler für den /f_log Befehl
bot.onText(/\/f_log/, (msg) => {
const chatId = msg.chat.id;
const userId = msg.from.id;
if (isUserAuthorized(userId)) {
try {
if (fs.existsSync(feedbackFilePath)) {
const tempFilePath = path.join(__dirname, 'feedback_log.txt');
const feedbackData = fs.readFileSync(feedbackFilePath, 'utf8');
fs.writeFileSync(tempFilePath, feedbackData);
bot.sendDocument(chatId, tempFilePath)
.then(() => {
fs.unlinkSync(tempFilePath);
console.log('Feedback-Log-Datei erfolgreich gesendet und gelöscht.');
})
.catch(error => {
logError(`Fehler beim Senden der feedback_log.txt an chatId ${chatId}: ${error.message}`);
bot.sendMessage(chatId, '❌ Fehler beim Senden der Feedback-Log-Datei.')
.catch(err => {
logError(`Fehler beim Senden der Fehlermeldung an chatId ${chatId}: ${err.message}`);
});
});
} else {
const errMsg = `Keine Feedback-Datei gefunden unter ${feedbackFilePath}.`;
console.log(errMsg);
bot.sendMessage(chatId, `${errMsg}`)
.catch(error => {
logError(`Fehler beim Senden der Fehlermeldung an chatId ${chatId}: ${error.message}`);
});
}
} catch (error) {
logError(`Fehler beim Senden der Feedback-Log-Datei: ${error.message}`);
bot.sendMessage(chatId, '❌ Fehler beim Senden der Feedback-Log-Datei.')
.catch(err => {
logError(`Fehler beim Senden der Fehlermeldung an chatId ${chatId}: ${err.message}`);
});
}
} else {
const errMsg = `Unberechtigter Zugriff auf /f_log von userId ${userId}.`;
console.log(errMsg);
bot.sendMessage(chatId, `${errMsg}`)
.catch(error => {
logError(`Unberechtigter Zugriff auf /f_log von userId ${userId}: ${error.message}`);
});
}
});
// Funktion zum Erstellen der allgemeinen Hilfennachricht
function createHelpMessage() {
return `📜 *Hier ist eine Liste der verfügbaren Befehle:*\n\n` +
`👋 /start - Registriert deinen Zugang.\n\n` +
`🔔 /notification\\_on - Aktiviert Benachrichtigungen für neue Filme.\n\n` +
`🔕 /notification\\_off - Deaktiviert Benachrichtigungen für neue Filme.\n\n` +
`📺 /serien - Zeigt eine Liste aller Serien an.\n\n` +
`🎬 /latestmovie - Zeigt den zuletzt hinzugefügten Film an.\n\n` +
`📅 /latest10movies - Zeigt die letzten 10 hinzugefügten Filme an.\n\n` +
`⭐ /top\\_rated - Zeigt die am besten bewerteten Filme an.\n\n` +
`💭 /wunsch - Nutze diesen Befehl, um einen Filmwunsch zu äußern.\n\n` +
`🎬 /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` +
2024-10-22 16:27:11 +00:00
`🌙 /night - Schaltet den Nachtmodus ein oder aus.\n\n` + // Hinzugefügter Befehl
2024-10-17 22:46:38 +00:00
`❓ /help - Zeigt diese Hilfennachricht an.\n\n`;
}
// Funktion zum Erstellen der weiteren Hilfennachricht
function createMoreHelpMessage() {
return `📜 *weitere Hilfe:*\n\n` +
`📝 /profil - Zeigt dein Profil an\n\n` +
`✨ /w\\_list - Zeigt dir deine Wünsche an.\n\n` +
`🔧 /dev - Funktionswunsch oder Bug melden.\n\n` +
`💬 /feedback - Gib Feedback zum Bot.\n\n` +
`❓ /faq - Häufig gestellte Fragen.\n\n` +
` /info - Anzahl Filme und Serien.\n\n` +
`🤖 /bot - Bot-Informationen.\n\n`;
}
2024-10-22 16:27:11 +00:00
2024-10-17 22:46:38 +00:00
// Funktion zum Erstellen der Admin-Hilfennachricht
function createAdminHelpMessage() {
return `*👨‍💻 Admin Befehle* \n\n` +
`🛠️ /admin - 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` +
`📰 /newsletter - Zeigt die Newsletter Funktion an\n\n` +
`📝 /logs - Zeigt die letzten Fehlermeldungen an.\n\n` +
`🗑️ /log\\_delete - Löscht Logs.\n\n` +
`📝 /f\\_log - Sendet das Feedback als .txt-Datei.\n\n` +
`❓ /add\\_faq - Fügt eine neue Frage zur FAQ hinzu.\n\n` +
`🗑️ /del\\_faq - Löscht eine FAQ.\n\n\n`+
`*👨‍💻 Dev Befehle* \n\n` +
`🔄 /update - Aktuallisiert die user.yml\n\n` +
`🗃️ /command\\_history - Zeigt eine Liste der zuletzt verwendeten Befehle an.\n\n` +
`💾 /backup - erstellt ein Backup und sendet es als zip\n\n` +
`🪧 /serverinfo - Zeigt Informationen über den Server\n\n` +
`🔍 /healthcheck - Überprüft den Bot\n\n` +
`🔄 /setdebug - Aktiviert oder deaktiviert den Debug-Modus\n\n` +
`🛠️ /support - Erstellt ein Support-Ticket an den Bot-Ersteller.\n\n`;
}
// /help-Befehl verarbeiten
bot.onText(/\/help/, (msg) => {
const chatId = msg.chat.id;
// Prüfen, ob der Benutzer ein Admin ist
const isAdmin = chatId.toString() === process.env.USER1_ID || chatId.toString() === process.env.USER2_ID;
if (!isAdmin) {
// Normale Benutzer: Hilfennachricht und "Mehr"-Button anzeigen
const helpMessage = createHelpMessage();
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: "Mehr",
callback_data: "more_help",
},
{
text: "Kontakt",
url: process.env.CONTACT_LINK,
}
]
]
},
parse_mode: 'Markdown'
};
bot.sendMessage(chatId, helpMessage, options).catch(error => {
console.log(`Error sending help message to chatId ${chatId}: ${error.message}`);
});
} else {
// Admin-Benutzer: Buttons "User Hilfe" und "Admin Hilfe" anzeigen
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: "User Hilfe",
callback_data: "user_help"
},
{
text: "Admin Hilfe",
callback_data: "admin_help",
}
]
]
},
parse_mode: 'Markdown'
};
bot.sendMessage(chatId, "Bitte wähle eine Option:", options).catch(error => {
console.log(`Error sending admin help buttons to chatId ${chatId}: ${error.message}`);
});
}
});
// Callback für die Inline-Buttons verarbeiten
bot.on('callback_query', (callbackQuery) => {
const chatId = callbackQuery.message.chat.id;
const data = callbackQuery.data;
if (data === "user_help") {
const helpMessage = createHelpMessage();
// Inline-Button für "Mehr" und Kontakt hinzufügen
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: "Mehr",
callback_data: "more_help",
},
{
text: "Kontakt",
url: process.env.CONTACT_LINK,
}
]
]
},
parse_mode: 'Markdown'
};
bot.sendMessage(chatId, helpMessage, options).catch(error => {
console.log(`Error sending user help message to chatId ${chatId}: ${error.message}`);
});
} else if (data === "more_help") {
const moreHelpMessage = createMoreHelpMessage();
// Kontakt-Button hinzufügen
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: "Kontakt",
url: process.env.CONTACT_LINK,
}
]
]
},
parse_mode: 'Markdown'
};
bot.sendMessage(chatId, moreHelpMessage, options).catch(error => {
console.log(`Error sending more help message to chatId ${chatId}: ${error.message}`);
});
} else if (data === "admin_help") {
// Überprüfung, ob der Benutzer berechtigt ist
if (chatId.toString() === process.env.USER1_ID || chatId.toString() === process.env.USER2_ID) {
const adminHelpMessage = createAdminHelpMessage();
const options = {
reply_markup: {
inline_keyboard: [
[
{
text: "Kontakt",
url: process.env.CONTACT_LINK,
}
]
]
},
parse_mode: 'Markdown'
};
bot.sendMessage(chatId, adminHelpMessage, options).catch(error => {
console.log(`Error sending admin help message to chatId ${chatId}: ${error.message}`);
});
} else {
bot.sendMessage(chatId, "Du hast keine Berechtigung, diesen Befehl zu verwenden.", { parse_mode: 'Markdown' }).catch(error => {
console.log(`Error sending unauthorized message to chatId ${chatId}: ${error.message}`);
});
}
}
});
// Funktion zum Abrufen der letzten 10 hinzugefügten Filme
async function fetchLatest10Movies() {
try {
const movies = await fetchAllMovies();
const sortedMovies = movies
.filter(movie => movie.addedAt)
.sort((a, b) => b.addedAt - a.addedAt)
.slice(0, 10); // Nimm nur die neuesten 10 Filme
return sortedMovies;
} catch (error) {
logError(`Error fetching latest 10 movies: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen der letzten 10 hinzugefügten Filme
async function fetchLatest10Movies() {
try {
const movies = await fetchAllMovies();
const sortedMovies = movies
.filter(movie => movie.addedAt)
.sort((a, b) => b.addedAt - a.addedAt)
.slice(0, 10); // Nimm nur die neuesten 10 Filme
return sortedMovies;
} catch (error) {
logError(`Error fetching latest 10 movies: ${error.message}`);
throw error;
}
}
// Funktion zum Abrufen der letzten 10 hinzugefügten Filme
async function fetchLatest10Movies() {
try {
const movies = await fetchAllMovies();
const sortedMovies = movies
.filter(movie => movie.addedAt)
.sort((a, b) => b.addedAt - a.addedAt)
.slice(0, 10); // Nimm nur die neuesten 10 Filme
return sortedMovies;
} catch (error) {
logError(`Error fetching latest 10 movies: ${error.message}`);
throw error;
}
}
// Maximal zulässige Länge der Bildunterschrift (in Zeichen)
const MAX_CAPTION_LENGTH = 1024; // Telegrams Beschränkung für Bildunterschriften
// Funktion zum Kürzen der Zusammenfassung
function truncateSummary(summary, maxLength) {
if (summary.length > maxLength) {
return summary.slice(0, maxLength) + '...'; // Kürzen und "..." hinzufügen
}
return summary;
}
// Funktion zum Erstellen der Bildunterschrift
function createCaption(title, summary, addedAt) {
// Initiale Bildunterschrift ohne Kürzung
let caption = `
🎬 Titel: ${title || 'Unbekannt'}
📝 Zusammenfassung:
${summary || 'Keine Zusammenfassung verfügbar.'}
📅 Hinzugefügt am: ${dayjs(addedAt * 1000).format('DD.MM.YYYY')}
`;
// Überprüfen, ob die Bildunterschrift zu lang ist
if (caption.length > MAX_CAPTION_LENGTH) {
// Berechnen der maximalen Länge für die Zusammenfassung
const maxSummaryLength = MAX_CAPTION_LENGTH - (caption.length - summary.length);
// Kürzen der Zusammenfassung auf die berechnete Länge
const truncatedSummary = truncateSummary(summary, maxSummaryLength);
// Neu zusammenstellen der Bildunterschrift mit der gekürzten Zusammenfassung
caption = `
🎬 Titel: ${title || 'Unbekannt'}
📝 Zusammenfassung:
${truncatedSummary}
📅 Hinzugefügt am: ${dayjs(addedAt * 1000).format('DD.MM.YYYY')}
`;
}
return caption;
}
// /latest10movies-Befehl verarbeiten
bot.onText(/\/latest10movies/, async (msg) => {
const chatId = msg.chat.id;
try {
const latestMovies = await fetchLatest10Movies();
if (latestMovies.length > 0) {
const numberEmojis = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣', '🔟'];
const inlineKeyboard = [[], []]; // Zwei Zeilen für das Inline-Keyboard
let message = 'Letzten 10 hinzugefügten Filme:\n\n';
latestMovies.forEach((movie, index) => {
const numberEmoji = numberEmojis[index] || '';
message += `${numberEmoji} - ${movie.title || 'Unbekannt'}\n\n`;
// Ordne die Schaltflächen in zwei Zeilen an (5 pro Zeile)
const rowIndex = index < 5 ? 0 : 1;
inlineKeyboard[rowIndex].push({ text: numberEmoji, callback_data: `movie_${index}` });
});
// Füge die Anweisung unter den Filmnamen hinzu
message += '\nKlicke auf die Zahl, um nähere Informationen zu bekommen.';
bot.sendMessage(chatId, message, {
reply_markup: {
inline_keyboard: inlineKeyboard
}
}).catch(error => {
logError(`Error sending message to chatId ${chatId}: ${error.message}`);
});
logMessage(`Sent latest 10 movies info to chatId ${chatId}`);
} else {
bot.sendMessage(chatId, 'Keine Filme gefunden.').catch(error => {
logError(`Error sending no movies message to chatId ${chatId}: ${error.message}`);
});
logMessage(`No movies found for chatId ${chatId}`);
}
} catch (error) {
handleError(chatId, error);
}
});
app.use(express.json());
//Anfang für Frontend
// schnittstelle für Kontakt.html
app.get('/api/contact-info', (req, res) => {
res.json({
email: process.env.SMTP_USER,
telegram: process.env.CONTACT_LINK
});
});
// Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Route für Umgebungsvariablen
app.get('/api/env', (req, res) => {
res.json({
botAlias: process.env.BOT_ALIAS,
telegramLink: process.env.TELEGRAM_LINK,
PW_FRONT: process.env.PW_FRONT, //Frontend Passwort Abfrage
});
});
app.use(express.static('public'));
// Middleware
app.use(bodyParser.json());
app.use(express.static('public'));
// Funktion zum Laden der Abonnenten
function loadSubscribers() {
if (fs.existsSync(subscribersFilePath)) {
const data = fs.readFileSync(subscribersFilePath);
subscribers = JSON.parse(data);
}
}
// Abonnieren
app.post('/subscribe', (req, res) => {
const { email, chatId, username } = req.body;
if (!subscribers.find(subscriber => subscriber.chatId === chatId)) {
subscribers.push({ chatId, email, username });
fs.writeFileSync(subscribersFilePath, JSON.stringify(subscribers, null, 2));
sendConfirmationEmail(email); // Bestätigungs-E-Mail senden
res.status(200).send('Erfolgreich angemeldet!');
} else {
res.status(400).send('Bereits angemeldet!');
}
});
// Abmelden
app.post('/unsubscribe', (req, res) => {
const { chatId } = req.body;
subscribers = subscribers.filter(subscriber => subscriber.chatId !== chatId);
fs.writeFileSync(subscribersFilePath, JSON.stringify(subscribers, null, 2));
res.status(200).send('Erfolgreich abgemeldet!');
});
// Lade Abonnenten beim Start
loadSubscribers();
// API-Route für die neuesten Filme
app.get('/api/latest-movies', async (req, res) => {
try {
const response = await axios.get(`${process.env.PLEX_DOMAIN}/library/recentlyAdded?X-Plex-Token=${process.env.PLEX_TOKEN}`);
const movies = response.data.MediaContainer.Metadata.slice(0, 10).map(movie => ({
title: movie.title,
coverImage: `${process.env.PLEX_DOMAIN}${movie.thumb}?X-Plex-Token=${process.env.PLEX_TOKEN}`, // Coverbild-URL mit Token
2024-10-20 20:09:31 +00:00
summary: movie.summary // Hier fügst du die Zusammenfassung hinzu
2024-10-17 22:46:38 +00:00
}));
console.log(movies); // Überprüfung der Daten
res.json(movies);
} catch (error) {
console.error('Fehler beim Abrufen der neuesten Filme:', error);
res.status(500).json({ error: 'Interner Serverfehler' });
}
});
app.get('/api/telegram-link', (req, res) => {
res.json({ link: process.env.TELEGRAM_LINK }); // Stelle den Link aus der .env bereit
});
app.get('/api/bot-version', (req, res) => {
res.json({ version: process.env.BOT_VERSION });
});
2024-10-18 23:49:19 +00:00
// API-Route, die den Wert von WEB_NAME bereitstellt
app.get('/api/web-name', (req, res) => {
res.json({ name: process.env.WEB_NAME });
});
2024-10-17 22:46:38 +00:00
// Inline-Knopf-Ereignis für Film auswählen verarbeiten
bot.on('callback_query', async (callbackQuery) => {
const chatId = callbackQuery.message.chat.id;
const data = callbackQuery.data;
if (data.startsWith('movie_')) {
const movieIndex = parseInt(data.split('_')[1], 10);
try {
const latestMovies = await fetchLatest10Movies();
const selectedMovie = latestMovies[movieIndex];
if (selectedMovie) {
// Bildunterschrift erstellen und kürzen, falls nötig
const movieDetails = createCaption(selectedMovie.title, selectedMovie.summary, selectedMovie.addedAt);
if (selectedMovie.thumb) {
const imageUrl = `${PLEX_DOMAIN}${selectedMovie.thumb}?X-Plex-Token=${PLEX_TOKEN}`;
bot.sendPhoto(chatId, imageUrl, { caption: movieDetails, parse_mode: 'Markdown' }).catch(error => {
logError(`Error sending photo to chatId ${chatId}: ${error.message}`);
});
} else {
bot.sendMessage(chatId, movieDetails, { parse_mode: 'Markdown' }).catch(error => {
logError(`Error sending message to chatId ${chatId}: ${error.message}`);
});
}
logMessage(`Sent movie details for movie index ${movieIndex} to chatId ${chatId}`);
} else {
bot.sendMessage(chatId, 'Film nicht gefunden.').catch(error => {
logError(`Error sending movie not found message to chatId ${chatId}: ${error.message}`);
});
}
} catch (error) {
handleError(chatId, error);
}
}
});
function handleError(chatId, error) {
if (error.response) {
bot.sendMessage(chatId, `Fehler beim Abrufen der Daten. Statuscode: ${error.response.status}`).catch(err => {
logError(`Error sending error message to chatId ${chatId}: ${err.message}`);
});
logError(`Error fetching data: ${error.response.status} - ${error.response.statusText}`);
} else if (error.request) {
bot.sendMessage(chatId, 'Fehler beim Abrufen der Daten. Keine Antwort vom Server.').catch(err => {
logError(`Error sending no response message to chatId ${chatId}: ${err.message}`);
});
logError(`Error fetching data: No response from server`);
} else {
logError(`Error fetching data: ${error.message}`);
}
}
// Route für das Dashboard
app.get('/admin/dashboard', (req, res) => {
if (!req.session.user) { // Überprüfung, ob der Benutzer eingeloggt ist
return res.redirect('/login'); // Weiterleitung zur Login-Seite
}
res.sendFile(__dirname + '/views/admin-dashboard.html'); // Sende die HTML-Datei
});
// API-Endpunkt für Bot-Laufzeit
app.get('/api/bot-uptime', (req, res) => {
const uptime = process.uptime();
const hours = Math.floor(uptime / 3600);
const minutes = Math.floor((uptime % 3600) / 60);
const seconds = Math.floor(uptime % 60);
res.json({ runtime: `${hours}h ${minutes}m ${seconds}s` });
});
// API-Endpunkt für Dateiprüfung
app.get('/api/file-check', (req, res) => {
const requiredFiles = ['user.yml', 'faq.json', 'subscribers.json', 'dev_reports.json', 'w_offen.json', 'feedback.log', 'command_history.json', 'error.log', 'Cache/cache-series.json', 'Cache/cache.json', 'Log/message.log', 'wunsch', 'backups'];
let fileStatus = requiredFiles.map(file => ({
file: file,
exists: fs.existsSync(file)
}));
res.json(fileStatus);
});
// API-Endpunkt für Serverinformationen
app.get('/api/server-info', (req, res) => {
const totalMemory = os.totalmem() / (1024 ** 3); // In GB
const freeMemory = os.freemem() / (1024 ** 3); // In GB
const serverInfo = {
platform: os.platform(),
architecture: os.arch(),
totalMemory: totalMemory.toFixed(2),
freeMemory: freeMemory.toFixed(2)
};
res.json(serverInfo);
});
// Route für das Fehlerprotokoll
app.get('/api/error-log', (req, res) => {
fs.readFile('./error.log', 'utf8', (err, data) => {
if (err) {
return res.status(500).send('Fehler beim Lesen des Fehlerprotokolls');
}
res.send(data);
});
});
// Route für die Kommando-Historie
app.get('/api/command-history', (req, res) => {
fs.readFile('./command_history.json', 'utf8', (err, data) => {
if (err) {
return res.status(500).send('Fehler beim Lesen der Kommando-Historie');
}
res.send(data);
});
});
// Route zum Leeren des Fehlerprotokolls
app.post('/api/clear-error-log', (req, res) => {
fs.writeFile('./error.log', '', (err) => {
if (err) {
return res.status(500).json({ success: false, message: 'Fehler beim Leeren des Fehlerprotokolls' });
}
res.json({ success: true });
});
});
// Route zum Leeren der Kommando-Historie
app.post('/api/clear-command-history', (req, res) => {
fs.writeFile('./command_history.json', '', (err) => {
if (err) {
return res.status(500).json({ success: false, message: 'Fehler beim Leeren der Kommando-Historie' });
}
res.json({ success: true });
});
});
// Route zum Abrufen der FAQs
app.get('/api/faqs', (req, res) => {
const faqs = loadFaqs();
res.json(faqs);
});
// Route zum Hinzufügen einer neuen FAQ
app.post('/api/add-faq', (req, res) => {
const faqs = loadFaqs();
const { question, answer } = req.body;
faqs.push({ question, answer });
saveFaqs(faqs);
res.json({ success: true });
});
// Route zum Löschen einer FAQ
app.delete('/api/delete-faq', (req, res) => {
const faqs = loadFaqs();
const index = req.body.index;
if (index >= 0 && index < faqs.length) {
faqs.splice(index, 1);
saveFaqs(faqs);
res.json({ success: true });
} else {
res.status(400).json({ success: false });
}
});
app.get('/api/wishes', (req, res) => {
fs.readFile('w_offen.json', 'utf8', (err, data) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Lesen der Wünsche' });
}
2024-10-20 20:09:31 +00:00
try {
// Hier kannst du die Logik zum Parsen der Datei manuell implementieren
const wishes = parseWishes(data);
res.json(wishes);
} catch (error) {
return res.status(500).json({ error: 'Fehler beim Verarbeiten der Wünsche' });
}
2024-10-17 22:46:38 +00:00
});
});
2024-10-20 20:09:31 +00:00
// Funktion zum manuellen Parsen der nicht-standardisierten Daten
function parseWishes(data) {
const wishes = [];
const lines = data.split('\n');
let currentWish = {};
for (let line of lines) {
if (line.startsWith('- userId:')) {
if (Object.keys(currentWish).length > 0) {
wishes.push(currentWish); // vorherigen Wunsch speichern
}
currentWish = { userId: parseInt(line.split(': ')[1]) }; // userId speichern
} else if (line.startsWith('message: |-')) {
// Nächste Zeile ist der Beginn der Nachricht
currentWish.message = '';
} else if (currentWish.message !== undefined) {
currentWish.message += line + '\n'; // Nachricht aufbauen
}
}
// Den letzten Wunsch hinzufügen
if (Object.keys(currentWish).length > 0) {
wishes.push(currentWish);
}
return wishes;
}
2024-10-17 22:46:38 +00:00
// Endpoint für das Feedback
app.get('/api/feedback', (req, res) => {
const feedbackFilePath = path.join(__dirname, 'feedback.log');
fs.readFile(feedbackFilePath, 'utf8', (err, data) => {
if (err) {
console.error('Fehler beim Lesen der feedback.log:', err);
return res.status(500).send('Fehler beim Laden des Feedbacks.');
}
res.send(data);
});
});
2024-10-22 16:27:11 +00:00
2024-10-17 22:46:38 +00:00
// 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 {
// Pfad zur user.yml-Datei
const filePath = path.join(__dirname, 'user.yml');
2024-10-22 16:27:11 +00:00
2024-10-17 22:46:38 +00:00
// YAML-Datei laden
const file = fs.readFileSync(filePath, 'utf8');
// YAML in ein JSON-Objekt konvertieren
const data = yaml.parse(file); // 'parse' Funktion verwenden
// Benutzerobjekte in ein Array umwandeln
2024-10-22 16:27:11 +00:00
const usersArray = Object.values(data).map(user => {
// Überprüfen, ob nightModes vorhanden sind und Werte abrufen
const nightMode = user.nightModes && user.nightModes.length > 0 ? user.nightModes[0] : null;
// Wenn kein Nachtmodus vorhanden ist, dann "Deaktiviert" anzeigen
const nightModeDisplay = nightMode
? `${nightMode.startTime} - ${nightMode.endTime}`
: 'Deaktiviert'; // Hier den gewünschten Text verwenden
return {
userId: user.userId,
username: user.username,
notifications: user.notifications,
firstUsed: user.firstUsed,
favoriteGenres: user.favoriteGenres && user.favoriteGenres.length > 0
? user.favoriteGenres.join(', ') // Falls favoriteGenres existiert, kommagetrenntes Format
: (user.favoriteGenre || 'Nicht festgelegt'), // Fallback auf favoriteGenre oder Standardwert
commandCount: user.commandCount || 0, // Standard auf 0, wenn nicht vorhanden
userLevel: user.userLevel || 'Nicht festgelegt', // Standard-Wert
nightMode: nightModeDisplay // Verwendung der neuen Logik für die Nachtmodus-Anzeige
};
});
2024-10-17 22:46:38 +00:00
// JSON-Daten zurückgeben
res.json(usersArray);
} catch (err) {
console.error('Fehler beim Laden der YAML-Datei:', err);
res.status(500).json({ message: 'Fehler beim Laden der Benutzerdaten' });
}
});
let lastRestart = new Date(); // Speichere den aktuellen Zeitpunkt als letzten Neustart
// Funktion zum Formatieren des Datums
const formatLastRestartDate = (date) => {
const options = {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false // 24-Stunden-Format
};
return date.toLocaleString('de-DE', options);
};
// Beispiel: Funktion, die beim Neustart des Bots aufgerufen wird
function onBotRestart() {
lastRestart = new Date(); // Aktualisiere den letzten Neustart
}
// Endpunkt für den letzten Neustart
app.get('/api/last-restart', (req, res) => {
// Hier ist der letzte Neustart korrekt referenziert
res.json({ lastRestart: formatLastRestartDate(lastRestart) });
});
// Beispiel: Rufe die Funktion auf, wenn der Bot neu gestartet wird
onBotRestart();
app.post('/api/send-message', async (req, res) => {
const { message } = req.body;
// Überprüfen, ob die Nachricht leer ist
if (!message) {
return res.status(400).json({ success: false, error: 'Nachricht darf nicht leer sein.' });
}
try {
const users = yaml.load(USER_YML_PATH);
const sendMessages = Object.keys(users).map(userChatId => {
return bot.sendMessage(userChatId, `Systemnachricht\n\n"${message}"`).catch(error => {
logError(`Fehler beim Senden der Systemnachricht an chatId ${userChatId}: ${error.message}`);
});
}).filter(promise => promise !== undefined);
await Promise.all(sendMessages);
res.json({ success: true });
} catch (error) {
console.error('Fehler beim Senden der Nachricht an alle Benutzer:', error);
res.status(500).json({ success: false, error: error.message });
}
});
app.get('/api/media-count', async (req, res) => {
try {
const mediaData = await fetchAllMedia(); // Stelle sicher, dass diese Funktion existiert
const { movieCount, showCount } = mediaData; // Zieht die Anzahl der Filme und Serien
res.json({ movieCount, showCount });
} catch (error) {
console.error('Fehler beim Abrufen der Medienanzahl:', error);
res.status(500).json({ error: 'Fehler beim Abrufen der Medienanzahl.' });
}
});
// Express-Endpunkt zum Empfangen des Wunsches
app.post('/api/telegram-wunsch', (req, res) => {
const { wunsch, type } = req.body;
// Überprüfe, ob req.user vorhanden ist und ob chatId existiert, andernfalls Dummy-ID verwenden
const chatId = req.user && req.user.chatId ? req.user.chatId : '123456789'; // Dummy chatId
sendWish(wunsch, type, chatId)
.then(() => {
res.json({ message: 'Dein Wunsch wurde erfolgreich gesendet!' });
})
.catch(err => {
console.error('Fehler beim Senden des Wunsches:', err);
res.status(500).json({ message: 'Fehler beim Senden deines Wunsches.' });
});
});
app.get('/api/admin-password', (req, res) => {
res.json({ password: process.env.ADMIN_PW });
});
const { exec } = require('child_process');
const path7zip = require('7zip-bin').path7za; // Pfad zu 7zip
const BACKUP_DIR = path.join(__dirname, 'backups');
const ZIP_PASSWORD = process.env.ZIP_PW; // Passwort aus der .env-Datei
// Sicherstellen, dass der Backup-Ordner existiert
if (!fs.existsSync(BACKUP_DIR)) {
fs.mkdirSync(BACKUP_DIR, { recursive: true });
}
// Middleware für statische Dateien
app.use('/backups', express.static(BACKUP_DIR));
// API-Endpunkt für das Erstellen eines Backups
app.post('/api/create-backup', (req, res) => {
const backupFileName = `backup_${Date.now()}.zip`;
const backupFilePath = path.join(BACKUP_DIR, backupFileName);
// Erstelle das Backup als ZIP mit Passwort
const command = `"${path7zip}" a -tzip "${backupFilePath}" * -p${ZIP_PASSWORD} -xr!backups -xr!node_modules`;
exec(command, { cwd: __dirname }, (err, stdout, stderr) => {
if (err) {
console.error('Fehler beim Erstellen des Backups:', err);
return res.status(500).json({ success: false, error: 'Fehler beim Erstellen des Backups' });
}
console.log(`Backup erfolgreich erstellt: ${backupFileName}`);
checkBackupCount(); // Überprüfe die Anzahl der Backups
res.json({ success: true, fileName: backupFileName });
});
});
// API-Endpunkt für das Abrufen der Backups
app.get('/api/backups', (req, res) => {
fs.readdir(BACKUP_DIR, (err, files) => {
if (err) {
console.error('Fehler beim Lesen des Backup-Verzeichnisses:', err);
return res.status(500).json({ success: false, error: 'Fehler beim Abrufen der Backups' });
}
const backups = files.map(file => ({
name: file,
date: fs.statSync(path.join(BACKUP_DIR, file)).mtime,
}));
res.json({ success: true, backups });
});
});
// API-Endpunkt für das Löschen eines Backups
app.post('/api/delete-backup', (req, res) => {
const { backupName } = req.body;
fs.unlink(path.join(BACKUP_DIR, backupName), (err) => {
if (err) {
console.error('Fehler beim Löschen des Backups:', err);
return res.status(500).json({ success: false, error: 'Fehler beim Löschen des Backups' });
}
console.log(`Backup gelöscht: ${backupName}`);
res.json({ success: true });
});
});
// API-Endpunkt zum Herunterladen eines Backups
app.get('/api/download-backup/:backupName', (req, res) => {
const { backupName } = req.params;
const filePath = path.join(BACKUP_DIR, backupName);
// Überprüfen, ob die Datei existiert
if (fs.existsSync(filePath)) {
res.download(filePath, backupName, (err) => {
if (err) {
console.error('Fehler beim Herunterladen des Backups:', err);
res.status(500).json({ success: false, error: 'Fehler beim Herunterladen des Backups' });
}
});
} else {
res.status(404).json({ success: false, error: 'Backup nicht gefunden' });
}
});
// Funktion zur Überprüfung der Anzahl der Backups und ggf. Löschen älterer Backups
function checkBackupCount() {
const maxBackupCount = 5; // Maximale Anzahl an Backups
fs.readdir(BACKUP_DIR, (err, files) => {
if (err) {
return console.error('Fehler beim Überprüfen der Backups:', err);
}
if (files.length > maxBackupCount) {
const sortedFiles = files
.map(file => ({
name: file,
time: fs.statSync(path.join(BACKUP_DIR, file)).mtime.getTime(),
}))
.sort((a, b) => a.time - b.time);
// Lösche die ältesten Backups, um die Anzahl zu reduzieren
const filesToDelete = sortedFiles.slice(0, files.length - maxBackupCount);
filesToDelete.forEach(file => {
fs.unlink(path.join(BACKUP_DIR, file.name), (err) => {
if (err) {
console.error('Fehler beim Löschen alter Backups:', err);
} else {
console.log(`Altes Backup gelöscht: ${file.name}`);
}
});
});
}
});
}
app.post('/api/toggle-debug', (req, res) => {
debugMode = req.body.debugMode;
console.log(`Debug-Modus wurde ${debugMode ? 'aktiviert' : 'deaktiviert'}`);
res.json({ success: true, debugMode });
});
app.get('/api/debug-status', (req, res) => {
res.json({ debugMode });
});
// Beispiel-Endpoint für den Backup-Download
app.post('/api/download-backup', (req, res) => {
const { backupName, password } = req.body;
// Überprüfe das Passwort
if (password !== process.env.ADMIN_PW) {
return res.status(403).json({ success: false, error: 'Falsches Passwort' });
}
// Der Download-Link oder die Logik für den Backup-Download
const backupPath = `path/to/backups/${backupName}`;
if (fs.existsSync(backupPath)) {
res.json({ success: true, downloadUrl: `/backups/${backupName}` });
} else {
res.status(404).json({ success: false, error: 'Backup nicht gefunden' });
}
});
2024-10-18 13:02:39 +00:00
2024-10-17 22:46:38 +00:00
// API-Endpunkt zum Abrufen der Entwicklerberichte
app.get('/api/dev-reports', (req, res) => {
try {
const reports = JSON.parse(fs.readFileSync(DEV_REPORTS_FILE_PATH));
res.json(reports);
} catch (error) {
console.error('Fehler beim Laden der Entwicklerberichte:', error);
res.status(500).json({ message: 'Fehler beim Laden der Entwicklerberichte.' });
}
});
// Route zum Löschen eines Dev Reports
app.delete('/api/dev-reports', (req, res) => {
const reportId = parseInt(req.query.id, 10);
try {
const reports = JSON.parse(fs.readFileSync(DEV_REPORTS_FILE_PATH));
const updatedReports = reports.filter(report => report.id !== reportId); // Lösche den Bericht
fs.writeFileSync(DEV_REPORTS_FILE_PATH, JSON.stringify(updatedReports, null, 2)); // Datei aktualisieren
res.status(204).send(); // 204 No Content
} catch (error) {
console.error('Fehler beim Löschen des Berichts:', error);
res.status(500).send('Interner Serverfehler');
}
});
app.use(bodyParser.json());
// API zum Empfangen der Berichte von der HTML-Seite
app.post('/api/submit-report', (req, res) => {
2024-10-18 13:02:39 +00:00
const { type, user, message } = req.body;
2024-10-17 22:46:38 +00:00
2024-10-18 13:02:39 +00:00
// Falls keine Chat-ID vorhanden ist, generiere eine zufällige ID
const chatId = user.id || Math.floor(Math.random() * 1000000);
2024-10-17 22:46:38 +00:00
2024-10-18 13:02:39 +00:00
const newReport = {
id: Date.now(), // Verwende die aktuelle Zeit als eindeutige ID
type,
user: {
name: user.name || 'Anonym',
id: chatId
},
message,
timestamp: new Date().toISOString()
};
2024-10-17 22:46:38 +00:00
2024-10-18 13:02:39 +00:00
try {
// Berichte aus der Datei laden oder ein leeres Array verwenden
let reports = [];
if (fs.existsSync(DEV_REPORTS_FILE_PATH)) {
reports = JSON.parse(fs.readFileSync(DEV_REPORTS_FILE_PATH, 'utf-8'));
}
2024-10-17 22:46:38 +00:00
2024-10-18 13:02:39 +00:00
// Füge den neuen Bericht hinzu
reports.push(newReport);
2024-10-17 22:46:38 +00:00
2024-10-18 13:02:39 +00:00
// Datei aktualisieren
fs.writeFileSync(DEV_REPORTS_FILE_PATH, JSON.stringify(reports, null, 2));
2024-10-17 22:46:38 +00:00
2024-10-18 13:02:39 +00:00
// Optional: Senden des Berichts an Telegram
sendToTelegram(newReport);
2024-10-17 22:46:38 +00:00
2024-10-18 13:02:39 +00:00
res.status(200).json({ message: 'Bericht erfolgreich übermittelt.' });
} catch (error) {
console.error('Fehler beim Schreiben des Berichts:', error);
res.status(500).json({ message: 'Fehler beim Schreiben des Berichts.' });
}
2024-10-17 22:46:38 +00:00
});
function sendToTelegram(report) {
const messageTemplate = `📩 ${report.type}\n\nvon: ${report.user.name} (${report.user.id})\n\n"${report.message}"`;
// Telegram API URL
const telegramApiUrl = `https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`;
// Sende die Nachricht
axios.post(telegramApiUrl, {
chat_id: DEV_CHAT_ID, // Sende an die in der .env gespeicherte Dev Chat ID
text: messageTemplate,
parse_mode: 'Markdown' // Formatierung der Nachricht
})
.then(response => {
console.log('Nachricht erfolgreich an Telegram gesendet:', response.data);
})
.catch(error => {
console.error('Fehler beim Senden der Nachricht an Telegram:', error);
});
}
2024-10-18 13:02:39 +00:00
2024-10-18 23:49:19 +00:00
// Ende Frontend
2024-10-17 22:46:38 +00:00
/// 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}`);
});
// Log-Rotation
function rotateLogs() {
const today = format(new Date(), 'yyyy-MM-dd');
const logFilePath = path.join(LOG_DIR, `${today}.log`);
// Lösche die Log-Datei von gestern, wenn sie existiert
const yesterday = format(new Date(Date.now() - 24 * 60 * 60 * 1000), 'yyyy-MM-dd');
const oldLogFilePath = path.join(LOG_DIR, `${yesterday}.log`);
if (fs.existsSync(oldLogFilePath)) {
fs.unlinkSync(oldLogFilePath); // Lösche die alte Logdatei
logMessage(`Deleted old log file: ${yesterday}`);
}
}
// Logs täglich um Mitternacht rotieren
function scheduleDailyRotation() {
const now = new Date();
const millisTillMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0, 0) - now;
setTimeout(function() {
rotateLogs(); // Rotieren der Logs um Mitternacht
setInterval(rotateLogs, 24 * 60 * 60 * 1000); // Danach täglich wiederholen
}, millisTillMidnight);
}
// Starte die tägliche Rotation
scheduleDailyRotation();
2024-10-17 21:29:42 +00:00
console.log('Bot is running...');