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