File size: 6,798 Bytes
bf627d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854a069
bf627d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854a069
bf627d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854a069
bf627d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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()