Spaces:
Paused
Paused
| const TelegramBot = require('node-telegram-bot-api'); | |
| const { spawn } = require('child_process'); | |
| const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; | |
| const os = require('os'); | |
| // Initialize Telegram bot with polling | |
| const token = '7899900752:AAFUdjznKaXgSkpp7eqFJjXanpb9eQVqw6E'; | |
| if (!token) { | |
| console.error('خطأ: يجب تعيين TELEGRAM_BOT_TOKEN في الكود'); | |
| process.exit(1); | |
| } | |
| const bot = new TelegramBot(token, { polling: true }); | |
| // Admin user ID (replace with your actual user ID) | |
| const ADMIN_USER_ID = '7708913693'; // TODO: Replace with your Telegram user ID | |
| // Store active streams: { id: { process: childProcess, chatId: number, rtmpsUrl: string } } | |
| const activeStreams = new Map(); | |
| // Helper function to log with timestamp | |
| function logToConsole(message) { | |
| const timestamp = new Date().toISOString(); | |
| console.log(`[${timestamp}] ${message}`); | |
| } | |
| // Generate a random 4-digit ID | |
| function generateStreamId() { | |
| return Math.floor(1000 + Math.random() * 9000).toString(); | |
| } | |
| // Check if user is admin | |
| function isAdmin(userId) { | |
| return userId.toString() === ADMIN_USER_ID; | |
| } | |
| // Handle /start command | |
| bot.onText(/\/start/, (msg) => { | |
| const userId = msg.from.id; | |
| const chatId = msg.chat.id; | |
| if (!isAdmin(userId)) { | |
| bot.sendMessage(chatId, 'خطأ: لست مخولًا لاستخدام هذا البوت'); | |
| logToConsole(`Unauthorized user ${userId} sent /start`); | |
| return; | |
| } | |
| const message = 'مرحبًا! أنا بوت بث الفيديو. استخدم الأوامر التالية:\n' + | |
| '/stream <مفتاح_فيسبوك> <رابط_m3u8> - لبدء البث\n' + | |
| '/check - لعرض معلومات النظام\n' + | |
| '/stop <رقم_البث> - لإيقاف البث'; | |
| bot.sendMessage(chatId, message); | |
| logToConsole(`User ${userId} sent /start`); | |
| }); | |
| // Handle /stream <fbkey> <m3u8> | |
| bot.onText(/\/stream (.+) (.+)/, (msg, match) => { | |
| const userId = msg.from.id; | |
| const chatId = msg.chat.id; | |
| if (!isAdmin(userId)) { | |
| bot.sendMessage(chatId, 'خطأ: لست مخولًا لاستخدام هذا البوت'); | |
| logToConsole(`Unauthorized user ${userId} attempted /stream`); | |
| return; | |
| } | |
| const fbKey = match[1].trim(); | |
| const m3u8Url = match[2].trim(); | |
| const rtmpsUrl = `rtmps://live-api-s.facebook.com:443/rtmp/${fbKey}`; | |
| // Validate inputs | |
| if (!m3u8Url.startsWith('http') || !rtmpsUrl.startsWith('rtmps')) { | |
| bot.sendMessage(chatId, 'خطأ: رابط M3U8 أو RTMPS غير صالح'); | |
| logToConsole(`Invalid URLs for user ${userId}: ${m3u8Url}, ${rtmpsUrl}`); | |
| return; | |
| } | |
| // Generate unique stream ID | |
| let streamId; | |
| do { | |
| streamId = generateStreamId(); | |
| } while (activeStreams.has(streamId)); | |
| // Single-line FFmpeg command with reconnect and 5-second delay | |
| const ffmpegCommand = `ffmpeg -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 -itsoffset 5 -re -i "${m3u8Url}" -c:v copy -c:a aac -f flv "${rtmpsUrl}"`; | |
| logToConsole(`Executing FFmpeg for Stream ${streamId}: ${ffmpegCommand}`); | |
| // Start FFmpeg process | |
| const ffmpegProcess = spawn(ffmpegCommand, { shell: true }); | |
| ffmpegProcess.stdout.on('data', (data) => { | |
| logToConsole(`FFmpeg stdout (Stream ${streamId}): ${data}`); | |
| }); | |
| ffmpegProcess.stderr.on('data', (data) => { | |
| logToConsole(`FFmpeg stderr (Stream ${streamId}): ${data}`); | |
| }); | |
| ffmpegProcess.on('spawn', () => { | |
| bot.sendMessage(chatId, `تم بدء البث برقم تعريف: ${streamId}`); | |
| activeStreams.set(streamId, { process: ffmpegProcess, chatId, rtmpsUrl }); | |
| logToConsole(`Stream ${streamId} started for user ${userId}`); | |
| }); | |
| ffmpegProcess.on('error', (err) => { | |
| bot.sendMessage(chatId, `فشل البث ${streamId}: ${err.message}`); | |
| logToConsole(`FFmpeg error (Stream ${streamId}): ${err.message}`); | |
| activeStreams.delete(streamId); | |
| }); | |
| ffmpegProcess.on('close', (code) => { | |
| bot.sendMessage(chatId, `انتهى البث ${streamId} (رمز الخروج: ${code}).`); | |
| logToConsole(`FFmpeg closed (Stream ${streamId}) with code ${code}`); | |
| activeStreams.delete(streamId); | |
| }); | |
| }); | |
| // Handle /check | |
| bot.onText(/\/check/, (msg) => { | |
| const userId = msg.from.id; | |
| const chatId = msg.chat.id; | |
| if (!isAdmin(userId)) { | |
| bot.sendMessage(chatId, 'خطأ: لست مخولًا لاستخدام هذا البوت'); | |
| logToConsole(`Unauthorized user ${userId} attempted /check`); | |
| return; | |
| } | |
| const systemInfo = ` | |
| معلومات النظام: | |
| - استخدام المعالج: ${Math.round(os.loadavg()[0] * 100) / 100}% (متوسط دقيقة واحدة) | |
| - الذاكرة الحرة: ${(os.freemem() / 1024 / 1024 / 1024).toFixed(2)} غيغابايت | |
| - إجمالي الذاكرة: ${(os.totalmem() / 1024 / 1024 / 1024).toFixed(2)} غيغابايت | |
| - البثوث النشطة: ${activeStreams.size} | |
| `; | |
| bot.sendMessage(chatId, systemInfo); | |
| logToConsole(`User ${userId} requested /check`); | |
| }); | |
| // Handle /stop <number> | |
| bot.onText(/\/stop (\d{4})/, (msg, match) => { | |
| const userId = msg.from.id; | |
| const chatId = msg.chat.id; | |
| if (!isAdmin(userId)) { | |
| bot.sendMessage(chatId, 'خطأ: لست مخولًا لاستخدام هذا البوت'); | |
| logToConsole(`Unauthorized user ${userId} attempted /stop ${match[1]}`); | |
| return; | |
| } | |
| const streamId = match[1]; | |
| if (!activeStreams.has(streamId)) { | |
| bot.sendMessage(chatId, `لا يوجد بث برقم تعريف: ${streamId}`); | |
| logToConsole(`User ${userId} tried to stop non-existent stream ${streamId}`); | |
| return; | |
| } | |
| const stream = activeStreams.get(streamId); | |
| logToConsole(`Attempting to stop FFmpeg process for Stream ${streamId} (PID: ${stream.process.pid})`); | |
| // Try SIGTERM first, then SIGKILL after 5 seconds if not terminated | |
| stream.process.kill('SIGTERM'); | |
| const timeout = setTimeout(() => { | |
| if (activeStreams.has(streamId)) { | |
| stream.process.kill('SIGKILL'); | |
| logToConsole(`Force-killed FFmpeg process for Stream ${streamId} (PID: ${stream.process.pid})`); | |
| } | |
| }, 5000); | |
| stream.process.on('close', (code) => { | |
| clearTimeout(timeout); // Cancel SIGKILL if process closes | |
| bot.sendMessage(chatId, `انتهى البث ${streamId} (رمز الخروج: ${code}).`); | |
| logToConsole(`FFmpeg closed (Stream ${streamId}) with code ${code}`); | |
| activeStreams.delete(streamId); | |
| }); | |
| bot.sendMessage(chatId, `تم إيقاف البث ${streamId}.`); | |
| logToConsole(`User ${userId} stopped stream ${streamId}`); | |
| activeStreams.delete(streamId); // Ensure cleanup even if close event is delayed | |
| }); | |
| // Log errors | |
| bot.on('error', (err) => { | |
| logToConsole(`Bot error: ${err.message}`); | |
| }); | |
| // Handle polling errors | |
| bot.on('polling_error', (err) => { | |
| logToConsole(`Polling error: ${err.message}`); | |
| }); | |
| logToConsole('Bot started'); | |
| console.log('البوت يعمل...'); |