serversude / bot.js
TheFirstOython's picture
Update bot.js
7e95f4d verified
raw
history blame
7.77 kB
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:AAHpD6GNWncBD9lEdfEuiJExwEVuROIodAI';
const ADMIN_USER_ID = '7708913693';
const WATERMARK_DIR = path.join(__dirname, 'watermarks');
const activeStreams = new Map();
if (!fs.existsSync(WATERMARK_DIR)) fs.mkdirSync(WATERMARK_DIR);
const bot = new TelegramBot(token, { polling: true });
function log(msg) {
console.log(`[${new Date().toISOString()}] ${msg}`);
}
function isAdmin(id) {
return id.toString() === ADMIN_USER_ID;
}
function generateStreamId() {
return Math.floor(1000 + Math.random() * 9000).toString();
}
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
bot.onText(/\/start/, (msg) => {
const id = msg.from.id;
if (!isAdmin(id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح لك.');
bot.sendMessage(msg.chat.id, `
مرحبًا! أوامر البوت:
🟢 /stream <fbkey> <m3u8> [watermark] [cc] - بدء البث
📷 /watermark <url> <name> - تحميل شعار
🔁 /urlchange <id> <new_m3u8> - تغيير المصدر
✍️ /cchange <id> <new_text> - تغيير النص
📴 /stop <id> - إيقاف البث
📟 /check - معلومات النظام`);
});
// /watermark
bot.onText(/\/watermark (.+) (.+)/, async (msg, [_, url, name]) => {
if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
try {
const filePath = await downloadWatermark(url.trim(), name.trim());
bot.sendMessage(msg.chat.id, `✅ تم تحميل الشعار: ${filePath}`);
} catch (e) {
bot.sendMessage(msg.chat.id, `❌ خطأ في التحميل: ${e.message}`);
}
});
// /stream with single success/failure message
bot.onText(/\/stream (.+?) (.+?)(?: (.+?))?(?: (.+))?/, async (msg, match) => {
const [_, fbKey, m3u8Url, watermarkName, ccText = ''] = match;
const chatId = msg.chat.id;
const userId = msg.from.id;
if (!isAdmin(userId)) return bot.sendMessage(chatId, '❌ غير مصرح.');
const rtmpsUrl = `rtmps://live-api-s.facebook.com:443/rtmp/${fbKey.trim()}`;
let watermarkPath = null;
if (watermarkName) {
watermarkPath = path.join(WATERMARK_DIR, `${watermarkName}.png`);
if (!fs.existsSync(watermarkPath)) {
return bot.sendMessage(chatId, `❌ الشعار ${watermarkName}.png غير موجود`);
}
}
if (!m3u8Url.startsWith('http') || !rtmpsUrl.startsWith('rtmps')) {
return bot.sendMessage(chatId, '❌ رابط M3U8 أو مفتاح فيسبوك غير صالح.');
}
let streamId;
do streamId = generateStreamId(); while (activeStreams.has(streamId));
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;
proc.stderr.on('data', (data) => {
const err = data.toString();
log(`FFmpeg stderr (Stream ${streamId}): ${err}`);
if (!hasResponded) {
if (err.includes('Server error') || err.includes('Invalid data')) {
bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: مفتاح RTMPS غير صالح`);
} else if (err.includes('No such file') || err.includes('Invalid argument')) {
bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: رابط M3U8 غير صالح`);
} else {
bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: خطأ غير معروف`);
}
hasResponded = true;
proc.kill('SIGTERM');
activeStreams.delete(streamId);
}
});
proc.on('spawn', () => {
// Wait 3 seconds to catch early errors before confirming success
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 [_, id, newUrl] = match;
const stream = activeStreams.get(id);
if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
if (!stream) return bot.sendMessage(msg.chat.id, `❌ لا يوجد بث ${id}`);
stream.process.kill('SIGTERM');
bot.emit('text', {
...msg,
text: `/stream ${stream.rtmpsUrl.split('/').pop()} ${newUrl} ${stream.watermark || ''} ${stream.cc}`
});
});
// /cchange
bot.onText(/\/cchange (\d{4}) (.+)/, (msg, match) => {
const [_, id, newCC] = match;
const stream = activeStreams.get(id);
if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
if (!stream) return bot.sendMessage(msg.chat.id, `❌ لا يوجد بث ${id}`);
stream.process.kill('SIGTERM');
bot.emit('text', {
...msg,
text: `/stream ${stream.rtmpsUrl.split('/').pop()} ${stream.m3u8Url} ${stream.watermark || ''} ${newCC}`
});
});
// /stop
bot.onText(/\/stop (\d{4})/, (msg, match) => {
const id = match[1];
const stream = activeStreams.get(id);
if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
if (!stream) return bot.sendMessage(msg.chat.id, `❌ لا يوجد بث ${id}`);
stream.process.kill('SIGTERM');
activeStreams.delete(id);
bot.sendMessage(msg.chat.id, `🛑 تم إيقاف البث ${id}`);
});
// /check
bot.onText(/\/check/, (msg) => {
if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
const mem = process.memoryUsage();
const load = os.loadavg();
const uptime = process.uptime();
bot.sendMessage(msg.chat.id, `📟 النظام:
- Uptime: ${(uptime / 60).toFixed(1)} min
- RAM: ${(mem.rss / 1024 / 1024).toFixed(1)} MB
- Load Avg: ${load.map(v => v.toFixed(2)).join(', ')}`);
});
// Bot startup log
console.log(`✅ Bot is running and polling for updates...`);