diff --git a/plex-bot.js b/plex-bot.js
index d91ba43..94b87d7 100644
--- a/plex-bot.js
+++ b/plex-bot.js
@@ -1,5077 +1,5197 @@
-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');
-
-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));
-}
-
-// 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.');
- }
- });
-});
-
-bot.onText(/\/passwd/, (msg) => {
- const chatId = msg.chat.id;
- const userId = msg.from.id.toString();
-
- if (authorizedUsers.includes(userId)) {
- const password = process.env.ADMIN_PW; // Passwort aus der .env-Datei
- const reply = `🔒 Das Passwort für den Adminbereich lautet:\n\n${password}\n\n‼️Hinweis:‼\n 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\n👤 @${msg.from.username}\n\n🆔 ID: ${userId}\n\n\n📅 Datum: ${new Date().toLocaleDateString('de-DE')}\n\n🕒 Uhrzeit: ${new Date().toLocaleTimeString('de-DE')}`;
-
- 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 // 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
- }
-});
-
-
-
-
-
-
-
-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));
-}
-
-// /night Befehl
-bot.onText(/\/night/, (msg) => {
- const chatId = msg.chat.id;
- const userData = loadUserData(); // Lade die Benutzerdaten
- const userId = chatId.toString();
-
- 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;
- if (!/^\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;
- if (!/^\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 ohne die Benachrichtigungen sofort zu deaktivieren
- userData[userId] = userData[userId] || {};
- userData[userId].nightMode = { startTime, endTime };
- saveUserData(userData); // Speichere die Daten in die yml-Datei
-
- bot.sendMessage(chatId, `🌓 Nachtmodus geplant von ${startTime} bis ${endTime}. Benachrichtigungen werden deaktiviert, wenn der Nachtmodus beginnt.`);
- });
- });
-});
-
-// Funktion zur Überprüfung, ob der Benutzer im Nachtmodus ist
-function isUserInNightMode(chatId) {
- const userData = loadUserData();
- const userId = chatId.toString();
- const userNightMode = userData[userId] && userData[userId].nightMode;
-
- if (!userNightMode) return false;
-
- const now = moment();
- 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
- }
-}
-
-// Überprüft und stellt den Nachtmodus nach Ablauf wieder her
-function resetNotificationsAfterNightMode() {
- const userData = loadUserData();
-
- for (const userId in userData) {
- if (isUserInNightMode(userId)) continue;
-
- // Setze die Benachrichtigungseinstellungen auf den ursprünglichen Wert zurück
- if (userData[userId].originalNotifications !== undefined) {
- userData[userId].notifications = userData[userId].originalNotifications;
- delete userData[userId].originalNotifications; // Lösche die temporäre Speicherung
- saveUserData(userData);
- }
- }
-}
-
-// Funktion zur automatischen Aktivierung des Nachtmodus
-function activateNightMode() {
- const userData = loadUserData();
-
- for (const userId in userData) {
- const userNightMode = userData[userId] && userData[userId].nightMode;
- if (!userNightMode) continue;
-
- const now = moment();
- const start = moment(userNightMode.startTime, 'HH:mm');
- const end = moment(userNightMode.endTime, 'HH:mm');
-
- // Wenn die Startzeit erreicht ist und die Benachrichtigungen noch nicht deaktiviert wurden, deaktiviere sie
- if (now.isSameOrAfter(start) && 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.`);
- console.log(`Nachtmodus für Benutzer ${userId} aktiviert.`);
- }
-
- // Wenn die Endzeit erreicht ist und die Benachrichtigungen deaktiviert wurden, aktiviere sie wieder
- if (now.isSameOrAfter(end) && userData[userId].notifications === false) {
- userData[userId].notifications = userData[userId].originalNotifications;
- delete userData[userId].originalNotifications; // Lösche die temporäre Speicherung
- saveUserData(userData);
- bot.sendMessage(userId, `🌓 Der Nachtmodus endet, die Benachrichtigungen sind jetzt wieder aktiv.`);
- console.log(`Nachtmodus für Benutzer ${userId} deaktiviert.`);
- }
- }
-}
-
-// Automatische Nachtmodus-Aktivierung und Zurücksetzung überwachen
-setInterval(() => {
- activateNightMode(); // Nachtmodus aktivieren, wenn es Zeit ist
- resetNotificationsAfterNightMode(); // Benachrichtigungen nach dem Nachtmodus zurücksetzen
-}, 60 * 1000); // Überprüfung alle 60 Sekunden
-
-// /night_off Befehl
-bot.onText(/\/n_off/, (msg) => {
- const chatId = msg.chat.id;
- const userData = loadUserData(); // Lade die Benutzerdaten
- const userId = chatId.toString();
-
- if (userData[userId] && userData[userId].nightMode) {
- // Setze die Benachrichtigungseinstellungen auf den ursprünglichen Wert zurück
- if (userData[userId].originalNotifications !== undefined) {
- userData[userId].notifications = userData[userId].originalNotifications;
- delete userData[userId].originalNotifications; // Lösche die temporäre Speicherung
- }
-
- // Entferne die Nachtmodus-Daten
- delete userData[userId].nightMode;
-
- // Speichere die Änderungen in der user.yml-Datei
- saveUserData(userData);
-
- bot.sendMessage(chatId, '🌓 Der Nachtmodus wurde deaktiviert. Benachrichtigungen sind wieder aktiviert.');
- } else {
- bot.sendMessage(chatId, 'Es ist kein Nachtmodus aktiv.');
- }
-});
-
-
-
-
-
-
-
-
-
-
-
-
-
-// /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: `
-
-
Willkommen zum Viper-Plex Newsletter!
-
Vielen Dank, dass Sie sich für unseren Newsletter angemeldet haben! 🎊
-
Ab sofort erhalten Sie jeden Sonntag die neuesten Informationen über spannende Filme.
-
-
Zuletzt hinzugefügter Film:
-
${latestMovieTitle}
- ${latestMovieThumb ? `
` : ''}
-
Zusammenfassung: ${latestMovieSummary}
-
Wir freuen uns, Sie als Teil unserer Viper-Plex Familie zu haben!
-
-
- `,
- };
-
- 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 = `
-
-
Neueste Filme auf Viper-Plex
-
- `;
-
- 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 += `
-
-
${movieTitle}
- ${movieThumb ? `
` : ''}
-
Zusammenfassung: ${movieSummary}
-
Hinzugefügt am: ${addedAtDate}
-
- `;
- });
-
- html += `
-
-
- `;
- 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.');
- }
- });
-}
-});
-
-// Lade Abonnenten beim Start
-loadSubscribers();
-
-// Profilbefehl
-bot.onText(/\/profil/, (msg) => {
- const chatId = msg.chat.id;
-
- 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');
-
- // Schritt 1: Benutzerinformationen aus user.yml lesen
- fs.readFile(userFilePath, 'utf8', (err, userData) => {
- if (err) {
- console.error(`Fehler beim Lesen der Datei ${userFilePath}: ${err}`);
- bot.sendMessage(chatId, 'Fehler beim Laden der Benutzerinformationen.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- return;
- }
-
- 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
-
- // Lieblingsgenre aus user.yml ermitteln
- const favoriteGenre = user.favoriteGenre || "Nicht festgelegt"; // Lieblingsgenre aus user.yml oder Standardwert
-
- // 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');
- }
- if (String(chatId) === devId) {
- roles.push('DEV');
- }
- const role = roles.length > 0 ? roles.join(', ') : 'Benutzer';
-
- // Schritt 2: Newsletter-Status aus subscribers.json lesen
- 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;
- }
-
- const subscribers = JSON.parse(subsData);
- const isSubscribed = subscribers.some(subscriber => subscriber.chatId === chatId);
- const newsletterStatus = isSubscribed ? 'Ja' : 'Nein';
-
- // 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) {
- const userWishes = JSON.parse(wishesData);
- wishesCount = userWishes.length;
- }
-
- // Schritt 4: Anzahl der Feedbacks zählen
- fs.stat(feedbackFilePath, (err) => {
- let feedbackCount = 0; // Standardwert für Feedbacks
-
- 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 profileMessage = `
-📝 *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
-`.trim(); // Whitespace entfernen
-
-//🎞️ *Lieblingsgenre:* ${favoriteGenre}\n
-
- // 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 profileMessage = `
-📝 *Profil Informationen:*\n\n
-👤 *Name:* @${userName}\n
-🔑 *ID:* ${userId}\n
-👤 *Nutzerrolle:* ${role}\n
-🌟 *Benutzerlevel:* ${userLevel}\n
-📅 *Registrierung:* ${firstUsedDate}\n
-📰 *Newsletter:* ${newsletterStatus}\n
-📋 *Anzahl der Wünsche:* ${wishesCount}\n
-📬 *Anzahl der Feedbacks:* 0\n
-🔔 *Benachrichtigung:* ${notificationStatus}\n
-`.trim(); // Whitespace entfernen
-
- 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}`));
- }
- });
- });
- });
- });
-});
-
-// 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') {
- // 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: 'Lieblingsgenre setzen', callback_data: 'set_favorite_genre' },
- { text: 'Profil zurücksetzen', callback_data: 'reset_profile' }
- ],
- [
- { text: 'Punkte löschen', callback_data: 'delete_points' },
- { text: 'Profil löschen', callback_data: 'delete_profile' }
- ]
- ]
- }
- });
- } else if (action === 'set_favorite_genre') {
- bot.sendMessage(chatId, 'Bitte geben Sie Ihre Lieblingsgenres ein, getrennt durch Kommas. Verfügbare Genres sind: \n\nAction, Abenteuer, Anime, Dokumentation, Drama, Familie, Fantasy, Horror, Katastrophen, Kinderfilme, Komödie, Krimi, Mystery, Syfy, Thriller, Western.');
-
- // Hier fangen wir die Nachricht des Benutzers ab
- bot.once('message', (msg) => {
- const newFavoriteGenre = msg.text;
-
- // Debugging: Logge das neue Lieblingsgenre
- console.log(`Neues Lieblingsgenre: ${newFavoriteGenre} für Benutzer ${chatId}`);
-
- // Update the favorite genre in user.yml
- 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 Aktualisieren des Lieblingsgenres.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- return;
- }
-
- const users = load(userData);
-
- // Überprüfen, ob der Benutzer bereits existiert
- if (users[chatId]) {
- // Setze das Lieblingsgenre
- users[chatId].favoriteGenre = newFavoriteGenre; // Aktualisiere das Lieblingsgenre
- } else {
- // Benutzer initialisieren, falls nicht vorhanden
- users[chatId] = {
- userId: chatId,
- username: msg.from.username,
- firstUsed: new Date().toISOString(),
- notifications: true, // Standardwert, falls nicht gesetzt
- commandCount: 0, // Standardwert für Befehlsanzahl
- userLevel: 'Neuling', // Standardbenutzerlevel
- favoriteGenre: newFavoriteGenre // Setze das Lieblingsgenre
- };
- }
-
- // 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 Aktualisieren des Lieblingsgenres.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- } else {
- bot.sendMessage(chatId, `✅ Ihr Lieblingsgenre wurde auf "${newFavoriteGenre}" gesetzt.`)
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- }
- });
- });
- });
- } else if (action === 'delete_points') {
- // Punkte auf 0 setzen
- 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 der Punkte.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- return;
- }
-
- const users = load(userData);
-
- // Überprüfen, ob der Benutzer existiert
- if (users[chatId]) {
- users[chatId].commandCount = 0; // Setze die Punkte auf 0
-
- // 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 der Punkte.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- } else {
- bot.sendMessage(chatId, '✅ Ihre Punkte wurden erfolgreich auf 0 gesetzt.')
- .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') {
- // 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;
- }
-
- const users = load(userData);
-
- // Überprüfen, ob der Benutzer existiert
- if (users[chatId]) {
- // Benutzer aus user.yml entfernen
- delete users[chatId];
-
- // 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;
- }
-
- // 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;
- }
-
- const wOffen = load(wOffenData);
- delete wOffen[chatId]; // Entferne den Benutzer aus w_offen.json
-
- // Schreibe die aktualisierten Einträge zurück in die w_offen.json
- fs.writeFile(wOffenFilePath, dump(wOffen), '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;
- }
-
- // 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 && err.code !== 'ENOENT') { // ENOENT bedeutet, die Datei existiert nicht
- 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}`));
- return;
- }
-
- // Lösche den Benutzer aus subscribers.json
- const subscribersFilePath = path.join(__dirname, 'subscribers.json');
- fs.readFile(subscribersFilePath, 'utf8', (err, subscribersData) => {
- if (err) {
- console.error(`Fehler beim Lesen der Datei ${subscribersFilePath}: ${err}`);
- bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- return;
- }
-
- let subscribers;
- try {
- subscribers = JSON.parse(subscribersData);
- } catch (parseErr) {
- console.error(`Fehler beim Parsen der subscribers.json: ${parseErr}`);
- bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- return;
- }
-
- // Entferne den Benutzer aus der Liste
- const updatedSubscribers = subscribers.filter(subscriber => subscriber.chatId !== chatId);
-
- // Schreibe die aktualisierten Abonnenten zurück in die Datei
- fs.writeFile(subscribersFilePath, JSON.stringify(updatedSubscribers, null, 2), 'utf8', (err) => {
- if (err) {
- console.error(`Fehler beim Schreiben in die Datei ${subscribersFilePath}: ${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}`));
- }
- });
-}
-});
-
-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
-function getUserLevel(commandCount, wishCount) {
- let level = 'Neuling';
-
- // Kriterien für die Vergabe des Benutzerlevels
- if (commandCount > 50) {
- level = 'VIP Benutzer';
- } else if (commandCount > 20) {
- level = 'Erfahrener Benutzer';
- } else if (commandCount > 5 || wishCount > 1) {
- level = 'Aktiver Benutzer';
- }
-
- 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(/\/n_off/, (msg) => {
- logCommand('/n_off', msg.from.username);
- // Logik für den Befehl...
-});
-
-bot.onText(/\/passwd/, (msg) => {
- logCommand('/passwd', msg.from.username);
- // Logik für den Befehl...
-});
-
-bot.onText(/\/support/, (msg) => {
- const chatId = msg.chat.id;
-
- // Direkt die Telegram-ID verwenden
- const adminId = 5507179337;
-
- if (msg.from.id !== adminId) {
- return bot.sendMessage(chatId, "🚫 Dieser Befehl ist nur für Administratoren 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 Admins
- 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 = `${process.env.USER1_ID}, ${process.env.USER2_ID}`; // 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
- });
-});
-
-// 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;
- const imageUrl = `https://plex.viper-918.myds.me${thumb}?X-Plex-Token=Pk5PySz_imbA3y24yDei`; // Beispiel-URL anpassen
-
- // 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`);
-}
-// 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' }],
- [{ text: '🐞 Bug melden', callback_data: 'dev_bug' }]
- ]
- }
- };
-}
-
-// 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;
-
- 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:') ||
- msg.reply_to_message.text.includes('Bitte beschreiben Sie den Bug, den Sie melden möchten:'))) {
- 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;
- const messageType = msg.reply_to_message.text.includes('Funktionswunsch') ? 'Funktionswunsch' : 'Bug';
-
- const devMessage = {
- id: null, // ID wird später zugewiesen
- type: messageType,
- user: {
- name: userName,
- id: userId
- },
- message: text,
- timestamp: new Date().toISOString()
- };
-
- // Dev Report in die Datei schreiben
- try {
- console.log('Sende Nachricht an Entwickler-Chat-ID:', DEV_CHAT_ID); // Debugging-Ausgabe
- await bot.sendMessage(DEV_CHAT_ID, formatDevMessage(devMessage), { parse_mode: 'Markdown' });
- console.log('Nachricht erfolgreich gesendet.');
-
- // Dev Report in die JSON-Datei speichern
- saveDevReport(devMessage);
-
- 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();
-
-// 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.`;
-
- // Inline-Button zu einer Webadresse
- const options = {
- reply_markup: {
- inline_keyboard: [
- [
- {
- text: 'zur Web Oberfläche',
- url: 'https://plex.viper.ipv64.net/'
- }
- ]
- ]
- }
- };
-
- 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;
- }
-}
-
-// 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_.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: [
- [{ text: 'Film', callback_data: 'type_film' }],
- [{ text: 'Serie', callback_data: 'type_serie' }]
- ]
- })
- };
-}
-
-// 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: [
- [
- { text: 'Wunsch erfüllt', callback_data: `wish_fulfilled_${chatId}` },
- { text: 'Wunsch nicht erfüllt', callback_data: `wish_not_fulfilled_${chatId}` }
- ]
- ]
- })
- };
-
- try {
- await Promise.all([
- 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.`);
- } 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';
- bot.sendMessage(chatId, `Du hast ${type} ausgewählt. Bitte gib den Titel des ${type} ein.`)
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- 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
-
- bot.sendMessage(userId, '🎉 Dein Wunsch wurde erfüllt!')
- .catch(error => console.error(`Fehler beim Senden der Nachricht: ${error.message}`));
-
- // Wunsch in der Datei 'wishes_.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
- });
-
- fs.writeFile(filePath, JSON.stringify(wishes, null, 2), (err) => {
- if (err) {
- console.error(`Fehler beim Aktualisieren des Wunsches: ${err}`);
- }
- });
- }
- });
- }
-
- if (data.startsWith('wish_not_fulfilled_')) {
- const userId = query.message.chat.id; // Nutze die Chat-ID des Nachrichtenautors
- bot.sendMessage(userId, '😢 Dein Wunsch wurde leider nicht erfüllt.')
- .catch(error => console.error(`Fehler beim Senden der Nachricht: ${error.message}`));
-
- // Wunsch in der Datei 'w_offen.json' speichern
- const filePath = path.join(__dirname, 'w_offen.json');
- const wishDetails = {
- userId,
- message: query.message.text,
- };
-
- fs.readFile(filePath, (err, data) => {
- let openWishes = [];
- if (!err) {
- openWishes = JSON.parse(data); // Vorhandene offene Wünsche lesen
- }
- 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.');
- }
- });
- });
- }
-
- 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;
- const text = msg.text;
-
- if (userStates[chatId] && userStates[chatId].waitingForWish) {
- const wish = text.trim();
- if (wish) {
- const type = userStates[chatId].type;
- await sendWish(wish, type, chatId);
- bot.sendMessage(chatId, `Dein ${type}-Wunsch wurde übermittelt.`)
- .catch(error => console.error(`Fehler bei der Bestätigungsnachricht: ${error.message}`));
- userStates[chatId].waitingForWish = false;
- } else {
- bot.sendMessage(chatId, `Bitte gib den Titel des ${userStates[chatId].type} ein.`)
- .catch(error => console.error(`Fehler bei der Wunsch-Nachricht: ${error.message}`));
- }
- return;
- }
-
- if (text.startsWith('/wunsch')) {
- bot.sendMessage(chatId, 'Möchtest du einen Film oder eine Serie wünschen? Wähle bitte eine Option:', getTypeKeyboard())
- .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 = {};
-
-// Funktion zum Anzeigen aller offenen Wünsche und Inline-Button zum Markieren eines Wunsches als erfüllt
-bot.onText(/\/open_wishes/, (msg) => {
- const chatId = msg.chat.id;
-
- // Pfad zur 'w_offen.json' Datei
- const filePath = path.join(__dirname, 'w_offen.json');
-
- fs.readFile(filePath, (err, data) => {
- if (err || data.length === 0) {
- bot.sendMessage(chatId, 'Es gibt keine offenen Wünsche.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- } else {
- const openWishes = JSON.parse(data);
- if (openWishes.length === 0) {
- bot.sendMessage(chatId, 'Es gibt keine offenen Wünsche.')
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- return;
- }
-
- let message = '📜 Offene Wünsche:\n\n';
- openWishes.forEach((wish, index) => {
- message += `${index + 1}. User ID: ${wish.userId}\n🔹 Titel: ${wish.message}\n\n`;
- });
-
- // Inline-Keyboard mit einem Button, um einen Wunsch als erfüllt zu markieren
- const inlineKeyboard = {
- reply_markup: JSON.stringify({
- inline_keyboard: [
- [{ text: 'Wunsch als erfüllt markieren', callback_data: 'mark_wish_fulfilled' }]
- ]
- })
- };
-
- bot.sendMessage(chatId, message, inlineKeyboard)
- .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
- }
- });
-});
-
-// 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_.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` +
- `❓ /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`;
-}
-
-// 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
- }));
-
- 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 });
-});
-
-// 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 });
- }
-});
-
-// 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' });
- }
- res.json(JSON.parse(data));
- });
-});
-
-// 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);
- });
-});
-
-// 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');
-
- // 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
- const usersArray = Object.values(data).map(user => ({
- userId: user.userId,
- username: user.username,
- notifications: user.notifications,
- firstUsed: user.firstUsed,
- favoriteGenre: user.favoriteGenre,
- commandCount: user.commandCount || 0, // Default auf 0, wenn nicht vorhanden
- userLevel: user.userLevel || 'Nicht festgelegt', // Default-Wert
- nightMode: user.nightMode || {} // Optionales Feld
- }));
-
- // 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' });
- }
-});
-
-// Endpunkt zum Löschen eines Benutzers
-app.delete('/api/users/:userId', (req, res) => {
- const userId = req.params.userId;
-
- try {
- // Pfad zur user.yml-Datei
- const filePath = path.join(__dirname, 'user.yml');
-
- // YAML-Datei laden
- const file = fs.readFileSync(filePath, 'utf8');
- const data = yaml.parse(file); // YAML in ein JSON-Objekt konvertieren
-
- // Überprüfe, ob der Benutzer existiert
- if (!data[userId]) {
- return res.status(404).json({ message: 'Benutzer nicht gefunden' });
- }
-
- // Benutzer aus den Daten entfernen
- delete data[userId];
-
- // Aktualisiere die YAML-Datei mit den neuen Daten
- fs.writeFileSync(filePath, yaml.stringify(data), 'utf8');
-
- res.json({ message: 'Benutzer erfolgreich gelöscht' });
- } catch (err) {
- console.error('Fehler beim Löschen des Benutzers:', err);
- res.status(500).json({ message: 'Fehler beim Löschen des Benutzers' });
- }
-});
-
-
-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' });
- }
-});
-
-// 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) => {
- const { type, user, message } = req.body;
-
- // Falls keine Chat-ID vorhanden ist, generiere eine zufällige ID
- const chatId = user.id || Math.floor(Math.random() * 1000000);
-
- 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()
- };
-
- 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'));
- }
-
- // Füge den neuen Bericht hinzu
- reports.push(newReport);
-
- // Datei aktualisieren
- fs.writeFileSync(DEV_REPORTS_FILE_PATH, JSON.stringify(reports, null, 2));
-
- // Optional: Senden des Berichts an Telegram
- sendToTelegram(newReport);
-
- 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.' });
- }
-});
-
-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);
- });
-}
-
-
-
-
-// Ende Frontend
-
-/// Definition der logDebug-Funktion
-function logDebug(message) {
- console.log(`${new Date().toISOString()} - DEBUG: ${message}`);
-}
-
-// Funktion zum Verarbeiten von Webhook-Anfragen
-app.post('/mywebhook', async (req, res) => {
-try {
- const event = req.body;
- logDebug(`Received webhook event: ${JSON.stringify(event, null, 2)}`);
-
- if (event.type === 'library.new' && event.Metadata) {
- const addedMovie = event.Metadata;
- const movieTitle = addedMovie.title || 'Unbekannt';
- const message = `Ein neuer Film wurde hinzugefügt:\n\nTitel: ${movieTitle}`;
-
- const users = yaml.load(USER_YML_PATH);
- const sendMessages = Object.keys(users).map(chatId =>
- bot.sendMessage(chatId, message).catch(error => {
- logError(`Error sending message to chatId ${chatId}: ${error.message}`);
- })
- );
-
- await Promise.all(sendMessages);
- logMessage(`Sent new movie message to all users`);
- } else {
- logDebug(`Unhandled event type or missing metadata: ${event.type}`);
- }
-
- res.sendStatus(200);
-} catch (error) {
- logError(`Error processing webhook: ${error.message}`);
- res.sendStatus(500);
-}
-});
-
-// 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();
-
+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');
+
+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));
+}
+
+// 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${password}\n\n‼️Hinweis:‼\n 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👤 @${msg.from.username}\n\n🆔 ID: ${userId}\n\n📅 Datum: ${new Date().toLocaleDateString('de-DE')}\n\n🕒 Uhrzeit: ${new Date().toLocaleTimeString('de-DE')}`;
+
+ 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${newPassword}\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';
+ const specialChars = '@#$!';
+
+ 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
+}
+
+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));
+}
+
+// /night Befehl
+bot.onText(/\/night/, (msg) => {
+ const chatId = msg.chat.id;
+ const userData = loadUserData(); // Lade die Benutzerdaten
+ const userId = chatId.toString();
+
+ 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;
+ if (!/^\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;
+ if (!/^\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 ohne die Benachrichtigungen sofort zu deaktivieren
+ userData[userId] = userData[userId] || {};
+ userData[userId].nightMode = { startTime, endTime };
+ saveUserData(userData); // Speichere die Daten in die yml-Datei
+
+ bot.sendMessage(chatId, `🌓 Nachtmodus geplant von ${startTime} bis ${endTime}. Benachrichtigungen werden deaktiviert, wenn der Nachtmodus beginnt.`);
+ });
+ });
+});
+
+// Funktion zur Überprüfung, ob der Benutzer im Nachtmodus ist
+function isUserInNightMode(chatId) {
+ const userData = loadUserData();
+ const userId = chatId.toString();
+ const userNightMode = userData[userId] && userData[userId].nightMode;
+
+ if (!userNightMode) return false;
+
+ const now = moment();
+ 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
+ }
+}
+
+// Überprüft und stellt den Nachtmodus nach Ablauf wieder her
+function resetNotificationsAfterNightMode() {
+ const userData = loadUserData();
+
+ for (const userId in userData) {
+ if (isUserInNightMode(userId)) continue;
+
+ // Setze die Benachrichtigungseinstellungen auf den ursprünglichen Wert zurück
+ if (userData[userId].originalNotifications !== undefined) {
+ userData[userId].notifications = userData[userId].originalNotifications;
+ delete userData[userId].originalNotifications; // Lösche die temporäre Speicherung
+ saveUserData(userData);
+ }
+ }
+}
+
+// Funktion zur automatischen Aktivierung des Nachtmodus
+function activateNightMode() {
+ const userData = loadUserData();
+
+ for (const userId in userData) {
+ const userNightMode = userData[userId] && userData[userId].nightMode;
+ if (!userNightMode) continue;
+
+ const now = moment();
+ const start = moment(userNightMode.startTime, 'HH:mm');
+ const end = moment(userNightMode.endTime, 'HH:mm');
+
+ // Wenn die Startzeit erreicht ist und die Benachrichtigungen noch nicht deaktiviert wurden, deaktiviere sie
+ if (now.isSameOrAfter(start) && 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.`);
+ console.log(`Nachtmodus für Benutzer ${userId} aktiviert.`);
+ }
+
+ // Wenn die Endzeit erreicht ist und die Benachrichtigungen deaktiviert wurden, aktiviere sie wieder
+ if (now.isSameOrAfter(end) && userData[userId].notifications === false) {
+ userData[userId].notifications = userData[userId].originalNotifications;
+ delete userData[userId].originalNotifications; // Lösche die temporäre Speicherung
+ saveUserData(userData);
+ bot.sendMessage(userId, `🌓 Der Nachtmodus endet, die Benachrichtigungen sind jetzt wieder aktiv.`);
+ console.log(`Nachtmodus für Benutzer ${userId} deaktiviert.`);
+ }
+ }
+}
+
+// Automatische Nachtmodus-Aktivierung und Zurücksetzung überwachen
+setInterval(() => {
+ activateNightMode(); // Nachtmodus aktivieren, wenn es Zeit ist
+ resetNotificationsAfterNightMode(); // Benachrichtigungen nach dem Nachtmodus zurücksetzen
+}, 60 * 1000); // Überprüfung alle 60 Sekunden
+
+// /night_off Befehl
+bot.onText(/\/n_off/, (msg) => {
+ const chatId = msg.chat.id;
+ const userData = loadUserData(); // Lade die Benutzerdaten
+ const userId = chatId.toString();
+
+ if (userData[userId] && userData[userId].nightMode) {
+ // Setze die Benachrichtigungseinstellungen auf den ursprünglichen Wert zurück
+ if (userData[userId].originalNotifications !== undefined) {
+ userData[userId].notifications = userData[userId].originalNotifications;
+ delete userData[userId].originalNotifications; // Lösche die temporäre Speicherung
+ }
+
+ // Entferne die Nachtmodus-Daten
+ delete userData[userId].nightMode;
+
+ // Speichere die Änderungen in der user.yml-Datei
+ saveUserData(userData);
+
+ bot.sendMessage(chatId, '🌓 Der Nachtmodus wurde deaktiviert. Benachrichtigungen sind wieder aktiviert.');
+ } else {
+ bot.sendMessage(chatId, 'Es ist kein Nachtmodus aktiv.');
+ }
+});
+
+
+
+
+
+
+
+
+
+
+
+
+
+// /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: `
+
+
Willkommen zum Viper-Plex Newsletter!
+
Vielen Dank, dass Sie sich für unseren Newsletter angemeldet haben! 🎊
+
Ab sofort erhalten Sie jeden Sonntag die neuesten Informationen über spannende Filme.
+
+
Zuletzt hinzugefügter Film:
+
${latestMovieTitle}
+ ${latestMovieThumb ? `
` : ''}
+
Zusammenfassung: ${latestMovieSummary}
+
Wir freuen uns, Sie als Teil unserer Viper-Plex Familie zu haben!
+
+
+ `,
+ };
+
+ 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 = `
+
+
Neueste Filme auf Viper-Plex
+
+ `;
+
+ 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 += `
+
+
${movieTitle}
+ ${movieThumb ? `
` : ''}
+
Zusammenfassung: ${movieSummary}
+
Hinzugefügt am: ${addedAtDate}
+
+ `;
+ });
+
+ html += `
+
+
+ `;
+ 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.');
+ }
+ });
+}
+});
+
+// Lade Abonnenten beim Start
+loadSubscribers();
+
+// Profilbefehl
+bot.onText(/\/profil/, (msg) => {
+ const chatId = msg.chat.id;
+
+ 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');
+
+ // Schritt 1: Benutzerinformationen aus user.yml lesen
+ fs.readFile(userFilePath, 'utf8', (err, userData) => {
+ if (err) {
+ console.error(`Fehler beim Lesen der Datei ${userFilePath}: ${err}`);
+ bot.sendMessage(chatId, 'Fehler beim Laden der Benutzerinformationen.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ return;
+ }
+
+ 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
+
+ // Lieblingsgenre aus user.yml ermitteln
+ const favoriteGenre = user.favoriteGenre || "Nicht festgelegt"; // Lieblingsgenre aus user.yml oder Standardwert
+
+ // 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');
+ }
+ if (String(chatId) === devId) {
+ roles.push('DEV');
+ }
+ const role = roles.length > 0 ? roles.join(', ') : 'Benutzer';
+
+ // Schritt 2: Newsletter-Status aus subscribers.json lesen
+ 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;
+ }
+
+ const subscribers = JSON.parse(subsData);
+ const isSubscribed = subscribers.some(subscriber => subscriber.chatId === chatId);
+ const newsletterStatus = isSubscribed ? 'Ja' : 'Nein';
+
+ // 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) {
+ const userWishes = JSON.parse(wishesData);
+ wishesCount = userWishes.length;
+ }
+
+ // Schritt 4: Anzahl der Feedbacks zählen
+ fs.stat(feedbackFilePath, (err) => {
+ let feedbackCount = 0; // Standardwert für Feedbacks
+
+ 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 profileMessage = `
+📝 *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
+`.trim(); // Whitespace entfernen
+
+//🎞️ *Lieblingsgenre:* ${favoriteGenre}\n
+
+ // 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 profileMessage = `
+📝 *Profil Informationen:*\n\n
+👤 *Name:* @${userName}\n
+🔑 *ID:* ${userId}\n
+👤 *Nutzerrolle:* ${role}\n
+🌟 *Benutzerlevel:* ${userLevel}\n
+📅 *Registrierung:* ${firstUsedDate}\n
+📰 *Newsletter:* ${newsletterStatus}\n
+📋 *Anzahl der Wünsche:* ${wishesCount}\n
+📬 *Anzahl der Feedbacks:* 0\n
+🔔 *Benachrichtigung:* ${notificationStatus}\n
+`.trim(); // Whitespace entfernen
+
+ 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}`));
+ }
+ });
+ });
+ });
+ });
+});
+
+// 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') {
+ // 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: 'Lieblingsgenre setzen', callback_data: 'set_favorite_genre' },
+ { text: 'Profil zurücksetzen', callback_data: 'reset_profile' }
+ ],
+ [
+ { text: 'Punkte löschen', callback_data: 'delete_points' },
+ { text: 'Profil löschen', callback_data: 'delete_profile' }
+ ]
+ ]
+ }
+ });
+ } else if (action === 'set_favorite_genre') {
+ bot.sendMessage(chatId, 'Bitte geben Sie Ihre Lieblingsgenres ein, getrennt durch Kommas. Verfügbare Genres sind: \n\nAction, Abenteuer, Anime, Dokumentation, Drama, Familie, Fantasy, Horror, Katastrophen, Kinderfilme, Komödie, Krimi, Mystery, Syfy, Thriller, Western.');
+
+ // Hier fangen wir die Nachricht des Benutzers ab
+ bot.once('message', (msg) => {
+ const newFavoriteGenre = msg.text;
+
+ // Debugging: Logge das neue Lieblingsgenre
+ console.log(`Neues Lieblingsgenre: ${newFavoriteGenre} für Benutzer ${chatId}`);
+
+ // Update the favorite genre in user.yml
+ 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 Aktualisieren des Lieblingsgenres.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ return;
+ }
+
+ const users = load(userData);
+
+ // Überprüfen, ob der Benutzer bereits existiert
+ if (users[chatId]) {
+ // Setze das Lieblingsgenre
+ users[chatId].favoriteGenre = newFavoriteGenre; // Aktualisiere das Lieblingsgenre
+ } else {
+ // Benutzer initialisieren, falls nicht vorhanden
+ users[chatId] = {
+ userId: chatId,
+ username: msg.from.username,
+ firstUsed: new Date().toISOString(),
+ notifications: true, // Standardwert, falls nicht gesetzt
+ commandCount: 0, // Standardwert für Befehlsanzahl
+ userLevel: 'Neuling', // Standardbenutzerlevel
+ favoriteGenre: newFavoriteGenre // Setze das Lieblingsgenre
+ };
+ }
+
+ // 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 Aktualisieren des Lieblingsgenres.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ } else {
+ bot.sendMessage(chatId, `✅ Ihr Lieblingsgenre wurde auf "${newFavoriteGenre}" gesetzt.`)
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ }
+ });
+ });
+ });
+ } else if (action === 'delete_points') {
+ // Punkte auf 0 setzen
+ 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 der Punkte.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ return;
+ }
+
+ const users = load(userData);
+
+ // Überprüfen, ob der Benutzer existiert
+ if (users[chatId]) {
+ users[chatId].commandCount = 0; // Setze die Punkte auf 0
+
+ // 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 der Punkte.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ } else {
+ bot.sendMessage(chatId, '✅ Ihre Punkte wurden erfolgreich auf 0 gesetzt.')
+ .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') {
+ // 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;
+ }
+
+ const users = load(userData);
+
+ // Überprüfen, ob der Benutzer existiert
+ if (users[chatId]) {
+ // Benutzer aus user.yml entfernen
+ delete users[chatId];
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ const wOffen = load(wOffenData);
+ delete wOffen[chatId]; // Entferne den Benutzer aus w_offen.json
+
+ // Schreibe die aktualisierten Einträge zurück in die w_offen.json
+ fs.writeFile(wOffenFilePath, dump(wOffen), '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;
+ }
+
+ // 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 && err.code !== 'ENOENT') { // ENOENT bedeutet, die Datei existiert nicht
+ 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}`));
+ return;
+ }
+
+ // Lösche den Benutzer aus subscribers.json
+ const subscribersFilePath = path.join(__dirname, 'subscribers.json');
+ fs.readFile(subscribersFilePath, 'utf8', (err, subscribersData) => {
+ if (err) {
+ console.error(`Fehler beim Lesen der Datei ${subscribersFilePath}: ${err}`);
+ bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ return;
+ }
+
+ let subscribers;
+ try {
+ subscribers = JSON.parse(subscribersData);
+ } catch (parseErr) {
+ console.error(`Fehler beim Parsen der subscribers.json: ${parseErr}`);
+ bot.sendMessage(chatId, 'Fehler beim Löschen des Profils.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ return;
+ }
+
+ // Entferne den Benutzer aus der Liste
+ const updatedSubscribers = subscribers.filter(subscriber => subscriber.chatId !== chatId);
+
+ // Schreibe die aktualisierten Abonnenten zurück in die Datei
+ fs.writeFile(subscribersFilePath, JSON.stringify(updatedSubscribers, null, 2), 'utf8', (err) => {
+ if (err) {
+ console.error(`Fehler beim Schreiben in die Datei ${subscribersFilePath}: ${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}`));
+ }
+ });
+}
+});
+
+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
+function getUserLevel(commandCount, wishCount) {
+ let level = 'Neuling';
+
+ // Kriterien für die Vergabe des Benutzerlevels
+ if (commandCount > 50) {
+ level = 'VIP Benutzer';
+ } else if (commandCount > 20) {
+ level = 'Erfahrener Benutzer';
+ } else if (commandCount > 5 || wishCount > 1) {
+ level = 'Aktiver Benutzer';
+ }
+
+ 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(/\/n_off/, (msg) => {
+ logCommand('/n_off', msg.from.username);
+ // Logik für den Befehl...
+});
+
+bot.onText(/\/passwd/, (msg) => {
+ logCommand('/passwd', msg.from.username);
+ // Logik für den Befehl...
+});
+
+bot.onText(/\/support/, (msg) => {
+ const chatId = msg.chat.id;
+
+ // Direkt die Telegram-ID verwenden
+ const adminId = 5507179337;
+
+ if (msg.from.id !== adminId) {
+ return bot.sendMessage(chatId, "🚫 Dieser Befehl ist nur für Administratoren 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 Admins
+ 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 = `${process.env.USER1_ID}, ${process.env.USER2_ID}`; // 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
+ });
+});
+
+// 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;
+ const imageUrl = `https://plex.viper-918.myds.me${thumb}?X-Plex-Token=Pk5PySz_imbA3y24yDei`; // Beispiel-URL anpassen
+
+ // 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`);
+}
+// 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' }],
+ [{ text: '🐞 Bug melden', callback_data: 'dev_bug' }]
+ ]
+ }
+ };
+}
+
+// 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;
+
+ 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:') ||
+ msg.reply_to_message.text.includes('Bitte beschreiben Sie den Bug, den Sie melden möchten:'))) {
+ 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;
+ const messageType = msg.reply_to_message.text.includes('Funktionswunsch') ? 'Funktionswunsch' : 'Bug';
+
+ const devMessage = {
+ id: null, // ID wird später zugewiesen
+ type: messageType,
+ user: {
+ name: userName,
+ id: userId
+ },
+ message: text,
+ timestamp: new Date().toISOString()
+ };
+
+ // Dev Report in die Datei schreiben
+ try {
+ console.log('Sende Nachricht an Entwickler-Chat-ID:', DEV_CHAT_ID); // Debugging-Ausgabe
+ await bot.sendMessage(DEV_CHAT_ID, formatDevMessage(devMessage), { parse_mode: 'Markdown' });
+ console.log('Nachricht erfolgreich gesendet.');
+
+ // Dev Report in die JSON-Datei speichern
+ saveDevReport(devMessage);
+
+ 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();
+
+// 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.`;
+
+ // Inline-Button zu einer Webadresse
+ const options = {
+ reply_markup: {
+ inline_keyboard: [
+ [
+ {
+ text: 'zur Web Oberfläche',
+ url: 'https://plex.viper.ipv64.net/'
+ }
+ ]
+ ]
+ }
+ };
+
+ 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;
+ }
+}
+
+// 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_.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: [
+ [{ text: 'Film', callback_data: 'type_film' }],
+ [{ text: 'Serie', callback_data: 'type_serie' }]
+ ]
+ })
+ };
+}
+
+// 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: [
+ [
+ { text: 'Wunsch erfüllt', callback_data: `wish_fulfilled_${chatId}` },
+ { text: 'Wunsch nicht erfüllt', callback_data: `wish_not_fulfilled_${chatId}` }
+ ]
+ ]
+ })
+ };
+
+ try {
+ await Promise.all([
+ 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.`);
+ } 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';
+ bot.sendMessage(chatId, `Du hast ${type} ausgewählt. Bitte gib den Titel des ${type} ein.`)
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ 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
+
+ bot.sendMessage(userId, '🎉 Dein Wunsch wurde erfüllt!')
+ .catch(error => console.error(`Fehler beim Senden der Nachricht: ${error.message}`));
+
+ // Wunsch in der Datei 'wishes_.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
+ });
+
+ fs.writeFile(filePath, JSON.stringify(wishes, null, 2), (err) => {
+ if (err) {
+ console.error(`Fehler beim Aktualisieren des Wunsches: ${err}`);
+ }
+ });
+ }
+ });
+ }
+
+ if (data.startsWith('wish_not_fulfilled_')) {
+ const userId = query.message.chat.id; // Nutze die Chat-ID des Nachrichtenautors
+ bot.sendMessage(userId, '😢 Dein Wunsch wurde leider nicht erfüllt.')
+ .catch(error => console.error(`Fehler beim Senden der Nachricht: ${error.message}`));
+
+ // Wunsch in der Datei 'w_offen.json' speichern
+ const filePath = path.join(__dirname, 'w_offen.json');
+ const wishDetails = {
+ userId,
+ message: query.message.text,
+ };
+
+ fs.readFile(filePath, (err, data) => {
+ let openWishes = [];
+ if (!err) {
+ openWishes = JSON.parse(data); // Vorhandene offene Wünsche lesen
+ }
+ 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.');
+ }
+ });
+ });
+ }
+
+ 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;
+ const text = msg.text;
+
+ if (userStates[chatId] && userStates[chatId].waitingForWish) {
+ const wish = text.trim();
+ if (wish) {
+ const type = userStates[chatId].type;
+ await sendWish(wish, type, chatId);
+ bot.sendMessage(chatId, `Dein ${type}-Wunsch wurde übermittelt.`)
+ .catch(error => console.error(`Fehler bei der Bestätigungsnachricht: ${error.message}`));
+ userStates[chatId].waitingForWish = false;
+ } else {
+ bot.sendMessage(chatId, `Bitte gib den Titel des ${userStates[chatId].type} ein.`)
+ .catch(error => console.error(`Fehler bei der Wunsch-Nachricht: ${error.message}`));
+ }
+ return;
+ }
+
+ if (text.startsWith('/wunsch')) {
+ bot.sendMessage(chatId, 'Möchtest du einen Film oder eine Serie wünschen? Wähle bitte eine Option:', getTypeKeyboard())
+ .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 = {};
+
+// Funktion zum Anzeigen aller offenen Wünsche und Inline-Button zum Markieren eines Wunsches als erfüllt
+bot.onText(/\/open_wishes/, (msg) => {
+ const chatId = msg.chat.id;
+
+ // Pfad zur 'w_offen.json' Datei
+ const filePath = path.join(__dirname, 'w_offen.json');
+
+ fs.readFile(filePath, (err, data) => {
+ if (err || data.length === 0) {
+ bot.sendMessage(chatId, 'Es gibt keine offenen Wünsche.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ } else {
+ const openWishes = JSON.parse(data);
+ if (openWishes.length === 0) {
+ bot.sendMessage(chatId, 'Es gibt keine offenen Wünsche.')
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ return;
+ }
+
+ let message = '📜 Offene Wünsche:\n\n';
+ openWishes.forEach((wish, index) => {
+ message += `${index + 1}. User ID: ${wish.userId}\n🔹 Titel: ${wish.message}\n\n`;
+ });
+
+ // Inline-Keyboard mit einem Button, um einen Wunsch als erfüllt zu markieren
+ const inlineKeyboard = {
+ reply_markup: JSON.stringify({
+ inline_keyboard: [
+ [{ text: 'Wunsch als erfüllt markieren', callback_data: 'mark_wish_fulfilled' }]
+ ]
+ })
+ };
+
+ bot.sendMessage(chatId, message, inlineKeyboard)
+ .catch(error => console.error(`Fehler bei der Nachricht: ${error.message}`));
+ }
+ });
+});
+
+// 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_.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` +
+ `❓ /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`;
+}
+
+// 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
+ }));
+
+ 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 });
+});
+
+// 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 });
+ }
+});
+
+// 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' });
+ }
+ res.json(JSON.parse(data));
+ });
+});
+
+// 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);
+ });
+});
+
+// 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');
+
+ // 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
+ const usersArray = Object.values(data).map(user => ({
+ userId: user.userId,
+ username: user.username,
+ notifications: user.notifications,
+ firstUsed: user.firstUsed,
+ favoriteGenre: user.favoriteGenre,
+ commandCount: user.commandCount || 0, // Default auf 0, wenn nicht vorhanden
+ userLevel: user.userLevel || 'Nicht festgelegt', // Default-Wert
+ nightMode: user.nightMode || {} // Optionales Feld
+ }));
+
+ // 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' });
+ }
+});
+
+// Endpunkt zum Löschen eines Benutzers
+app.delete('/api/users/:userId', (req, res) => {
+ const userId = req.params.userId;
+
+ try {
+ // Pfad zur user.yml-Datei
+ const filePath = path.join(__dirname, 'user.yml');
+
+ // YAML-Datei laden
+ const file = fs.readFileSync(filePath, 'utf8');
+ const data = yaml.parse(file); // YAML in ein JSON-Objekt konvertieren
+
+ // Überprüfe, ob der Benutzer existiert
+ if (!data[userId]) {
+ return res.status(404).json({ message: 'Benutzer nicht gefunden' });
+ }
+
+ // Benutzer aus den Daten entfernen
+ delete data[userId];
+
+ // Aktualisiere die YAML-Datei mit den neuen Daten
+ fs.writeFileSync(filePath, yaml.stringify(data), 'utf8');
+
+ res.json({ message: 'Benutzer erfolgreich gelöscht' });
+ } catch (err) {
+ console.error('Fehler beim Löschen des Benutzers:', err);
+ res.status(500).json({ message: 'Fehler beim Löschen des Benutzers' });
+ }
+});
+
+
+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' });
+ }
+});
+
+// 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) => {
+ const { type, user, message } = req.body;
+
+ // Falls keine Chat-ID vorhanden ist, generiere eine zufällige ID
+ const chatId = user.id || Math.floor(Math.random() * 1000000);
+
+ 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()
+ };
+
+ 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'));
+ }
+
+ // Füge den neuen Bericht hinzu
+ reports.push(newReport);
+
+ // Datei aktualisieren
+ fs.writeFileSync(DEV_REPORTS_FILE_PATH, JSON.stringify(reports, null, 2));
+
+ // Optional: Senden des Berichts an Telegram
+ sendToTelegram(newReport);
+
+ 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.' });
+ }
+});
+
+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);
+ });
+}
+
+
+
+
+// Ende Frontend
+
+/// Definition der logDebug-Funktion
+function logDebug(message) {
+ console.log(`${new Date().toISOString()} - DEBUG: ${message}`);
+}
+
+// Funktion zum Verarbeiten von Webhook-Anfragen
+app.post('/mywebhook', async (req, res) => {
+try {
+ const event = req.body;
+ logDebug(`Received webhook event: ${JSON.stringify(event, null, 2)}`);
+
+ if (event.type === 'library.new' && event.Metadata) {
+ const addedMovie = event.Metadata;
+ const movieTitle = addedMovie.title || 'Unbekannt';
+ const message = `Ein neuer Film wurde hinzugefügt:\n\nTitel: ${movieTitle}`;
+
+ const users = yaml.load(USER_YML_PATH);
+ const sendMessages = Object.keys(users).map(chatId =>
+ bot.sendMessage(chatId, message).catch(error => {
+ logError(`Error sending message to chatId ${chatId}: ${error.message}`);
+ })
+ );
+
+ await Promise.all(sendMessages);
+ logMessage(`Sent new movie message to all users`);
+ } else {
+ logDebug(`Unhandled event type or missing metadata: ${event.type}`);
+ }
+
+ res.sendStatus(200);
+} catch (error) {
+ logError(`Error processing webhook: ${error.message}`);
+ res.sendStatus(500);
+}
+});
+
+// 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();
+
console.log('Bot is running...');
\ No newline at end of file