TheFirstOython commited on
Commit
857e272
·
verified ·
1 Parent(s): b240c3f

Update bot.js

Browse files
Files changed (1) hide show
  1. bot.js +178 -69
bot.js CHANGED
@@ -6,27 +6,32 @@ const fs = require('fs');
6
  const path = require('path');
7
  const axios = require('axios');
8
 
9
- const token = '8141535657:AAHpD6GNWncBD9lEdfEuiJExwEVuROIodAI';
10
  const ADMIN_USER_ID = '7708913693';
11
- const WATERMARK_DIR = path.join(__dirname, 'watermarks');
12
- const activeStreams = new Map();
13
 
 
14
  if (!fs.existsSync(WATERMARK_DIR)) fs.mkdirSync(WATERMARK_DIR);
15
 
 
 
16
  const bot = new TelegramBot(token, { polling: true });
17
 
18
- function log(msg) {
19
- console.log(`[${new Date().toISOString()}] ${msg}`);
 
20
  }
21
 
22
- function isAdmin(id) {
23
- return id.toString() === ADMIN_USER_ID;
 
24
  }
25
 
 
26
  function generateStreamId() {
27
  return Math.floor(1000 + Math.random() * 9000).toString();
28
  }
29
 
 
30
  async function downloadWatermark(url, name) {
31
  const filePath = path.join(WATERMARK_DIR, `${name}.png`);
32
  const response = await axios({ url, method: 'GET', responseType: 'stream' });
@@ -38,80 +43,116 @@ async function downloadWatermark(url, name) {
38
  });
39
  }
40
 
41
- // /start
42
  bot.onText(/\/start/, (msg) => {
43
- const id = msg.from.id;
44
- if (!isAdmin(id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح لك.');
45
- bot.sendMessage(msg.chat.id, `
46
- مرحبًا! أوامر البوت:
47
- 🟢 /stream <fbkey> <m3u8> [watermark] [cc] - بدء البث
48
- 📷 /watermark <url> <name> - تحميل شعار
49
- 🔁 /urlchange <id> <new_m3u8> - تغيير المصدر
50
- ✍️ /cchange <id> <new_text> - تغيير النص
51
- 📴 /stop <id> - إيقاف البث
52
- 📟 /check - معلومات النظام`);
 
 
 
 
 
 
 
 
53
  });
54
 
55
- // /watermark
56
- bot.onText(/\/watermark (.+) (.+)/, async (msg, [_, url, name]) => {
57
- if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
 
 
 
 
 
 
 
 
 
58
  try {
59
- const filePath = await downloadWatermark(url.trim(), name.trim());
60
- bot.sendMessage(msg.chat.id, `✅ تم تحميل الشعار: ${filePath}`);
61
- } catch (e) {
62
- bot.sendMessage(msg.chat.id, `❌ خطأ في التحميل: ${e.message}`);
 
 
63
  }
64
  });
65
 
66
- // /stream with single success/failure message
67
  bot.onText(/\/stream (.+?) (.+?)(?: (.+?))?(?: (.+))?/, async (msg, match) => {
68
- const [_, fbKey, m3u8Url, watermarkName, ccText = ''] = match;
69
- const chatId = msg.chat.id;
70
  const userId = msg.from.id;
 
 
 
 
 
 
71
 
72
- if (!isAdmin(userId)) return bot.sendMessage(chatId, '❌ غير مصرح.');
 
 
 
73
 
74
- const rtmpsUrl = `rtmps://live-api-s.facebook.com:443/rtmp/${fbKey.trim()}`;
75
  let watermarkPath = null;
76
 
77
  if (watermarkName) {
78
  watermarkPath = path.join(WATERMARK_DIR, `${watermarkName}.png`);
79
  if (!fs.existsSync(watermarkPath)) {
80
- return bot.sendMessage(chatId, `❌ الشعار ${watermarkName}.png غير موجود`);
 
 
81
  }
82
  }
83
 
84
  if (!m3u8Url.startsWith('http') || !rtmpsUrl.startsWith('rtmps')) {
85
- return bot.sendMessage(chatId, '❌ رابط M3U8 أو مفتاح فيسبوك غير صالح.');
 
 
86
  }
87
 
 
88
  let streamId;
89
  do streamId = generateStreamId(); while (activeStreams.has(streamId));
90
 
 
91
  let cmd = `${ffmpegPath} -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 -itsoffset 5 -re -i "${m3u8Url}" `;
 
92
  if (watermarkPath) {
93
  cmd += `-i "${watermarkPath}" -filter_complex "[0:v][1:v]overlay=10:10[vt];`;
94
  } else {
95
  cmd += `-filter_complex "[0:v]copy[vt];`;
96
  }
 
97
  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,`;
98
  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]" `;
99
  cmd += `-map "[outv]" -map 0:a -c:v libx264 -preset veryfast -b:v 3000k -c:a aac -f flv "${rtmpsUrl}"`;
100
 
101
  const proc = spawn(cmd, { shell: true });
 
102
  let hasResponded = false;
103
 
 
104
  proc.stderr.on('data', (data) => {
105
- const err = data.toString();
106
- log(`FFmpeg stderr (Stream ${streamId}): ${err}`);
107
 
108
  if (!hasResponded) {
109
- if (err.includes('Server error') || err.includes('Invalid data')) {
110
- bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: مفتاح RTMPS غير صالح`);
111
- } else if (err.includes('No such file') || err.includes('Invalid argument')) {
112
- bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: رابط M3U8 غير صالح`);
113
  } else {
114
- bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: خطأ غير معروف`);
115
  }
116
  hasResponded = true;
117
  proc.kill('SIGTERM');
@@ -119,13 +160,20 @@ bot.onText(/\/stream (.+?) (.+?)(?: (.+?))?(?: (.+))?/, async (msg, match) => {
119
  }
120
  });
121
 
 
122
  proc.on('spawn', () => {
123
- // Wait 3 seconds to catch early errors before confirming success
124
  setTimeout(() => {
125
  if (!hasResponded) {
126
  bot.sendMessage(chatId, `✅ تم بدء البث: ${streamId}`);
127
  hasResponded = true;
128
- activeStreams.set(streamId, { process: proc, chatId, rtmpsUrl, m3u8Url, cc: ccText, watermark: watermarkName });
 
 
 
 
 
 
 
129
  log(`Stream ${streamId} started for user ${userId}`);
130
  }
131
  }, 3000);
@@ -134,7 +182,7 @@ bot.onText(/\/stream (.+?) (.+?)(?: (.+?))?(?: (.+))?/, async (msg, match) => {
134
  proc.on('close', (code) => {
135
  log(`FFmpeg closed (Stream ${streamId}) with code ${code}`);
136
  if (!hasResponded && code !== 0) {
137
- bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: FFmpeg أغلق بالكود ${code}`);
138
  activeStreams.delete(streamId);
139
  } else {
140
  activeStreams.delete(streamId);
@@ -151,57 +199,118 @@ bot.onText(/\/stream (.+?) (.+?)(?: (.+?))?(?: (.+))?/, async (msg, match) => {
151
  });
152
  });
153
 
154
- // /urlchange
155
  bot.onText(/\/urlchange (\d{4}) (.+)/, (msg, match) => {
156
- const [_, id, newUrl] = match;
157
- const stream = activeStreams.get(id);
158
- if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
159
- if (!stream) return bot.sendMessage(msg.chat.id, `❌ لا يوجد بث ${id}`);
 
 
 
 
 
160
 
 
 
 
 
 
 
 
 
 
 
 
161
  stream.process.kill('SIGTERM');
 
 
 
162
  bot.emit('text', {
163
  ...msg,
164
- text: `/stream ${stream.rtmpsUrl.split('/').pop()} ${newUrl} ${stream.watermark || ''} ${stream.cc}`
165
  });
166
  });
167
 
168
- // /cchange
169
  bot.onText(/\/cchange (\d{4}) (.+)/, (msg, match) => {
170
- const [_, id, newCC] = match;
171
- const stream = activeStreams.get(id);
172
- if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
173
- if (!stream) return bot.sendMessage(msg.chat.id, `❌ لا يوجد بث ${id}`);
 
 
 
 
 
174
 
 
 
 
 
 
 
175
  stream.process.kill('SIGTERM');
 
 
 
176
  bot.emit('text', {
177
  ...msg,
178
- text: `/stream ${stream.rtmpsUrl.split('/').pop()} ${stream.m3u8Url} ${stream.watermark || ''} ${newCC}`
179
  });
180
  });
181
 
182
- // /stop
183
  bot.onText(/\/stop (\d{4})/, (msg, match) => {
184
- const id = match[1];
185
- const stream = activeStreams.get(id);
186
- if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
187
- if (!stream) return bot.sendMessage(msg.chat.id, `❌ لا يوجد بث ${id}`);
 
 
 
 
 
 
 
 
188
 
 
189
  stream.process.kill('SIGTERM');
190
- activeStreams.delete(id);
191
- bot.sendMessage(msg.chat.id, `🛑 تم إيقاف البث ${id}`);
 
192
  });
193
 
194
- // /check
195
  bot.onText(/\/check/, (msg) => {
196
- if (!isAdmin(msg.from.id)) return bot.sendMessage(msg.chat.id, '❌ غير مصرح.');
 
 
 
 
 
 
 
197
  const mem = process.memoryUsage();
 
 
198
  const load = os.loadavg();
199
  const uptime = process.uptime();
200
- bot.sendMessage(msg.chat.id, `📟 النظام:
201
- - Uptime: ${(uptime / 60).toFixed(1)} min
202
- - RAM: ${(mem.rss / 1024 / 1024).toFixed(1)} MB
203
- - Load Avg: ${load.map(v => v.toFixed(2)).join(', ')}`);
 
 
 
 
 
 
 
 
 
 
204
  });
205
 
206
- // Bot startup log
207
- console.log(`✅ Bot is running and polling for updates...`);
 
6
  const path = require('path');
7
  const axios = require('axios');
8
 
9
+ const token = '7963845783:AAF7T5PdDKTrzENm4Kno-4PihY1DXdrROMU';
10
  const ADMIN_USER_ID = '7708913693';
 
 
11
 
12
+ const WATERMARK_DIR = path.join(__dirname, 'watermarks');
13
  if (!fs.existsSync(WATERMARK_DIR)) fs.mkdirSync(WATERMARK_DIR);
14
 
15
+ const activeStreams = new Map();
16
+
17
  const bot = new TelegramBot(token, { polling: true });
18
 
19
+ // Logger with timestamp
20
+ function log(message) {
21
+ console.log(`[${new Date().toISOString()}] ${message}`);
22
  }
23
 
24
+ // Check admin
25
+ function isAdmin(userId) {
26
+ return userId.toString() === ADMIN_USER_ID;
27
  }
28
 
29
+ // Generate 4-digit stream ID
30
  function generateStreamId() {
31
  return Math.floor(1000 + Math.random() * 9000).toString();
32
  }
33
 
34
+ // Download watermark image from URL and save
35
  async function downloadWatermark(url, name) {
36
  const filePath = path.join(WATERMARK_DIR, `${name}.png`);
37
  const response = await axios({ url, method: 'GET', responseType: 'stream' });
 
43
  });
44
  }
45
 
46
+ // /start command
47
  bot.onText(/\/start/, (msg) => {
48
+ const userId = msg.from.id;
49
+ const chatId = msg.chat.id;
50
+ if (!isAdmin(userId)) {
51
+ bot.sendMessage(chatId, '❌ غير مصرح لك باستخدام هذا البوت.');
52
+ log(`Unauthorized /start from user ${userId}`);
53
+ return;
54
+ }
55
+ const message = `
56
+ مرحبًا! هذه أوامر البوت:
57
+ 🟢 /stream <fbkey> <m3u8> [watermark] [cc] - بدء بث جديد
58
+ 📷 /watermark <url> <name> - تحميل شعار جديد
59
+ 🔁 /urlchange <id> <new_m3u8> - تغيير رابط البث
60
+ ✍️ /cchange <id> <new_text> - تغيير نص CC المتحرك
61
+ 🛑 /stop <id> - إيقاف بث
62
+ 📟 /check - معلومات النظام
63
+ `;
64
+ bot.sendMessage(chatId, message.trim());
65
+ log(`Admin ${userId} used /start`);
66
  });
67
 
68
+ // /watermark <url> <name>
69
+ bot.onText(/\/watermark (.+) (.+)/, async (msg, match) => {
70
+ const userId = msg.from.id;
71
+ const chatId = msg.chat.id;
72
+ if (!isAdmin(userId)) {
73
+ bot.sendMessage(chatId, '❌ غير مصرح.');
74
+ log(`Unauthorized /watermark from user ${userId}`);
75
+ return;
76
+ }
77
+ const url = match[1].trim();
78
+ const name = match[2].trim();
79
+
80
  try {
81
+ const filePath = await downloadWatermark(url, name);
82
+ bot.sendMessage(chatId, `✅ تم تحميل الشعار وحفظه باسم: ${name}.png`);
83
+ log(`Watermark downloaded by user ${userId}: ${filePath}`);
84
+ } catch (error) {
85
+ bot.sendMessage(chatId, `❌ خطأ في تحميل الشعار: ${error.message}`);
86
+ log(`Watermark download failed for user ${userId}: ${error.message}`);
87
  }
88
  });
89
 
90
+ // /stream <fbkey> <m3u8> [watermark] [cc]
91
  bot.onText(/\/stream (.+?) (.+?)(?: (.+?))?(?: (.+))?/, async (msg, match) => {
 
 
92
  const userId = msg.from.id;
93
+ const chatId = msg.chat.id;
94
+ if (!isAdmin(userId)) {
95
+ bot.sendMessage(chatId, '❌ غير مصرح.');
96
+ log(`Unauthorized /stream from user ${userId}`);
97
+ return;
98
+ }
99
 
100
+ const fbKey = match[1].trim();
101
+ const m3u8Url = match[2].trim();
102
+ const watermarkName = match[3] ? match[3].trim() : null;
103
+ const ccText = match[4] ? match[4].trim() : '';
104
 
105
+ const rtmpsUrl = `rtmps://live-api-s.facebook.com:443/rtmp/${fbKey}`;
106
  let watermarkPath = null;
107
 
108
  if (watermarkName) {
109
  watermarkPath = path.join(WATERMARK_DIR, `${watermarkName}.png`);
110
  if (!fs.existsSync(watermarkPath)) {
111
+ bot.sendMessage(chatId, `❌ الشعار ${watermarkName}.png غير موجود.`);
112
+ log(`Watermark ${watermarkName}.png not found for user ${userId}`);
113
+ return;
114
  }
115
  }
116
 
117
  if (!m3u8Url.startsWith('http') || !rtmpsUrl.startsWith('rtmps')) {
118
+ bot.sendMessage(chatId, '❌ رابط M3U8 أو مفتاح فيسبوك غير صالح.');
119
+ log(`Invalid stream URLs from user ${userId}: ${m3u8Url}, ${rtmpsUrl}`);
120
+ return;
121
  }
122
 
123
+ // Generate unique stream ID
124
  let streamId;
125
  do streamId = generateStreamId(); while (activeStreams.has(streamId));
126
 
127
+ // Build FFmpeg command
128
  let cmd = `${ffmpegPath} -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 -itsoffset 5 -re -i "${m3u8Url}" `;
129
+
130
  if (watermarkPath) {
131
  cmd += `-i "${watermarkPath}" -filter_complex "[0:v][1:v]overlay=10:10[vt];`;
132
  } else {
133
  cmd += `-filter_complex "[0:v]copy[vt];`;
134
  }
135
+
136
  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,`;
137
  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]" `;
138
  cmd += `-map "[outv]" -map 0:a -c:v libx264 -preset veryfast -b:v 3000k -c:a aac -f flv "${rtmpsUrl}"`;
139
 
140
  const proc = spawn(cmd, { shell: true });
141
+
142
  let hasResponded = false;
143
 
144
+ // Error detection & early failure message
145
  proc.stderr.on('data', (data) => {
146
+ const errorText = data.toString();
147
+ log(`FFmpeg stderr (Stream ${streamId}): ${errorText}`);
148
 
149
  if (!hasResponded) {
150
+ if (errorText.includes('Server error') || errorText.includes('Invalid data')) {
151
+ bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: مفتاح RTMPS غير صالح.`);
152
+ } else if (errorText.includes('No such file') || errorText.includes('Invalid argument')) {
153
+ bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: رابط M3U8 غير صالح.`);
154
  } else {
155
+ bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: خطأ غير معروف.`);
156
  }
157
  hasResponded = true;
158
  proc.kill('SIGTERM');
 
160
  }
161
  });
162
 
163
+ // On process spawn, wait 3 sec then confirm success if no errors
164
  proc.on('spawn', () => {
 
165
  setTimeout(() => {
166
  if (!hasResponded) {
167
  bot.sendMessage(chatId, `✅ تم بدء البث: ${streamId}`);
168
  hasResponded = true;
169
+ activeStreams.set(streamId, {
170
+ process: proc,
171
+ chatId,
172
+ rtmpsUrl,
173
+ m3u8Url,
174
+ cc: ccText,
175
+ watermark: watermarkName,
176
+ });
177
  log(`Stream ${streamId} started for user ${userId}`);
178
  }
179
  }, 3000);
 
182
  proc.on('close', (code) => {
183
  log(`FFmpeg closed (Stream ${streamId}) with code ${code}`);
184
  if (!hasResponded && code !== 0) {
185
+ bot.sendMessage(chatId, `❌ فشل بدء البث ${streamId}: FFmpeg أغلق بالكود ${code}.`);
186
  activeStreams.delete(streamId);
187
  } else {
188
  activeStreams.delete(streamId);
 
199
  });
200
  });
201
 
202
+ // /urlchange <streamId> <new_m3u8>
203
  bot.onText(/\/urlchange (\d{4}) (.+)/, (msg, match) => {
204
+ const userId = msg.from.id;
205
+ const chatId = msg.chat.id;
206
+ if (!isAdmin(userId)) {
207
+ bot.sendMessage(chatId, '❌ غير مصرح.');
208
+ log(`Unauthorized /urlchange from user ${userId}`);
209
+ return;
210
+ }
211
+ const streamId = match[1];
212
+ const newM3u8Url = match[2].trim();
213
 
214
+ if (!activeStreams.has(streamId)) {
215
+ bot.sendMessage(chatId, `❌ لا يوجد بث برقم ${streamId}.`);
216
+ return;
217
+ }
218
+
219
+ if (!newM3u8Url.startsWith('http')) {
220
+ bot.sendMessage(chatId, '❌ رابط M3U8 جديد غير صالح.');
221
+ return;
222
+ }
223
+
224
+ const stream = activeStreams.get(streamId);
225
  stream.process.kill('SIGTERM');
226
+ bot.sendMessage(chatId, `⏳ جاري تحديث رابط البث ${streamId}...`);
227
+
228
+ // Re-run stream with new URL but same other parameters
229
  bot.emit('text', {
230
  ...msg,
231
+ text: `/stream ${stream.rtmpsUrl.split('/').pop()} ${newM3u8Url} ${stream.watermark || ''} ${stream.cc}`,
232
  });
233
  });
234
 
235
+ // /cchange <streamId> <new_cc>
236
  bot.onText(/\/cchange (\d{4}) (.+)/, (msg, match) => {
237
+ const userId = msg.from.id;
238
+ const chatId = msg.chat.id;
239
+ if (!isAdmin(userId)) {
240
+ bot.sendMessage(chatId, '❌ غير مصرح.');
241
+ log(`Unauthorized /cchange from user ${userId}`);
242
+ return;
243
+ }
244
+ const streamId = match[1];
245
+ const newCcText = match[2].trim();
246
 
247
+ if (!activeStreams.has(streamId)) {
248
+ bot.sendMessage(chatId, `❌ لا يوجد بث برقم ${streamId}.`);
249
+ return;
250
+ }
251
+
252
+ const stream = activeStreams.get(streamId);
253
  stream.process.kill('SIGTERM');
254
+ bot.sendMessage(chatId, `⏳ جاري تحديث النص المتحرك للبث ${streamId}...`);
255
+
256
+ // Re-run stream with new CC text but same other parameters
257
  bot.emit('text', {
258
  ...msg,
259
+ text: `/stream ${stream.rtmpsUrl.split('/').pop()} ${stream.m3u8Url} ${stream.watermark || ''} ${newCcText}`,
260
  });
261
  });
262
 
263
+ // /stop <streamId>
264
  bot.onText(/\/stop (\d{4})/, (msg, match) => {
265
+ const userId = msg.from.id;
266
+ const chatId = msg.chat.id;
267
+ const streamId = match[1];
268
+ if (!isAdmin(userId)) {
269
+ bot.sendMessage(chatId, '❌ غير مصرح.');
270
+ log(`Unauthorized /stop from user ${userId}`);
271
+ return;
272
+ }
273
+ if (!activeStreams.has(streamId)) {
274
+ bot.sendMessage(chatId, `❌ لا يوجد بث برقم ${streamId}.`);
275
+ return;
276
+ }
277
 
278
+ const stream = activeStreams.get(streamId);
279
  stream.process.kill('SIGTERM');
280
+ activeStreams.delete(streamId);
281
+ bot.sendMessage(chatId, `🛑 تم إيقاف البث ${streamId}.`);
282
+ log(`Stream ${streamId} stopped by user ${userId}`);
283
  });
284
 
285
+ // /check system info (RAM in GB, uptime, loadavg)
286
  bot.onText(/\/check/, (msg) => {
287
+ const userId = msg.from.id;
288
+ const chatId = msg.chat.id;
289
+ if (!isAdmin(userId)) {
290
+ bot.sendMessage(chatId, '❌ غير مصرح.');
291
+ log(`Unauthorized /check from user ${userId}`);
292
+ return;
293
+ }
294
+
295
  const mem = process.memoryUsage();
296
+ const totalMem = os.totalmem();
297
+ const freeMem = os.freemem();
298
  const load = os.loadavg();
299
  const uptime = process.uptime();
300
+
301
+ const usedGB = (mem.rss / 1024 / 1024 / 1024).toFixed(2);
302
+ const freeGB = (freeMem / 1024 / 1024 / 1024).toFixed(2);
303
+ const totalGB = (totalMem / 1024 / 1024 / 1024).toFixed(2);
304
+
305
+ bot.sendMessage(chatId, `
306
+ 📟 معلومات النظام:
307
+ - وقت التشغيل: ${(uptime / 60).toFixed(1)} دقيقة
308
+ - ذاكرة البوت المستخدمة: ${usedGB} جيجابايت
309
+ - الذاكرة الحرة للنظام: ${freeGB} جيجابايت
310
+ - إجمالي ذاكرة النظام: ${totalGB} جيجابايت
311
+ - معدل تحميل النظام: ${load.map(v => v.toFixed(2)).join(', ')}
312
+ `.trim());
313
+ log(`System info sent to user ${userId}`);
314
  });
315
 
316
+ console.log(`✅ Bot started and polling...`);