import os import time import re import asyncio import requests import threading from http.server import HTTPServer, BaseHTTPRequestHandler from pyrogram import Client, filters, idle from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery # ========================================== # šŸŖ„ HUGGING FACE KEEP-ALIVE TRICK # ========================================== class DummyHandler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.end_headers() self.wfile.write(b"Lecture Bot is alive and running on Hugging Face!") def keep_alive(): server = HTTPServer(('0.0.0.0', 7860), DummyHandler) server.serve_forever() threading.Thread(target=keep_alive, daemon=True).start() # ========================================== # āš™ļø CONFIGURATION # ========================================== TOKEN = "8476068831:AAG9mEiMYhlIOEBYSy2P11V88NePwrJh06w" API_ID = 2040 API_HASH = "b18441a1ff607e10a989891a5462e627" BANNER_URL = "https://img.freepik.com/free-vector/laptop-with-program-code-isometric-icon-software-development-programming-applications-dark-neon_39422-971.jpg" app = Client("LectureBot", api_id=API_ID, api_hash=API_HASH, bot_token=TOKEN) user_states = {} print("šŸš€ LECTURE BOT STARTED...") # ========================================== # šŸ“¤ GOFILE UPLOAD HELPER # ========================================== def upload_to_gofile(filepath): print("Initiating Gofile Upload...") with open(filepath, 'rb') as f: files = {'file': f} # Gofile creates a guest account automatically when no token is provided res = requests.post('https://upload.gofile.io/uploadfile', files=files) data = res.json() if data.get('status') == 'ok': return data['data']['downloadPage'] else: raise Exception(f"Gofile API Error: {data.get('status')}") # ========================================== # šŸŽ® BOT HANDLERS # ========================================== @app.on_message(filters.command("start")) async def start_cmd(client, message): user_states[message.chat.id] = None keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("šŸš€ Start Extraction", callback_data="btn_extract")] ]) await message.reply_photo( photo=BANNER_URL, caption=f"šŸ‘‹ **Welcome, {message.from_user.first_name}**\n\nI am your **Lecture Downloader**.\n\nšŸ”¹ **Modes:**\n• < 50MB: Direct Telegram File\n• > 50MB: High-Speed Gofile Link\n\n_Click below to start:_".replace(".", "\\."), reply_markup=keyboard ) @app.on_callback_query() async def callback_handler(client, query: CallbackQuery): chat_id = query.message.chat.id if query.data == "btn_extract": user_states[chat_id] = "WAITING_URL" keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("āŒ Cancel", callback_data="btn_cancel")]]) await query.message.reply_text("šŸ”— **Send the Lecture Link now.**", reply_markup=keyboard) await query.answer() elif query.data == "btn_cancel": user_states[chat_id] = None await query.message.delete() await query.answer("Cancelled.") @app.on_message(filters.text & ~filters.command("start")) async def message_handler(client, message): chat_id = message.chat.id text = message.text if user_states.get(chat_id) != "WAITING_URL": return user_states[chat_id] = None # Reset state if not text.startswith("http"): return await message.reply_text("āš ļø Invalid Link.") process_msg = await message.reply_text("šŸ•µļøā€ā™‚ļø **Starting Process...**\n_Analyzing..._") try: # --- STEP 1: ANALYZE URL --- print(f"STEP 1: Analyzing URL: {text}") stream_url = text cookie_string = "" user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" try: res = requests.get(text, headers={'User-Agent': user_agent}, timeout=15) # Extract cookies if present if 'set-cookie' in res.headers: raw_cookies = res.headers['set-cookie'].split(',') cookie_string = "; ".join([c.split(';')[0] for c in raw_cookies]) # Regex check for hidden stream URL match = re.search(r"src:\s*'(/Stream/Index/[^']+)'", res.text) if match: stream_url = f"https://vss-v2-app.techsol360.com{match.group(1)}" print("āœ… Found HIDDEN Stream URL") except Exception as e: print(f"āš ļø Scrape Error: {str(e)} (Using original link)") # --- STEP 2: DOWNLOAD --- print("STEP 2: Starting FFmpeg Download...") await process_msg.edit_text("ā¬‡ļø **Downloading...**\n_Please wait..._") timestamp = int(time.time()) filepath = f"Lecture_{timestamp}.mp4" cmd = f'ffmpeg -user_agent "{user_agent}" -headers "Cookie: {cookie_string}" -i "{stream_url}" -c copy -bsf:a aac_adtstoasc "{filepath}" -y' # Run FFmpeg asynchronously so it doesn't block the bot process = await asyncio.create_subprocess_shell( cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) await process.communicate() if not os.path.exists(filepath): raise Exception("File missing after FFmpeg download.") # Check size size_bytes = os.path.getsize(filepath) size_mb = size_bytes / (1024 * 1024) print(f"āœ… Download Success. Size: {size_mb:.2f} MB") # --- STEP 3: UPLOAD --- if size_mb < 49.0: print("STEP 3: Uploading to Telegram...") await process_msg.edit_text("šŸ“¤ **Uploading to Telegram...**") await message.reply_document( document=filepath, caption=f"šŸ“¦ {size_mb:.2f} MB" ) else: print("STEP 3: Uploading to Gofile...") await process_msg.edit_text("šŸš€ **Uploading to Gofile Cloud...**") link = await asyncio.to_thread(upload_to_gofile, filepath) print(f"āœ… Gofile Success: {link}") await message.reply_text( f"āœ… **Done!**\n\nšŸ”— [Download Link]({link})\nšŸ“¦ Size: {size_mb:.2f} MB", disable_web_page_preview=True ) # Cleanup if os.path.exists(filepath): os.remove(filepath) except Exception as e: print(f"āŒ CRITICAL ERROR: {str(e)}") await process_msg.edit_text(f"āŒ **Process Failed.**\n`{str(e)}`") if 'filepath' in locals() and os.path.exists(filepath): os.remove(filepath) if __name__ == "__main__": app.run()