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 { format } = require('date-fns'); const express = require('express'); const bodyParser = require('body-parser'); // 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 CHANGE_DIR = path.resolve(PROJECT_ROOT, process.env.CHANGE_DIR); const PORT = process.env.PORT; const MAX_CHANGE_FILE_SIZE = parseInt(process.env.MAX_CHANGE_FILE_SIZE, 10); const USER1_ID = process.env.USER1_ID; const USER2_ID = process.env.USER2_ID; // 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); console.log('CHANGE_DIR:', CHANGE_DIR); // Sicherstellen, dass Verzeichnisse und Dateien existieren if (!fs.existsSync(LOG_DIR)) { fs.mkdirSync(LOG_DIR, { recursive: true }); } if (!fs.existsSync(CHANGE_DIR)) { fs.mkdirSync(CHANGE_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 } // 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 = format(new Date(), 'yyyy-MM-dd'); const logFilePath = path.join(LOG_DIR, `${today}.log`); fs.appendFileSync(logFilePath, `${format(new Date(), 'HH:mm:ss')} - ${message}\n`); } // Funktion zur Fehlerprotokollierung function logError(error) { const errorMessage = `${format(new Date(), 'HH:mm:ss')} - Error: ${error}\n`; fs.appendFileSync(ERROR_LOG_PATH, errorMessage); } // Funktion zum Protokollieren von Debug-Informationen in die change-Datei function logDebug(message) { const now = new Date(); const changeFilePath = path.join(CHANGE_DIR, `change_${format(now, 'yyyy-MM-dd_HH')}.log`); if (fs.existsSync(changeFilePath) && fs.statSync(changeFilePath).size > MAX_CHANGE_FILE_SIZE) { fs.renameSync(changeFilePath, path.join(CHANGE_DIR, `change_${format(now, 'yyyy-MM-dd_HH')}_old.log`)); } fs.appendFileSync(changeFilePath, `${format(now, 'HH:mm:ss')} - Debug: ${message}\n`); } // 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 { // Hole alle Sektionen const sectionsData = await fetchPlexData(PLEX_LIBRARY_URL); const sections = sectionsData.MediaContainer.Directory; let movies = []; // Hole Filme aus jeder Sektion 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')); } } // Sortiere Filme nach 'addedAt' Zeitstempel in absteigender Reihenfolge 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 Suchen von Filmen nach Genre, Titel und Schauspielern async function searchMovies(query) { try { // Alle Filme abrufen const movies = await fetchAllMovies(); // Suchbegriff in Kleinbuchstaben umwandeln const searchQuery = query.toLowerCase(); // Filtere Filme basierend auf dem Suchbegriff const results = movies.filter(movie => { // Sicherstellen, dass wir auf vorhandene Attribute zugreifen const title = (movie.title || '').toLowerCase(); const summary = (movie.summary || '').toLowerCase(); const genres = (movie.genres || []).map(g => g.toLowerCase()); // Genre ist eine Liste const actors = (movie.actors || []).map(a => a.toLowerCase()); // Schauspieler ist eine Liste // Überprüfen, ob der Suchbegriff in einem der Attribute vorkommt return title.includes(searchQuery) || summary.includes(searchQuery) || genres.some(genre => genre.includes(searchQuery)) || actors.some(actor => actor.includes(searchQuery)); }).map(movie => ({ title: movie.title || 'Unbekannt', summary: movie.summary || 'Keine Zusammenfassung verfügbar', thumb: movie.thumb ? `${PLEX_DOMAIN}${movie.thumb}?X-Plex-Token=${PLEX_TOKEN}` : '', genres: (movie.genres || []).join(', '), // Genre-Liste in einen String umwandeln actors: (movie.actors || []).join(', ') // Schauspieler-Liste in einen String umwandeln })); return results; } catch (error) { logError(`Error searching movies: ${error.message}`); throw error; } } // Funktion zum Abrufen eines zufälligen Films async function fetchRandomMovie() { try { const movies = await fetchAllMovies(); 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; } } // /start-Befehl verarbeiten bot.onText(/\/start/, (msg) => { const chatId = msg.chat.id; const userId = msg.from.id; // Benutzerdaten in user.yml speichern let users = yaml.load(USER_YML_PATH); users[chatId] = userId; fs.writeFileSync(USER_YML_PATH, yaml.stringify(users, 4)); const welcomeMessage = ` Willkommen! Dein Zugang zum Bot wurde erfolgreich eingerichtet. Um die verfügbaren Befehle anzuzeigen, tippe /help. `; bot.sendMessage(chatId, welcomeMessage); // /start-Befehl protokollieren logMessage(`Received /start command from chatId ${chatId} (userId ${userId})`); }); // /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}` : ''; const message = `Der zuletzt hinzugefügte Film ist:\n\nTitel: ${movieTitle}\n\nZusammenfassung: \n${movieSummary}\n\nHinzugefügt am: ${addedAtDate}`; // Bild anzeigen, wenn vorhanden if (movieThumb) { bot.sendPhoto(chatId, movieThumb, { caption: message }).catch(error => { logError(`Error sending photo to chatId ${chatId}: ${error.message}`); }); } else { bot.sendMessage(chatId, message).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 { bot.sendMessage(chatId, 'Fehler beim Abrufen der neuesten Filme. Unbekannter Fehler.').catch(err => { logError(`Error sending unknown error message to chatId ${chatId}: ${err.message}`); }); logError(`Error fetching latest movie: ${error.message}`); } } }); // /info-Befehl verarbeiten bot.onText(/\/info/, async (msg) => { const chatId = msg.chat.id; const plexDomain = process.env.PLEX_DOMAIN; // Lese die Plex-Domain aus der Umgebungsvariablen try { const { movieCount, showCount } = await fetchAllMedia(); const message = `In der Bibliothek befinden sich derzeit:\n\nFilme: ${movieCount}\nSerien: ${showCount}\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}`); }); logMessage(`Sent media count, copyright, and Plex button to chatId ${chatId}`); } catch (error) { logError(`Error fetching media count: ${error.message}`); await bot.sendMessage(chatId, 'Fehler beim Abrufen der Medienanzahl.').catch(err => { logError(`Error sending media count error message to chatId ${chatId}: ${err.message}`); }); } }); // Funktion zum Abrufen der Anzahl aller Filme und Serien async function fetchAllMedia() { try { const movies = await fetchAllMovies(); const shows = await fetchAllShows(); // Diese Funktion musst du ebenfalls hinzufügen return { movieCount: movies.length, showCount: shows.length }; } catch (error) { logError(`Error fetching all media: ${error.message}`); throw error; } } // Funktion zum Abrufen aller Serien async function fetchAllShows() { try { // Hole alle Sektionen const sectionsData = await fetchPlexData(PLEX_LIBRARY_URL); const sections = sectionsData.MediaContainer.Directory; let shows = []; // Hole Serien aus jeder Sektion for (const section of sections) { const sectionUrl = `${process.env.PLEX_DOMAIN}/library/sections/${section.key}/all?X-Plex-Token=${process.env.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; } } // Funktion zum Erstellen des Inline-Keyboard 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 async function sendWish(wish, type, chatId) { const message = `❗️ Achtung ❗️\n\nEin neuer ${type} Wunsch ist eingegangen:\n\nType: ${type}\n\nTitel:\n${wish}`; try { await Promise.all([ bot.sendMessage(USER1_ID, message), bot.sendMessage(USER2_ID, message), ]); logMessage(`Sent ${type} wish to users ${USER1_ID} and ${USER2_ID}`); } catch (error) { logError(`Error sending ${type} wish: ${error.message}`); console.error(`Error details: ${error}`); } } // 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 => { logError(`Error sending type confirmation message to chatId ${chatId}: ${error.message}`); }); userStates[chatId] = { type, waitingForWish: true }; // Setze den Status auf "wartend auf Wunsch" } // Markiere die Callback-Abfrage als beantwortet bot.answerCallbackQuery(query.id).catch(error => { logError(`Error answering callback query: ${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) { // Verarbeite den Titel des Wunsches const wish = text.trim(); // Titel erhalten if (wish) { const type = userStates[chatId].type; await sendWish(wish, type, chatId); bot.sendMessage(chatId, `Dein ${type}-Wunsch wurde übermittelt.`).catch(error => { logError(`Error sending wish confirmation to chatId ${chatId}: ${error.message}`); }); logMessage(`Received and forwarded ${type} wish from chatId ${chatId}: ${wish}`); userStates[chatId].waitingForWish = false; // Benutzerstatus zurücksetzen } else { bot.sendMessage(chatId, `Bitte gib den Titel des ${userStates[chatId].type} ein.`).catch(error => { logError(`Error sending empty wish message to chatId ${chatId}: ${error.message}`); }); } return; // Beende die Verarbeitung, wenn der Benutzer in der Eingabestimmung ist } if (text.startsWith('/wunsch')) { // Benutzer zur Auswahl des Typs (Film oder Serie) auffordern bot.sendMessage(chatId, 'Möchtest du einen Film oder eine Serie wünschen? Wähle bitte eine Option:', getTypeKeyboard()).catch(error => { logError(`Error sending type request message to chatId ${chatId}: ${error.message}`); }); userStates[chatId] = { waitingForType: true }; // Setze den Status auf "wartend auf Typ" } if (userStates[chatId] && userStates[chatId].waitingForQuery) { // Verarbeite Suchabfragen, falls der Benutzer darauf wartet const query = text; // Suchbegriff erhalten try { const results = await searchMovies(query); if (results.length === 0) { 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 for (const movie of results) { const { title, summary, thumb } = movie; const message = `Titel: ${title}\n\nZusammenfassung: \n\n${summary}`; if (thumb) { await bot.sendPhoto(chatId, thumb, { caption: message }).catch(error => { logError(`Error sending photo to chatId ${chatId}: ${error.message}`); }); } else { await bot.sendMessage(chatId, message).catch(error => { logError(`Error sending message to chatId ${chatId}: ${error.message}`); }); } } logMessage(`Sent search results for query "${query}" to chatId ${chatId}`); } } catch (error) { if (error.response) { bot.sendMessage(chatId, `Fehler beim Durchführen der Suche. Statuscode: ${error.response.status}`).catch(err => { logError(`Error sending search error message to chatId ${chatId}: ${err.message}`); }); logError(`Error searching movies: ${error.response.status} - ${error.response.statusText}`); } else if (error.request) { bot.sendMessage(chatId, 'Fehler beim Durchführen der Suche. Keine Antwort vom Server.').catch(err => { logError(`Error sending no response message to chatId ${chatId}: ${err.message}`); }); logError(`Error searching movies: No response from server`); } else { bot.sendMessage(chatId, 'Fehler beim Durchführen der Suche. Unbekannter Fehler.').catch(err => { logError(`Error sending unknown error message to chatId ${chatId}: ${error.message}`); }); logError(`Error searching movies: ${error.message}`); } } // Benutzerstatus zurücksetzen userStates[chatId].waitingForQuery = false; } }); // /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}`; // Bild anzeigen, wenn vorhanden if (movieThumb) { bot.sendPhoto(chatId, movieThumb, { caption: message }).catch(error => { logError(`Error sending photo to chatId ${chatId}: ${error.message}`); }); } else { bot.sendMessage(chatId, message).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) { 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 for (const movie of results) { const { title, summary, thumb } = movie; const message = `Titel: ${title}\n\nZusammenfassung: \n\n${summary}`; if (thumb) { await bot.sendPhoto(chatId, thumb, { caption: message }).catch(error => { logError(`Error sending photo to chatId ${chatId}: ${error.message}`); }); } else { await bot.sendMessage(chatId, message).catch(error => { logError(`Error sending message to chatId ${chatId}: ${error.message}`); }); } } logMessage(`Sent search results for query "${query}" to chatId ${chatId}`); } } catch (error) { if (error.response) { bot.sendMessage(chatId, `Fehler beim Durchführen der Suche. Statuscode: ${error.response.status}`).catch(err => { logError(`Error sending search error message to chatId ${chatId}: ${err.message}`); }); logError(`Error searching movies: ${error.response.status} - ${error.response.statusText}`); } else if (error.request) { bot.sendMessage(chatId, 'Fehler beim Durchführen der Suche. Keine Antwort vom Server.').catch(err => { logError(`Error sending no response message to chatId ${chatId}: ${err.message}`); }); logError(`Error searching movies: No response from server`); } else { bot.sendMessage(chatId, 'Fehler beim Durchführen der Suche. Unbekannter Fehler.').catch(err => { logError(`Error sending unknown error message to chatId ${chatId}: ${err.message}`); }); logError(`Error searching movies: ${error.message}`); } } // Benutzerstatus zurücksetzen userStates[chatId].waitingForQuery = false; } }); // Funktion zum Abrufen der gut bewerteten Filme async function fetchTopRatedMovies() { try { const movies = await fetchAllMovies(); if (!movies.length) return []; // Filtere Filme mit Bewertung (hier als Beispiel angenommen, dass die Bewertung in `rating` vorhanden ist) const ratedMovies = movies.filter(movie => movie.rating && movie.rating > 0); // Sortiere Filme nach Bewertung (absteigend) 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 async function fetchDailyRecommendation() { try { const ratedMovies = await fetchTopRatedMovies(); if (ratedMovies.length === 0) return null; // Heute ist der Index der zu zeigende Film const todayIndex = new Date().getDate() % ratedMovies.length; return ratedMovies[todayIndex]; } catch (error) { logError(`Error fetching daily recommendation: ${error.message}`); throw error; } } // /empfehlung-Befehl verarbeiten bot.onText(/\/empfehlung/, async (msg) => { const chatId = msg.chat.id; try { const dailyMovie = await fetchDailyRecommendation(); if (dailyMovie) { const movieTitle = dailyMovie.title || 'Unbekannt'; const movieSummary = dailyMovie.summary || 'Keine Zusammenfassung verfügbar'; const movieThumb = dailyMovie.thumb ? `${PLEX_DOMAIN}${dailyMovie.thumb}?X-Plex-Token=${PLEX_TOKEN}` : ''; const message = `Hier ist der empfohlene Film des Tages:\n\nTitel: ${movieTitle}\n\nZusammenfassung: \n${movieSummary}`; // Bild anzeigen, wenn vorhanden if (movieThumb) { bot.sendPhoto(chatId, movieThumb, { caption: message }).catch(error => { logError(`Error sending photo to chatId ${chatId}: ${error.message}`); }); } else { bot.sendMessage(chatId, message).catch(error => { logError(`Error sending message to chatId ${chatId}: ${error.message}`); }); } logMessage(`Sent daily recommendation to chatId ${chatId}`); } else { 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) { if (error.response) { bot.sendMessage(chatId, `Fehler beim Abrufen der Empfehlung. Statuscode: ${error.response.status}`).catch(err => { logError(`Error sending error message to chatId ${chatId}: ${err.message}`); }); logError(`Error fetching daily recommendation: ${error.response.status} - ${error.response.statusText}`); } else if (error.request) { bot.sendMessage(chatId, 'Fehler beim Abrufen der Empfehlung. Keine Antwort vom Server.').catch(err => { logError(`Error sending no response message to chatId ${chatId}: ${err.message}`); }); logError(`Error fetching daily recommendation: No response from server`); } else { bot.sendMessage(chatId, 'Fehler beim Abrufen der Empfehlung. Unbekannter Fehler.').catch(err => { logError(`Error sending unknown error message to chatId ${chatId}: ${error.message}`); }); logError(`Error fetching daily recommendation: ${error.message}`); } } }); // /help-Befehl verarbeiten bot.onText(/\/help/, (msg) => { const chatId = msg.chat.id; const helpMessage = `📜 **Hier ist eine Liste der verfügbaren Befehle:**\n\n` + `👋 **/start** - Registriert deinen Zugang.\n\n` + `🎬 **/latestmovie** - Zeigt den zuletzt hinzugefügten Film an.\n\n` + `📅 **/latest10movies** - Zeigt die letzten 10 hinzugefügten Filme an.\n\n` + `ℹ️ **/info** - Gibt die Anzahl der Filme und Serien aus.\n\n` + `🎲 **/zufall** - Zeigt einen zufälligen Film an.\n\n` + `🔍 **/search** - Startet die Filmsuche. \n\n` + `💭 **/wunsch** - Nutze diesen Befehl, um einen Filmwunsch zu äußern. \n\n` + `🔝 **/empfehlung** - Film Empfehlung des Tages.\n\n` + `❓ **/help** - Zeigt diese Hilfennachricht an.`; bot.sendMessage(chatId, helpMessage, { parse_mode: 'Markdown' }).catch(error => { logError(`Error sending help message to chatId ${chatId}: ${error.message}`); }); logMessage(`Sent help message to chatId ${chatId}`); }); // 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; } } // /latest10movies-Befehl verarbeiten bot.onText(/\/latest10movies/, async (msg) => { const chatId = msg.chat.id; try { const latestMovies = await fetchLatest10Movies(); if (latestMovies.length > 0) { let message = 'Letzten 10 hinzugefügten Filme:\n\n'; latestMovies.forEach(movie => { message += `${movie.title || 'Unbekannt'}\n`; }); bot.sendMessage(chatId, message).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) { if (error.response) { bot.sendMessage(chatId, `Fehler beim Abrufen der letzten Filme. Statuscode: ${error.response.status}`).catch(err => { logError(`Error sending error message to chatId ${chatId}: ${err.message}`); }); logError(`Error fetching latest 10 movies: ${error.response.status} - ${error.response.statusText}`); } else if (error.request) { bot.sendMessage(chatId, 'Fehler beim Abrufen der letzten Filme. Keine Antwort vom Server.').catch(err => { logError(`Error sending no response message to chatId ${chatId}: ${err.message}`); }); logError(`Error fetching latest 10 movies: No response from server`); } else { bot.sendMessage(chatId, 'Fehler beim Abrufen der letzten Filme. Unbekannter Fehler.').catch(err => { logError(`Error sending unknown error message to chatId ${chatId}: ${err.message}`); }); logError(`Error fetching latest 10 movies: ${error.message}`); } } }); // Funktion zum Verarbeiten von Webhook-Anfragen app.post('/webhook', async (req, res) => { try { const event = req.body; // Ereignisprotokoll für Debugging 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}`; // Nachricht an alle Benutzer senden 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}`); }) ); // Warte, bis alle Nachrichten gesendet wurden 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); // Empfang der Anfrage bestätigen } catch (error) { logError(`Error processing webhook: ${error.message}`); res.sendStatus(500); // Serverfehler } }); // 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...');