833 lines
32 KiB
JavaScript
833 lines
32 KiB
JavaScript
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...');
|