| """ |
| TikTok Downloader Bot - Gradio Web Interface |
| """ |
| import os |
| import sys |
| import asyncio |
| import tempfile |
| import logging |
| import threading |
| import yt_dlp |
| import gradio as gr |
| from pyrogram import Client, filters |
| from pyrogram.enums import ParseMode |
|
|
| |
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
|
| |
| from config import API_ID, API_HASH, BOT_TOKEN |
|
|
| |
| app = Client("TikTokDownloaderBot", api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN) |
|
|
| |
| bot_status = {"status": "Initializing...", "running": False} |
|
|
| |
|
|
| @app.on_message(filters.command("start") & filters.private) |
| async def start_handler(client, message): |
| await message.reply_text( |
| "π **Welcome to TikTok Downloader Bot!**\n\n" |
| "Send me a TikTok video link to download.\n\n" |
| "**Commands:**\n" |
| "/tt <url> - Download TikTok video\n" |
| "/help - Show help", |
| parse_mode=ParseMode.MARKDOWN |
| ) |
|
|
| @app.on_message(filters.command("help") & filters.private) |
| async def help_handler(client, message): |
| await message.reply_text( |
| "π **Help**\n\n" |
| "**Usage:**\n" |
| "1. Send a TikTok video link\n" |
| "2. Wait for download\n" |
| "3. Video will be sent to you\n\n" |
| "**Supported:**\n" |
| "- TikTok videos (with/without watermark)\n" |
| "- Video metadata display", |
| parse_mode=ParseMode.MARKDOWN |
| ) |
|
|
| @app.on_message(filters.command("tt") & filters.private) |
| async def download_handler(client, message): |
| if len(message.command) < 2: |
| await message.reply_text( |
| "β **Please provide a TikTok URL**\n\n" |
| "**Usage:** `/tt <tiktok_url>`", |
| parse_mode=ParseMode.MARKDOWN |
| ) |
| return |
| |
| url = message.command[1] |
| status_msg = await message.reply_text("π Searching...") |
| |
| try: |
| |
| await status_msg.edit("π‘ Fetching video info...") |
| ydl_opts = {'quiet': True, 'extract_flat': False} |
| with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
| info = ydl.extract_info(url, download=False) |
| title = info.get('title', 'Video') |
| views = info.get('view_count', 0) |
| duration = info.get('duration', 0) |
| |
| |
| await status_msg.edit("β¬οΈ Downloading video...") |
| output_file = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) |
| output_file.close() |
| |
| ydl_opts = { |
| "format": "mp4", |
| "outtmpl": output_file.name, |
| "quiet": True, |
| } |
| with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
| ydl.download([url]) |
| |
| |
| await status_msg.edit("β¬οΈ Uploading to Telegram...") |
| duration_str = f"{int(duration//60)}:{int(duration%60):02d}" if duration else "N/A" |
| |
| caption = ( |
| f"π΅ **Title:** {title}\n" |
| f"ποΈ **Views:** {views:,}\n" |
| f"β±οΈ **Duration:** {duration_str}\n" |
| f"π [Watch on TikTok]({url})" |
| ) |
| |
| await message.reply_video( |
| video=output_file.name, |
| caption=caption, |
| parse_mode=ParseMode.MARKDOWN |
| ) |
| |
| await status_msg.delete() |
| os.remove(output_file.name) |
| |
| except Exception as e: |
| logger.error(f"Download error: {e}") |
| await status_msg.edit(f"β **Error:** `{str(e)}`", parse_mode=ParseMode.MARKDOWN) |
|
|
| |
|
|
| def download_tiktok(url): |
| """Download TikTok video using yt-dlp""" |
| output_file = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) |
| output_file.close() |
| |
| ydl_opts = { |
| "format": "mp4", |
| "outtmpl": output_file.name, |
| "quiet": True, |
| } |
| |
| try: |
| with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
| info = ydl.extract_info(url, download=True) |
| return output_file.name, info.get('title', 'Video') |
| except Exception as e: |
| logger.error(f"Download error: {e}") |
| return None, str(e) |
|
|
| def get_video_info(url): |
| """Get video metadata without downloading""" |
| ydl_opts = {'quiet': True, 'extract_flat': False} |
| try: |
| with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
| info = ydl.extract_info(url, download=False) |
| return { |
| "title": info.get('title', 'N/A'), |
| "views": f"{info.get('view_count', 0):,}", |
| "duration": f"{int(info.get('duration', 0)//60)}:{int(info.get('duration', 0)%60):02d}", |
| } |
| except Exception as e: |
| return {"error": str(e)} |
|
|
| def gradio_download(url): |
| """Gradio interface for downloading TikTok videos""" |
| if not url: |
| yield None, "β Please enter a TikTok URL" |
| return |
| |
| yield None, "π Fetching video info..." |
| info = get_video_info(url) |
| |
| if "error" in info: |
| yield None, f"β Error: {info['error']}" |
| return |
| |
| yield None, f"π₯ Downloading: {info['title']}..." |
| file_path, result = download_tiktok(url) |
| |
| if not file_path: |
| yield None, f"β Download failed: {result}" |
| return |
| |
| yield file_path, f"β
Success! Downloaded: {info['title']}" |
| |
| try: |
| os.remove(file_path) |
| except: |
| pass |
|
|
| |
|
|
| def run_pyrogram(): |
| """Run Pyrogram bot in separate thread""" |
| global bot_status |
| try: |
| if API_ID and API_HASH and BOT_TOKEN: |
| bot_status["status"] = "π€ Telegram bot starting..." |
| import asyncio |
| loop = asyncio.new_event_loop() |
| asyncio.set_event_loop(loop) |
| loop.run_until_complete(app.run()) |
| else: |
| bot_status["status"] = "β οΈ Telegram credentials not configured" |
| except Exception as e: |
| bot_status["status"] = f"β Bot error: {e}" |
| logger.error(f"Bot error: {e}") |
|
|
| |
| if API_ID and API_HASH and BOT_TOKEN: |
| bot_thread = threading.Thread(target=run_pyrogram, daemon=True) |
| bot_thread.start() |
| bot_status["status"] = "π€ Telegram bot running" |
| bot_status["running"] = True |
| else: |
| bot_status["status"] = "β οΈ Telegram credentials not configured" |
|
|
| |
|
|
| with gr.Blocks(title="TikTok Downloader") as demo: |
| gr.Markdown("# π΅ TikTok Video Downloader") |
| gr.Markdown("### Download TikTok videos directly to your device") |
| |
| with gr.Row(): |
| with gr.Column(): |
| url_input = gr.Textbox(label="TikTok URL", placeholder="Paste TikTok link here...") |
| download_btn = gr.Button("β¬οΈ Download", variant="primary") |
| with gr.Column(): |
| video_output = gr.Video(label="Downloaded Video") |
| status_output = gr.Textbox(label="Status", lines=2) |
| |
| gr.Markdown("---") |
| gr.Markdown(f"**Telegram Bot Status:** `{bot_status['status']}`") |
| gr.Markdown(""" |
| ### π How to use: |
| 1. Paste TikTok URL above |
| 2. Click Download |
| 3. Save the video |
| """) |
| |
| download_btn.click(fn=gradio_download, inputs=url_input, outputs=[video_output, status_output]) |
|
|
| if __name__ == "__main__": |
| demo.launch(server_name="0.0.0.0", server_port=7860) |
|
|