const TelegramBot = require('node-telegram-bot-api'); const { spawn } = require('child_process'); const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; const os = require('os'); const fs = require('fs'); const path = require('path'); const axios = require('axios'); const token = '8141535657:AAGYH7PFD8vjbd5Ty6IJn2r8yBRpdSVEbQg'; const ADMIN_USER_ID = '7708913693'; const WATERMARK_DIR = path.join(__dirname, 'watermarks'); if (!fs.existsSync(WATERMARK_DIR)) fs.mkdirSync(WATERMARK_DIR); const activeStreams = new Map(); const bot = new TelegramBot(token, { polling: true }); // Logger with timestamp function log(message) { console.log(`[${new Date().toISOString()}] ${message}`); } // Check admin function isAdmin(userId) { return userId.toString() === ADMIN_USER_ID; } // Generate 4-digit stream ID function generateStreamId() { return Math.floor(1000 + Math.random() * 9000).toString(); } // Download watermark image from URL and save async function downloadWatermark(url, name) { const filePath = path.join(WATERMARK_DIR, `${name}.png`); const response = await axios({ url, method: 'GET', responseType: 'stream' }); const writer = fs.createWriteStream(filePath); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', () => resolve(filePath)); writer.on('error', reject); }); } // /start command bot.onText(/\/start/, (msg) => { const userId = msg.from.id; const chatId = msg.chat.id; if (!isAdmin(userId)) { bot.sendMessage(chatId, '❌ غير مصرح لك باستخدام هذا البوت.'); log(`Unauthorized /start from user ${userId}`); return; } const message = ` مرحبًا! هذه أوامر البوت: 🟢 /stream [watermark] [cc] - بدء بث جديد 📷 /watermark - تحميل شعار جديد 🔁 /urlchange - تغيير رابط البث ✍️ /cchange - تغيير نص CC المتحرك 🛑 /stop - إيقاف بث 📟 /check - معلومات النظام `; bot.sendMessage(chatId, message.trim()); log(`Admin ${userId} used /start`); }); // /watermark bot.onText(/\/watermark (.+) (.+)/, async (msg, match) => { const userId = msg.from.id; const chatId = msg.chat.id; if (!isAdmin(userId)) { bot.sendMessage(chatId, '❌ غير مصرح.'); log(`Unauthorized /watermark from user ${userId}`); return; } const url = match[1].trim(); const name = match[2].trim(); try { const filePath = await downloadWatermark(url, name); bot.sendMessage(chatId, `✅ تم تحميل الشعار وحفظه باسم: ${name}.png`); log(`Watermark downloaded by user ${userId}: ${filePath}`); } catch (error) { bot.sendMessage(chatId, `❌ خطأ في تحميل الشعار: ${error.message}`); log(`Watermark download failed for user ${userId}: ${error.message}`); } }); // /stream [watermark] [cc] bot.onText(/\/stream (.+?) (.+?)(?: (.+?))?(?: (.+))?/, async (msg, match) => { const userId = msg.from.id; const chatId = msg.chat.id; if (!isAdmin(userId)) { bot.sendMessage(chatId, '❌ غير مصرح.'); log(`Unauthorized /stream from user ${userId}`); return; } const fbKey = match[1].trim(); const m3u8Url = match[2].trim(); const watermarkName = match[3] ? match[3].trim() : null; const ccText = match[4] ? match[4].trim() : ''; const rtmpsUrl = `rtmps://live-api-s.facebook.com:443/rtmp/${fbKey}`; let watermarkPath = null; if (watermarkName) { watermarkPath = path.join(WATERMARK_DIR, `${watermarkName}.png`); if (!fs.existsSync(watermarkPath)) { bot.sendMessage(chatId, `❌ الشعار ${watermarkName}.png غير موجود.`); log(`Watermark ${watermarkName}.png not found for user ${userId}`); return; } } if (!m3u8Url.startsWith('http') || !rtmpsUrl.startsWith('rtmps')) { bot.sendMessage(chatId, '❌ رابط M3U8 أو مفتاح فيسبوك غير صالح.'); log(`Invalid stream URLs from user ${userId}: ${m3u8Url}, ${rtmpsUrl}`); return; } // Generate unique stream ID let streamId; do streamId = generateStreamId(); while (activeStreams.has(streamId)); // Build FFmpeg command let cmd = `${ffmpegPath} -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 -itsoffset 5 -re -i "${m3u8Url}" `; if (watermarkPath) { cmd += `-i "${watermarkPath}" -filter_complex "[0:v][1:v]overlay=10:10[vt];`; } else { cmd += `-filter_complex "[0:v]copy[vt];`; } cmd += `[vt]drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:text='${ccText}':fontcolor=white:fontsize=24:x=w-tw-10*t:y=h-th-10,`; cmd += `drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:text='Vanilla X':fontcolor=white:fontsize=16:x=10:y=10:box=1:boxcolor=black@0.5:boxborderw=5[outv]" `; cmd += `-map "[outv]" -map 0:a -c:v libx264 -preset veryfast -b:v 3000k -c:a aac -f flv "${rtmpsUrl}"`; const proc = spawn(cmd, { shell: true }); let hasResponded = false; // Error detection & early failure message proc.stderr.on('data', (data) => { const errorText = data.toString(); log(`FFmpeg stderr (Stream ${streamId}): ${errorText}`); if (!hasResponded) { if (errorText.includes('Server error') || errorText.includes('Invalid data')) { bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: مفتاح RTMPS غير صالح.`); } else if (errorText.includes('No such file') || errorText.includes('Invalid argument')) { bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: رابط M3U8 غير صالح.`); } else { bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: خطأ غير معروف.`); } hasResponded = true; proc.kill('SIGTERM'); activeStreams.delete(streamId); } }); // On process spawn, wait 3 sec then confirm success if no errors proc.on('spawn', () => { setTimeout(() => { if (!hasResponded) { bot.sendMessage(chatId, `✅ تم بدء البث: ${streamId}`); hasResponded = true; activeStreams.set(streamId, { process: proc, chatId, rtmpsUrl, m3u8Url, cc: ccText, watermark: watermarkName, }); log(`Stream ${streamId} started for user ${userId}`); } }, 3000); }); proc.on('close', (code) => { log(`FFmpeg closed (Stream ${streamId}) with code ${code}`); if (!hasResponded && code !== 0) { bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: FFmpeg أغلق بالكود ${code}.`); activeStreams.delete(streamId); } else { activeStreams.delete(streamId); } }); proc.on('error', (err) => { if (!hasResponded) { bot.sendMessage(chatId, `❌ خطأ في البث ${streamId}: ${err.message}`); hasResponded = true; } activeStreams.delete(streamId); log(`FFmpeg error (Stream ${streamId}): ${err.message}`); }); }); // /urlchange bot.onText(/\/urlchange (\d{4}) (.+)/, (msg, match) => { const userId = msg.from.id; const chatId = msg.chat.id; if (!isAdmin(userId)) { bot.sendMessage(chatId, '❌ غير مصرح.'); log(`Unauthorized /urlchange from user ${userId}`); return; } const streamId = match[1]; const newM3u8Url = match[2].trim(); if (!activeStreams.has(streamId)) { bot.sendMessage(chatId, `❌ لا يوجد بث برقم ${streamId}.`); return; } if (!newM3u8Url.startsWith('http')) { bot.sendMessage(chatId, '❌ رابط M3U8 جديد غير صالح.'); return; } const stream = activeStreams.get(streamId); stream.process.kill('SIGTERM'); bot.sendMessage(chatId, `⏳ جاري تحديث رابط البث ${streamId}...`); // Re-run stream with new URL but same other parameters bot.emit('text', { ...msg, text: `/stream ${stream.rtmpsUrl.split('/').pop()} ${newM3u8Url} ${stream.watermark || ''} ${stream.cc}`, }); }); // /cchange bot.onText(/\/cchange (\d{4}) (.+)/, (msg, match) => { const userId = msg.from.id; const chatId = msg.chat.id; if (!isAdmin(userId)) { bot.sendMessage(chatId, '❌ غير مصرح.'); log(`Unauthorized /cchange from user ${userId}`); return; } const streamId = match[1]; const newCcText = match[2].trim(); if (!activeStreams.has(streamId)) { bot.sendMessage(chatId, `❌ لا يوجد بث برقم ${streamId}.`); return; } const stream = activeStreams.get(streamId); stream.process.kill('SIGTERM'); bot.sendMessage(chatId, `⏳ جاري تحديث النص المتحرك للبث ${streamId}...`); // Re-run stream with new CC text but same other parameters bot.emit('text', { ...msg, text: `/stream ${stream.rtmpsUrl.split('/').pop()} ${stream.m3u8Url} ${stream.watermark || ''} ${newCcText}`, }); }); // /stop bot.onText(/\/stop (\d{4})/, (msg, match) => { const userId = msg.from.id; const chatId = msg.chat.id; const streamId = match[1]; if (!isAdmin(userId)) { bot.sendMessage(chatId, '❌ غير مصرح.'); log(`Unauthorized /stop from user ${userId}`); return; } if (!activeStreams.has(streamId)) { bot.sendMessage(chatId, `❌ لا يوجد بث برقم ${streamId}.`); return; } const stream = activeStreams.get(streamId); stream.process.kill('SIGTERM'); activeStreams.delete(streamId); bot.sendMessage(chatId, `🛑 تم إيقاف البث ${streamId}.`); log(`Stream ${streamId} stopped by user ${userId}`); }); // /check system info (RAM in GB, uptime, loadavg) bot.onText(/\/check/, (msg) => { const userId = msg.from.id; const chatId = msg.chat.id; if (!isAdmin(userId)) { bot.sendMessage(chatId, '❌ غير مصرح.'); log(`Unauthorized /check from user ${userId}`); return; } const mem = process.memoryUsage(); const totalMem = os.totalmem(); const freeMem = os.freemem(); const load = os.loadavg(); const uptime = process.uptime(); const usedGB = (mem.rss / 1024 / 1024 / 1024).toFixed(2); const freeGB = (freeMem / 1024 / 1024 / 1024).toFixed(2); const totalGB = (totalMem / 1024 / 1024 / 1024).toFixed(2); bot.sendMessage(chatId, ` 📟 معلومات النظام: - وقت التشغيل: ${(uptime / 60).toFixed(1)} دقيقة - ذاكرة البوت المستخدمة: ${usedGB} جيجابايت - الذاكرة الحرة للنظام: ${freeGB} جيجابايت - إجمالي ذاكرة النظام: ${totalGB} جيجابايت - معدل تحميل النظام: ${load.map(v => v.toFixed(2)).join(', ')} `.trim()); log(`System info sent to user ${userId}`); }); console.log(`✅ Bot started and polling...`);