Spaces:
Sleeping
Sleeping
| // 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(` | |
| <h1>Telegram Media Downloader Bot</h1> | |
| <p>Bot Status: <span style="color: green;">Running β </span></p> | |
| <p>Active Cloned Bots: ${clonedBots.size}</p> | |
| <p>Uptime: ${Math.floor(process.uptime() / 60)} minutes</p> | |
| <hr> | |
| <p>Created by Emmy - @emmyhenztech</p> | |
| `); | |
| }); | |
| 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'); |