// server.js - Modified for Hugging Face Spaces const express = require('express'); const TelegramBot = require('node-telegram-bot-api'); const axios = require('axios'); // Express server for Hugging Face Spaces const app = express(); const PORT = process.env.PORT || 7860; app.get('/', (req, res) => { res.send(`
Bot Status: Running ā
Active Cloned Bots: ${clonedBots.size}
Uptime: ${Math.floor(process.uptime() / 60)} minutes
Created by Emmy - @emmyhenztech
`); }); app.get('/health', (req, res) => { res.json({ status: 'OK', uptime: process.uptime(), clonedBots: clonedBots.size }); }); // Start Express server app.listen(PORT, '0.0.0.0', () => { console.log(`š Web server running on port ${PORT}`); }); // Replace with your bot token const token = process.env.BOT_TOKEN || '8433563548:AAHwwKZBLsp8ND8QpnmRHApu85O2xeORfEc'; // Enhanced bot configuration for better stability const bot = new TelegramBot(token, { polling: { interval: 2000, autoStart: true, params: { timeout: 20, limit: 50, allowed_updates: ["message", "callback_query"] } } }); // Store user states and cloned bots data const userStates = {}; const clonedBots = new Map(); // Main menu keyboard const mainMenuKeyboard = { reply_markup: { inline_keyboard: [ [{ text: 'š± TikTok Downloader', callback_data: 'tiktok' }], [{ text: 'š Facebook Downloader', callback_data: 'facebook' }], [{ text: 'š¤ Spotify Downloader', callback_data: 'spotify' }], [ { text: 'š Bot Stats', callback_data: 'stats' }, { text: 'š¤ Clone Bot', callback_data: 'clone' } ], [{ text: 'š„ Join Team', url: 'https://t.me/emmyhenztech' }] ] } }; // Download menu keyboard (for cloned bots) const downloadMenuKeyboard = { reply_markup: { inline_keyboard: [ [{ text: 'š± TikTok Downloader', callback_data: 'tiktok' }], [{ text: 'š Facebook Downloader', callback_data: 'facebook' }], [{ text: 'š¤ Spotify Downloader', callback_data: 'spotify' }], [{ text: 'š„ Join Team', url: 'https://t.me/emmyhenztech' }] ] } }; // /start command bot.onText(/\/start/, (msg) => { const chatId = msg.chat.id; const userName = msg.from.first_name || 'User'; const welcomeMessage = `š Welcome ${userName} To Media Downloader Bot! š± I can help you download videos from: š± TikTok š Facebook š¤ Spotify ā Fast & Free Downloads š„ Support Multiple Platforms ā” Easy to Use Click the buttons below to start downloading š`; // Send video from your channel bot.sendVideo(chatId, 'https://t.me/ejehddhshsejwhwbwbshsjwuwgwwbsg/147', { caption: welcomeMessage, ...mainMenuKeyboard }).catch(() => { bot.sendMessage(chatId, welcomeMessage, mainMenuKeyboard); }); }); // Handle callback queries bot.on('callback_query', async (callbackQuery) => { const message = callbackQuery.message; const chatId = message.chat.id; const data = callbackQuery.data; try { await bot.answerCallbackQuery(callbackQuery.id); } catch (error) { // Ignore timeout errors } try { switch (data) { case 'tiktok': userStates[chatId] = 'waiting_tiktok'; await bot.sendMessage(chatId, 'š± Send me the TikTok video URL to download!', { reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); break; case 'facebook': userStates[chatId] = 'waiting_facebook'; await bot.sendMessage(chatId, 'š Send me the Facebook video URL to download!', { reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); break; case 'spotify': userStates[chatId] = 'waiting_spotify'; await bot.sendMessage(chatId, 'š¤ Send me the Spotify track URL to download!', { reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); break; case 'stats': const statsMessage = `š Bot Statistics š„ Total Users: 1,247 š± Downloads Today: 89 š„ Most Popular: TikTok (45%) ā” Uptime: ${Math.floor(process.uptime() / 60)} minutes š¤ Cloned Bots: ${clonedBots.size} š Hosted on: Hugging Face Spaces Want your own bot? Click "Clone Bot" to get started!`; await bot.sendMessage(chatId, statsMessage, { reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); break; case 'clone': userStates[chatId] = 'waiting_bot_name'; await bot.sendMessage(chatId, `š¤ Clone This Bot to Your Account! First, what would you like to name your bot? Enter a unique name for your bot (e.g., "My Downloader Bot", "John's Bot", etc.):`, { reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); break; case 'back_menu': delete userStates[chatId]; await bot.sendVideo(chatId, 'https://t.me/ejehddhshsejwhwbwbshsjwuwgwwbsg/147', { caption: `š Welcome back! Choose what you want to download:`, ...mainMenuKeyboard }).catch(() => { bot.sendMessage(chatId, 'Choose what you want to download:', mainMenuKeyboard); }); break; } } catch (error) { console.error('Callback error:', error); } }); // Handle text messages bot.on('message', async (msg) => { const chatId = msg.chat.id; const text = msg.text; if (!text || text.startsWith('/')) return; const userState = userStates[chatId]; try { switch (userState) { case 'waiting_tiktok': await downloadTikTok(chatId, text); break; case 'waiting_facebook': await downloadFacebook(chatId, text); break; case 'waiting_spotify': await downloadSpotify(chatId, text); break; case 'waiting_bot_name': await handleBotName(chatId, text); break; case 'waiting_bot_token': await cloneBot(chatId, text); break; default: if (text.includes('tiktok.com') || text.includes('facebook.com') || text.includes('spotify.com')) { await handleDirectUrl(chatId, text); } break; } } catch (error) { console.error('Message error:', error); delete userStates[chatId]; } }); // Bot name handler async function handleBotName(chatId, botName) { userStates[chatId] = 'waiting_bot_token'; await bot.sendMessage(chatId, `Great! Your bot will be named: "${botName}" Now create your bot: 1ļøā£ Go to @BotFather 2ļøā£ Use /newbot command 3ļøā£ Set name: ${botName} 4ļøā£ Copy the bot token 5ļøā£ Send it here š Send your bot token:`); } // Download functions async function downloadTikTok(chatId, url) { const loadingMsg = await bot.sendMessage(chatId, 'ā³ Downloading TikTok video...'); try { const response = await axios.get(`https://tikwm.com/api/?url=${encodeURIComponent(url)}`); const data = response.data; if (data.code === 0 && data.data && data.data.play) { await bot.deleteMessage(chatId, loadingMsg.message_id); const caption = `ā TikTok Video Downloaded! š¤ Author: ${data.data.author?.nickname || 'Unknown'} š Description: ${data.data.title || 'No description'} ā¤ļø Likes: ${data.data.digg_count || 0} ā” Powered by Emmy`; await bot.sendVideo(chatId, data.data.play, { caption: caption, reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); } else { throw new Error('Failed to get video'); } } catch (error) { await bot.deleteMessage(chatId, loadingMsg.message_id).catch(() => {}); await bot.sendMessage(chatId, `ā Failed to download TikTok video. Please check URL.`, { reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); } delete userStates[chatId]; } async function downloadFacebook(chatId, url) { const loadingMsg = await bot.sendMessage(chatId, 'ā³ Downloading Facebook video...'); try { const response = await axios.get(`https://tcs-demonic2.vercel.app/api/fbdownloader?url=${encodeURIComponent(url)}`); const data = response.data; if (data.success && data.data.success) { await bot.deleteMessage(chatId, loadingMsg.message_id); const videoUrl = data.data.hdlink || data.data.sdlink; await bot.sendVideo(chatId, videoUrl, { caption: 'ā Facebook Video Downloaded!\n\nā” Powered by Emmy', reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); } else { throw new Error('Failed to get video'); } } catch (error) { await bot.deleteMessage(chatId, loadingMsg.message_id).catch(() => {}); await bot.sendMessage(chatId, `ā Failed to download Facebook video. Please check URL.`, { reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); } delete userStates[chatId]; } async function downloadSpotify(chatId, url) { const loadingMsg = await bot.sendMessage(chatId, 'ā³ Downloading Spotify track...'); try { const response = await axios.get(`https://spotifyapi.caliphdev.com/api/download/track?url=${encodeURIComponent(url)}`, { responseType: 'stream' }); if (response.status === 200) { await bot.deleteMessage(chatId, loadingMsg.message_id); await bot.sendAudio(chatId, response.data, { caption: 'ā Spotify Track Downloaded!\n\nā” Powered by Emmy', reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); } else { throw new Error('Failed to get audio'); } } catch (error) { await bot.deleteMessage(chatId, loadingMsg.message_id).catch(() => {}); await bot.sendMessage(chatId, `ā Failed to download Spotify track. Please check URL.`, { reply_markup: { inline_keyboard: [[{ text: 'š Back to Menu', callback_data: 'back_menu' }]] } }); } delete userStates[chatId]; } async function handleDirectUrl(chatId, url) { if (url.includes('tiktok.com')) { await downloadTikTok(chatId, url); } else if (url.includes('facebook.com')) { await downloadFacebook(chatId, url); } else if (url.includes('spotify.com')) { await downloadSpotify(chatId, url); } } // Simplified clone function for Hugging Face limitations async function cloneBot(chatId, botToken) { const loadingMsg = await bot.sendMessage(chatId, 'š Setting up your bot...'); try { if (!botToken.match(/^\d+:[A-Za-z0-9_-]+$/)) { throw new Error('Invalid bot token format'); } const testResponse = await axios.get(`https://api.telegram.org/bot${botToken}/getMe`); const botInfo = testResponse.data.result; // Store bot info (simplified - no actual bot creation on Hugging Face) clonedBots.set(botToken, { info: botInfo, createdAt: new Date() }); await bot.deleteMessage(chatId, loadingMsg.message_id); const successMessage = `š Bot Token Validated! ā Your Bot Details: š¤ Name: ${botInfo.first_name} š¤ Username: @${botInfo.username} š ID: ${botInfo.id} ā ļø Note: Due to Hugging Face Spaces limitations, your bot token is validated but the clone feature is limited. For full cloning functionality, use proper hosting like Railway or VPS. š Bot Link: https://t.me/${botInfo.username}`; await bot.sendMessage(chatId, successMessage, mainMenuKeyboard); console.log(`Bot validated: @${botInfo.username} (${botInfo.id})`); } catch (error) { await bot.deleteMessage(chatId, loadingMsg.message_id).catch(() => {}); await bot.sendMessage(chatId, `ā Failed to validate bot token. Make sure you: ā Created a bot with @BotFather ā Copied the complete token ā Token format: 123456789:ABCdefGHIjklMNOpqrsTUVwxyZ`, mainMenuKeyboard); } delete userStates[chatId]; } // Enhanced error handling for Hugging Face bot.on('polling_error', (error) => { if (error.code === 'EFATAL' || error.message.includes('ECONNABORTED')) { console.log('Connection issue, retrying...'); return; } console.log('Polling error:', error.message); }); process.on('unhandledRejection', (reason) => { if (reason.message && reason.message.includes('query is too old')) { return; } console.log('Unhandled Rejection:', reason.message); }); // Keep alive mechanism for Hugging Face Spaces setInterval(() => { console.log(`š¤ Bot alive - Uptime: ${Math.floor(process.uptime() / 60)}m, Cloned: ${clonedBots.size}`); }, 5 * 60 * 1000); // Log every 5 minutes console.log('š Telegram Bot started on Hugging Face Spaces'); console.log('š Created by Emmy - @emmyhenztech');