diff --git a/.env b/.env new file mode 100644 index 0000000..78c4da8 --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +TELEGRAM_BOT_TOKEN=BOT TOKEN +TELEGRAM_CHAT_ID=ADMIN CHAT ID +PLEX_TOKEN=PLEX TOKEN +PLEX_URL=PLEX URL diff --git a/bot.js b/bot.js new file mode 100644 index 0000000..5783288 --- /dev/null +++ b/bot.js @@ -0,0 +1,599 @@ +require("dotenv").config(); +const { Telegraf, Markup } = require("telegraf"); +const axios = require("axios"); +const express = require("express"); +const path = require("path"); +const fs = require("fs"); + + +const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN); +const app = express(); +const PORT = 3000; + +const PLEX_URL = process.env.PLEX_URL; +const PLEX_TOKEN = process.env.PLEX_TOKEN; +const TELEGRAM_CHAT_ID = process.env.TELEGRAM_CHAT_ID; + +const monitoredUsers = new Set(["user1", "666Bong"]); // Hier die Plex-Namen eintragen + +let activeSessions = new Map(); // Speichert aktive Wiedergaben +let userSessions = new Map(); // Speichert aktive Sessions pro Benutzer +let lastNotified = new Map(); // Speichert die Benachrichtigungen pro Benutzer Session +let lastNotifiedDevices = new Map(); // Speichert, ob eine Warnung für zwei Geräte bereits gesendet wurde +let userViolations = new Map(); // Speichert Verstöße für Benutzer +let bannedUsers = new Map(); // Speichert gebannte Benutzer und ihre Ban-Dauer +let whitelist = new Set(); // Set für Whitelisted Benutzer +const whitelistFile = path.join(__dirname, 'whitelist.json'); + + + +let maintenanceMode = false; + +const PASSWORD = process.env.DASHBOARD_PASSWORD; // Passwort aus der .env Datei + +// Statisches Dashboard im 'public' Ordner +app.use(express.static(path.join(__dirname, 'public'))); + +// Startseite mit Passwortabfrage +app.get("/index", (req, res) => { + res.sendFile(path.join(__dirname, 'public', 'index.html')); +}); + +const os = require('os'); + +// API-Endpunkt zum Abrufen der Statistiken +app.get('/stats', (req, res) => { + // Abrufen der Statistiken: aktive Sessions, gebannte Benutzer, Verstöße + const activeSessionsCount = getActiveSessionsCount(); + const bannedUsersCount = getBannedUsersCount(); + const violationsCount = getViolationsCount(); + const recentActivities = getRecentActivities(); + + // CPU- und RAM-Nutzung + const serverCpu = getCpuUsage(); + const serverRam = getRamUsage(); + + // Antwort als JSON + res.json({ + activeSessions: activeSessionsCount, + bannedUsers: bannedUsersCount, + violations: violationsCount, + serverCpu, + serverRam, + recentActivities + }); +}); + +// Funktion zum Abrufen der CPU-Auslastung +function getCpuUsage() { + const cpus = os.cpus(); + let idle = 0; + let total = 0; + + cpus.forEach(cpu => { + for (type in cpu.times) { + total += cpu.times[type]; + } + idle += cpu.times.idle; + }); + + return Math.round(((total - idle) / total) * 100); +} + +// Funktion zum Abrufen der RAM-Auslastung +function getRamUsage() { + const totalMemory = os.totalmem(); + const freeMemory = os.freemem(); + return Math.round(((totalMemory - freeMemory) / totalMemory) * 100); +} + +// Funktion zum Abrufen der Anzahl der aktiven Sessions +function getActiveSessionsCount() { + return activeSessions.size; +} + +// Funktion zum Abrufen der Anzahl gebannter Benutzer +function getBannedUsersCount() { + return bannedUsers.size; +} + +// Funktion zum Abrufen der Anzahl der Verstöße +function getViolationsCount() { + return Array.from(userViolations.values()).reduce((acc, violations) => acc + violations, 0); +} + +let isAutoActive = false; + +function getRecentActivities() { + const autoStatus = autoMode ? 'Automatik Aktiv' : 'Automatik Nicht Aktiv'; + return [ + `${autoStatus}` + ]; +} + + +// Funktion zum Abrufen der aktuellen Wiedergabe +async function checkPlexActivity() { + try { + console.log("🔄 Plex-Wiedergaben werden überprüft..."); + const response = await axios.get(`${PLEX_URL}/status/sessions`, { + headers: { "X-Plex-Token": PLEX_TOKEN }, + }); + + const sessions = response.data.MediaContainer.Metadata || []; + + let newActiveSessions = new Map(); + let newUserSessions = new Map(); + + // Sammle alle Sessions für Benutzer +for (const session of sessions) { + const title = session.title; + const user = session.User?.title; + const ip = session.Player?.publicAddress || session.Player?.address || "Unbekannt"; + const sessionId = session.Session?.id; + if (!sessionId || !user) continue; + + newActiveSessions.set(sessionId, { title, user, ip }); + + if (!newUserSessions.has(user)) { + newUserSessions.set(user, []); + } + newUserSessions.get(user).push({ sessionId, title, ip }); + + // Wenn der Benutzer auf der Whitelist ist, überspringe weitere Prüfungen + if (isUserWhitelisted(user)) { + continue; // Verhindert die Verarbeitung des Benutzers, wenn er auf der Whitelist ist + } + + // Prüfen, ob der Benutzer Accountsharing hat und mehrere Geräte verwendet + if (monitoredUsers.has(user) && newUserSessions.get(user).length > 1) { + console.log(`🚫 Accountsharing erkannt bei ${user}. Wiedergabe wird gestoppt.`); + + const stopMessage = "🚫 Accountsharing verboten. Dein Stream wurde beendet."; + await stopPlaybackWithMessage(user, stopMessage); + + // Verstoß zählen und ggf. sperren + let violations = userViolations.get(user) || 0; + if (violations >= 2) { + bannedUsers.set(user, Date.now()); + userViolations.delete(user); + bot.telegram.sendMessage( + TELEGRAM_CHAT_ID, + `🚫 ${user} wurde aufgrund von wiederholtem Accountsharing für 3 Stunden gesperrt.` + ); + } else { + userViolations.set(user, violations + 1); + bot.telegram.sendMessage( + TELEGRAM_CHAT_ID, + `⚠️ Warnung! Accountsharing erkannt. (${violations + 1}/3 Verstöße)` + ); + } + } + + // Wenn der Benutzer auf mehreren Geräten angemeldet ist, sende eine Warnung + if (newUserSessions.get(user).length > 1 && !lastNotifiedDevices.has(user)) { + const sessionsDetails = newUserSessions.get(user) + .map(s => `📍 **IP-Adresse:** ${s.ip}\n🎞️ **Film:** ${s.title}`) + .join("\n\n"); + + bot.telegram.sendMessage( + TELEGRAM_CHAT_ID, + `🚨 **Achtung! Zwei Geräte mit demselben Benutzer verbunden!**\n\n👤 **Name:** ${user} \n\n${sessionsDetails}`, + Markup.inlineKeyboard([[Markup.button.callback("🚫 Accountsharing verboten", `share_ban_${user}`)]]), + ); + + lastNotifiedDevices.set(user, Date.now()); + } + + if (!lastNotified.has(sessionId)) { + bot.telegram.sendMessage( + TELEGRAM_CHAT_ID, + `🎬 **Neue Wiedergabe erkannt!**\n\n👤 **Name:** ${user} \n📍 **IP-Adresse:** ${ip} \n🎞️ **Film:** ${title}` + ); + + lastNotified.set(sessionId, Date.now()); + } +} + + // Bereinigung der inaktiven Sessions + for (const [sessionId] of activeSessions) { + if (!newActiveSessions.has(sessionId)) { + const session = activeSessions.get(sessionId); + const user = session.user; + + const userSessionsList = userSessions.get(user); + if (userSessionsList) { + const index = userSessionsList.findIndex(s => s.sessionId === sessionId); + if (index !== -1) { + userSessionsList.splice(index, 1); + if (userSessionsList.length === 0) { + userSessions.delete(user); + lastNotifiedDevices.delete(user); + } + } + } + + activeSessions.delete(sessionId); + } + } + + activeSessions = newActiveSessions; + userSessions = newUserSessions; + console.log("✅ Plex-Wiedergaben erfolgreich aktualisiert."); + } catch (error) { + console.error("❌ Fehler beim Abrufen der Plex-Daten:", error.message); + } +} + +// Wiedergabe stoppen für alle Sessions eines Benutzers +async function stopPlaybackWithMessage(userOrSessionId, message) { + try { + const sessions = userSessions.get(userOrSessionId) || []; + + for (const session of sessions) { + await axios.post( + `${PLEX_URL}/status/sessions/terminate?sessionId=${session.sessionId}&reason=${encodeURIComponent(message)}`, + null, + { + headers: { "X-Plex-Token": PLEX_TOKEN }, + } + ); + } + + if (userSessions.has(userOrSessionId)) { + userSessions.delete(userOrSessionId); + } + if (activeSessions.has(userOrSessionId)) { + activeSessions.delete(userOrSessionId); + } + + lastNotifiedDevices.delete(userOrSessionId); + return true; + } catch (error) { + console.error("❌ Fehler beim Stoppen der Wiedergabe:", error.message); + return false; + } +} + +// Aktion für den "Accountsharing verboten"-Button +bot.action(/^share_ban_(\w+)$/, async (ctx) => { + const user = ctx.match[1]; + + if (!user) { + return ctx.reply("❌ Fehler: Benutzer nicht gefunden."); + } + + // Zähle die Verstöße des Benutzers + let violations = userViolations.get(user) || 0; + + if (violations >= 2) { + // Temporären Bann einführen, wenn der Benutzer 3 Verstöße hat + bannedUsers.set(user, Date.now()); + userViolations.delete(user); // Verstöße zurücksetzen + ctx.reply(`🚫 ${user} wurde aufgrund von wiederholtem Accountsharing vorübergehend gesperrt. Der Bann wird in 3 Stunden aufgehoben.`); + } else { + // Ansonsten die Zahl der Verstöße erhöhen + userViolations.set(user, violations + 1); + ctx.reply(`⚠️ Warnung! Accountsharing erkannt. (${violations + 1}/3 Verstöße)`); + } + + const responseText = "🚫 Accountsharing ist nicht erlaubt. Zugriff verweigert."; + const success = await stopPlaybackWithMessage(user, responseText); + + if (success) { + ctx.reply(`✅ Alle Streams von ${user} wurden gestoppt und die Nachricht "Accountsharing verboten" wurde gesendet.`); + } else { + ctx.reply("❌ Fehler beim Stoppen der Wiedergabe."); + } +}); + +// **Neuer Befehl /reload für manuelle Prüfung** +bot.command("reload", async (ctx) => { + ctx.reply("🔄 Wiedergaben werden erneut überprüft..."); + await checkPlexActivity(); + ctx.reply("✅ Überprüfung abgeschlossen."); +}); + +// **Geplante Neustarts und Wartungsmodus** +bot.command('maintenance', async (ctx) => { + if (maintenanceMode) { + return ctx.reply('🚨 Wartungsmodus ist bereits aktiviert.'); + } + + maintenanceMode = true; + ctx.reply('🔧 Wartungsmodus aktiviert. Alle weiteren Aktivitäten werden angehalten.'); +}); + +bot.command('end_maintenance', async (ctx) => { + if (!maintenanceMode) { + return ctx.reply('🚨 Wartungsmodus ist derzeit nicht aktiv.'); + } + + maintenanceMode = false; + ctx.reply('✅ Wartungsmodus beendet. Alle Aktivitäten sind wieder normal.'); +}); + +// **Geräteverwaltung** +bot.command('devices', async (ctx) => { + const activeDeviceList = Array.from(activeSessions.values()) + .map(s => `📱 **Gerät:** ${s.title}, **IP:** ${s.ip}`); + + if (activeDeviceList.length === 0) { + return ctx.reply('❌ Keine Geräte aktuell verbunden.'); + } + + const deviceListMessage = '🔌 **Aktuelle Geräte:**\n' + activeDeviceList.join('\n'); + ctx.reply(deviceListMessage); +}); + +// Unban-Befehl zum Aufheben des Banns +bot.command('unban', async (ctx) => { + const user = ctx.message.text.split(' ')[1]; + + if (!user) { + return ctx.reply('❌ Bitte gib den Namen des Benutzers an, den du entbannen möchtest.'); + } + + // Überprüfen, ob der Benutzer gebannt ist + if (!bannedUsers.has(user)) { + return ctx.reply(`❌ Benutzer ${user} ist derzeit nicht gebannt.`); + } + + // Bann aufheben + bannedUsers.delete(user); + ctx.reply(`✅ Der Bann für ${user} wurde erfolgreich aufgehoben. Der Benutzer kann wieder auf Plex zugreifen.`); +}); + +// Hilfe-Befehl +bot.command('help', async (ctx) => { + const helpMessage = ` + 🤖 **Telegram Plex Bot Hilfe** + +**Verfügbare Befehle:** + +/reload - Führt eine manuelle Prüfung aller aktiven Wiedergaben durch.\n +/stats - Zeigt Statistiken zu aktiven Sessions, gebannten Benutzern, Verstöße und Whitelist-Nutzer.\n +/whitelist - Fügt einen Benutzer zur Whitelist hinzu (verhindert Accountsharing-Überprüfung).\n +/remove_whitelist - Entfernt einen Benutzer von der Whitelist.\n +/unban - Hebt den Bann für einen Benutzer auf.\n +/multiple_devices - Zeigt Benutzer mit mehreren Geräten an.\n +/server_status - Prüft den Status des Plex-Servers.\n +/stats - Zeigt eine Zusammenfassung der aktuellen Plex-Nutzung, einschließlich aktiver Sessions und Verstöße.\n +/help - Zeigt diese Hilfe-Nachricht an.\n + +**Wichtige Hinweise:**\n +- Der Bot überprüft regelmäßig alle aktiven Plex-Wiedergaben.\n +- Wird Accountsharing festgestellt, sendet der Bot eine Warnung an den Administrator.\n +- Bei wiederholtem Accountsharing wird der Benutzer temporär gesperrt.\n +- Nur Benutzer, die nicht auf der Whitelist sind, werden überprüft.\n +- Der Bot sendet tägliche Zusammenfassungen der gesperrten Benutzer und anderer relevanter Informationen.\n + `; + + await ctx.reply(helpMessage); +}); + +bot.command('multiple_devices', async (ctx) => { + const multipleDevicesUsers = Array.from(userSessions.entries()) + .filter(([user, sessions]) => sessions.length > 1) + .map(([user, sessions]) => `${user}: ${sessions.length} Geräte`); + + if (multipleDevicesUsers.length === 0) { + return ctx.reply('❌ Keine Benutzer mit mehreren Geräten gefunden.'); + } + + const message = '📱 Benutzer mit mehreren Geräten:\n' + multipleDevicesUsers.join('\n'); + ctx.reply(message); +}); + + +setInterval(async () => { + const bannedUsersList = Array.from(bannedUsers.keys()).join(', '); + const whitelistedUsersList = Array.from(whitelist).join(', '); + const violationsCount = getViolationsCount(); + const autoModeStatus = isAutoActive ? 'Automatik Aktiv' : 'Automatik Nicht Aktiv'; + + const statsMessage = ` + 📅 **Tägliche Zusammenfassung:** + + - **Aktuell gesperrte Benutzer:** ${bannedUsersList || 'Keine'} + - **Whitelisted Benutzer:** ${whitelistedUsersList || 'Keine'} + - **Verstöße insgesamt:** ${violationsCount} + - **Automatikmodus:** ${autoModeStatus} + `; + bot.telegram.sendMessage(TELEGRAM_CHAT_ID, statsMessage); +}, 86400000); // Täglich (24 Stunden) + +bot.command('server_status', async (ctx) => { + try { + const response = await axios.get(`${PLEX_URL}/status?X-Plex-Token=${PLEX_TOKEN}`); + if (response.status === 200) { + ctx.reply('✅ Plex-Server läuft einwandfrei!'); + } + } catch (error) { + ctx.reply('❌ Fehler beim Abrufen des Plex-Server-Status.'); + } +}); + +// **Stats Befehl** +bot.command('stats', async (ctx) => { + const activeSessionsCount = activeSessions.size; + const bannedUsersCount = bannedUsers.size; + const totalViolations = Array.from(userViolations.values()).reduce((acc, violations) => acc + violations, 0); + const whitelistedUsersCount = whitelist.size; + + ctx.reply(` + 📊 **Statistiken:** + - Aktive Sessions: ${activeSessionsCount} + - Gebannte Benutzer: ${bannedUsersCount} + - Gesamte Verstöße: ${totalViolations} + - Whitelisted Benutzer: ${whitelistedUsersCount} + `); +}); + +// **Whitelist Befehl zum Hinzufügen** +// Funktion zum Laden der Whitelist aus der Datei +function loadWhitelist() { + try { + const data = fs.readFileSync(whitelistFile, 'utf8'); + whitelist = new Set(JSON.parse(data)); + } catch (err) { + console.error('Fehler beim Laden der Whitelist:', err.message); + } +} + +// Funktion zum Speichern der Whitelist in der Datei +function saveWhitelist() { + try { + fs.writeFileSync(whitelistFile, JSON.stringify(Array.from(whitelist), null, 2)); + } catch (err) { + console.error('Fehler beim Speichern der Whitelist:', err.message); + } +} + +// Beim Starten des Bots die Whitelist laden +loadWhitelist(); + +// Funktion zum Überprüfen, ob ein Benutzer auf der Whitelist ist +function isUserWhitelisted(user) { + return whitelist.has(user); +} + +// **Whitelist Befehl zum Hinzufügen** +bot.command('whitelist', async (ctx) => { + const user = ctx.message.text.split(' ')[1]; + + if (!user) { + return ctx.reply('❌ Bitte gib den Namen des Benutzers an, den du auf die Whitelist setzen möchtest.'); + } + + // Überprüfen, ob der Benutzer bereits auf der Whitelist ist + if (whitelist.has(user)) { + return ctx.reply(`❌ Benutzer ${user} ist bereits auf der Whitelist.`); + } + + // Benutzer zur Whitelist hinzufügen + whitelist.add(user); + saveWhitelist(); // Die Änderungen speichern + ctx.reply(`✅ Benutzer ${user} wurde erfolgreich zur Whitelist hinzugefügt.`); +}); + +// **Whitelist Befehl zum Entfernen** +bot.command('remove_whitelist', async (ctx) => { + const user = ctx.message.text.split(' ')[1]; + + if (!user) { + return ctx.reply('❌ Bitte gib den Namen des Benutzers an, den du von der Whitelist entfernen möchtest.'); + } + + // Überprüfen, ob der Benutzer in der Whitelist ist + if (!whitelist.has(user)) { + return ctx.reply(`❌ Benutzer ${user} ist nicht auf der Whitelist.`); + } + + // Benutzer von der Whitelist entfernen + whitelist.delete(user); + saveWhitelist(); // Die Änderungen speichern + ctx.reply(`✅ Benutzer ${user} wurde erfolgreich von der Whitelist entfernt.`); +}); + +// Funktion zum Überprüfen, ob ein Benutzer auf der Whitelist ist +function isUserWhitelisted(user) { + return whitelist.has(user); +} + +bot.command('reset_violations', async (ctx) => { + const user = ctx.message.text.split(' ')[1]; + + if (!user) { + return ctx.reply('❌ Bitte gib den Namen des Benutzers an, dessen Verstöße du zurücksetzen möchtest.'); + } + + // Verstöße zurücksetzen + userViolations.set(user, 0); + ctx.reply(`✅ Die Verstöße für Benutzer ${user} wurden zurückgesetzt.`); +}); + +// Bot starten +bot.launch(); + +// Server für Status-Check +app.get("/", (req, res) => { + res.send("Telegram-Plex-Bot läuft!"); +}); + +let autoMode = false; + +function getRecentActivities() { + const autoStatus = autoMode ? 'Aktiv' : 'Nicht Aktiv'; + + // Hier kannst du deine Logik einbauen, um die letzten Aktivitäten zurückzugeben + return [ + `Automatik Status: ${autoStatus}` + ]; +} + +// /auto-Befehl zum Aktivieren/Deaktivieren des Auto-Modus +bot.command('auto', async (ctx) => { + autoMode = !autoMode; + + if (autoMode) { + ctx.reply('🚀 Der Auto-Modus wurde aktiviert! Alle Accountsharings werden automatisch beendet.'); + } else { + ctx.reply('❌ Der Auto-Modus wurde deaktiviert.'); + } +}); + + +function getRecentActivities() { + const autoStatus = autoMode ? 'Aktiv' : 'Nicht Aktiv'; + return [ + `Automatik Status: ${autoStatus}` + ]; +} + +// Funktion zur automatischen Beendigung von Accountsharing, wenn der Auto-Modus aktiviert ist +async function handleAutoMode() { + if (!autoMode) return; + + for (const [user, sessions] of userSessions.entries()) { + // Überprüfen, ob der Benutzer auf der Whitelist steht + if (whitelist.has(user)) { + console.log(`✅ ${user} ist auf der Whitelist und wird nicht betroffen.`); + continue; // Überspringe den Benutzer, wenn er auf der Whitelist steht + } + + if (sessions.length > 1) { + console.log(`🚫 Automatisches Beenden von Accountsharing für ${user}.`); + + const stopMessage = "🚫 Accountsharing verboten. Dein Stream wurde automatisch beendet."; + await stopPlaybackWithMessage(user, stopMessage); + + // Verstöße zählen und ggf. sperren + let violations = userViolations.get(user) || 0; + if (violations >= 2) { + bannedUsers.set(user, Date.now()); + userViolations.delete(user); + bot.telegram.sendMessage( + TELEGRAM_CHAT_ID, + `🚫 ${user} wurde aufgrund von wiederholtem Accountsharing für 3 Stunden gesperrt.` + ); + } else { + userViolations.set(user, violations + 1); + bot.telegram.sendMessage( + TELEGRAM_CHAT_ID, + `⚠️ Warnung! Accountsharing erkannt. (${violations + 1}/3 Verstöße)` + ); + } + } + } +} + +// Modifizierter setInterval-Aufruf für die Auto-Logik +setInterval(async () => { + await checkPlexActivity(); + await handleAutoMode(); // Überprüft und beendet automatisch Accountsharing im Auto-Modus +}, 30000); // Alle 30 Sekunden + + + +app.listen(PORT, () => console.log(`🚀 Server läuft auf Port ${PORT}`));