understanding commited on
Commit
c67e26d
·
verified ·
1 Parent(s): cb21994

Rename database.py to terabox.py

Browse files
Files changed (2) hide show
  1. database.py +0 -0
  2. terabox.py +420 -0
database.py DELETED
File without changes
terabox.py ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from aria2p import API as Aria2API, Client as Aria2Client
2
+ import asyncio
3
+ from dotenv import load_dotenv
4
+ from datetime import datetime
5
+ import os
6
+ import logging
7
+ import math
8
+ from pyrogram import Client, filters
9
+ from pyrogram.types import Message, InlineKeyboardButton, InlineKeyboardMarkup
10
+ from pyrogram.enums import ChatMemberStatus
11
+ from pyrogram.errors import FloodWait
12
+ import time
13
+ import urllib.parse
14
+ from urllib.parse import urlparse
15
+ from flask import Flask, render_template
16
+ from threading import Thread
17
+
18
+ load_dotenv('config.env', override=True)
19
+ logging.basicConfig(
20
+ level=logging.INFO,
21
+ format="[%(asctime)s - %(name)s - %(levelname)s] %(message)s - %(filename)s:%(lineno)d"
22
+ )
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+ logging.getLogger("pyrogram.session").setLevel(logging.ERROR)
27
+ logging.getLogger("pyrogram.connection").setLevel(logging.ERROR)
28
+ logging.getLogger("pyrogram.dispatcher").setLevel(logging.ERROR)
29
+
30
+ aria2 = Aria2API(
31
+ Aria2Client(
32
+ host="http://localhost",
33
+ port=6800,
34
+ secret=""
35
+ )
36
+ )
37
+ options = {
38
+ "max-tries": "50",
39
+ "retry-wait": "3",
40
+ "continue": "true",
41
+ "allow-overwrite": "true",
42
+ "min-split-size": "4M",
43
+ "split": "10"
44
+ }
45
+
46
+ aria2.set_global_options(options)
47
+
48
+ API_ID = os.environ.get('TELEGRAM_API', '')
49
+ if len(API_ID) == 0:
50
+ logging.error("TELEGRAM_API variable is missing! Exiting now")
51
+ exit(1)
52
+
53
+ API_HASH = os.environ.get('TELEGRAM_HASH', '')
54
+ if len(API_HASH) == 0:
55
+ logging.error("TELEGRAM_HASH variable is missing! Exiting now")
56
+ exit(1)
57
+
58
+ BOT_TOKEN = os.environ.get('BOT_TOKEN', '')
59
+ if len(BOT_TOKEN) == 0:
60
+ logging.error("BOT_TOKEN variable is missing! Exiting now")
61
+ exit(1)
62
+
63
+ DUMP_CHAT_ID = os.environ.get('DUMP_CHAT_ID', '')
64
+ if len(DUMP_CHAT_ID) == 0:
65
+ logging.error("DUMP_CHAT_ID variable is missing! Exiting now")
66
+ exit(1)
67
+ else:
68
+ DUMP_CHAT_ID = int(DUMP_CHAT_ID)
69
+
70
+ FSUB_ID = os.environ.get('FSUB_ID', '')
71
+ if len(FSUB_ID) == 0:
72
+ logging.error("FSUB_ID variable is missing! Exiting now")
73
+ exit(1)
74
+ else:
75
+ FSUB_ID = int(FSUB_ID)
76
+
77
+ USER_SESSION_STRING = os.environ.get('USER_SESSION_STRING', '')
78
+ if len(USER_SESSION_STRING) == 0:
79
+ logging.info("USER_SESSION_STRING variable is missing! Bot will split Files in 2Gb...")
80
+ USER_SESSION_STRING = None
81
+
82
+ app = Client("jetbot", api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN)
83
+
84
+ user = None
85
+ SPLIT_SIZE = 2093796556
86
+ if USER_SESSION_STRING:
87
+ user = Client("jetu", api_id=API_ID, api_hash=API_HASH, session_string=USER_SESSION_STRING)
88
+ SPLIT_SIZE = 4241280205
89
+
90
+ VALID_DOMAINS = [
91
+ 'terabox.com', 'nephobox.com', '4funbox.com', 'mirrobox.com',
92
+ 'momerybox.com', 'teraboxapp.com', '1024tera.com',
93
+ 'terabox.app', 'gibibox.com', 'goaibox.com', 'terasharelink.com',
94
+ 'teraboxlink.com', 'terafileshare.com'
95
+ ]
96
+ last_update_time = 0
97
+
98
+ async def is_user_member(client, user_id):
99
+ try:
100
+ member = await client.get_chat_member(FSUB_ID, user_id)
101
+ if member.status in [ChatMemberStatus.MEMBER, ChatMemberStatus.ADMINISTRATOR, ChatMemberStatus.OWNER]:
102
+ return True
103
+ else:
104
+ return False
105
+ except Exception as e:
106
+ logging.error(f"Error checking membership status for user {user_id}: {e}")
107
+ return False
108
+
109
+ def is_valid_url(url):
110
+ parsed_url = urlparse(url)
111
+ return any(parsed_url.netloc.endswith(domain) for domain in VALID_DOMAINS)
112
+
113
+ def format_size(size):
114
+ if size < 1024:
115
+ return f"{size} B"
116
+ elif size < 1024 * 1024:
117
+ return f"{size / 1024:.2f} KB"
118
+ elif size < 1024 * 1024 * 1024:
119
+ return f"{size / (1024 * 1024):.2f} MB"
120
+ else:
121
+ return f"{size / (1024 * 1024 * 1024):.2f} GB"
122
+
123
+ @app.on_message(filters.command("start"))
124
+ async def start_command(client: Client, message: Message):
125
+ join_button = InlineKeyboardButton("ᴊᴏɪɴ ❤️🚀", url="https://t.me/jetmirror")
126
+ developer_button = InlineKeyboardButton("ᴅᴇᴠᴇʟᴏᴘᴇʀ ⚡️", url="https://t.me/rtx5069")
127
+ repo69 = InlineKeyboardButton("ʀᴇᴘᴏ 🌐", url="https://github.com/Hrishi2861/Terabox-Downloader-Bot")
128
+ user_mention = message.from_user.mention
129
+ reply_markup = InlineKeyboardMarkup([[join_button, developer_button], [repo69]])
130
+ final_msg = f"ᴡᴇʟᴄᴏᴍᴇ, {user_mention}.\n\n🌟 ɪ ᴀᴍ ᴀ ᴛᴇʀᴀʙᴏx ᴅᴏᴡɴʟᴏᴀᴅᴇʀ ʙᴏᴛ. sᴇɴᴅ ᴍᴇ ᴀɴʏ ᴛᴇʀᴀʙᴏx ʟɪɴᴋ ɪ ᴡɪʟʟ ᴅᴏᴡɴʟᴏᴀᴅ ᴡɪᴛʜɪɴ ғᴇᴡ sᴇᴄᴏɴᴅs ᴀɴᴅ sᴇɴᴅ ɪᴛ ᴛᴏ ʏᴏᴜ ✨."
131
+ video_file_id = "/app/Jet-Mirror.mp4"
132
+ if os.path.exists(video_file_id):
133
+ await client.send_video(
134
+ chat_id=message.chat.id,
135
+ video=video_file_id,
136
+ caption=final_msg,
137
+ reply_markup=reply_markup
138
+ )
139
+ else:
140
+ await message.reply_text(final_msg, reply_markup=reply_markup)
141
+
142
+ async def update_status_message(status_message, text):
143
+ try:
144
+ await status_message.edit_text(text)
145
+ except Exception as e:
146
+ logger.error(f"Failed to update status message: {e}")
147
+
148
+ @app.on_message(filters.text)
149
+ async def handle_message(client: Client, message: Message):
150
+ if message.text.startswith('/'):
151
+ return
152
+ if not message.from_user:
153
+ return
154
+
155
+ user_id = message.from_user.id
156
+ is_member = await is_user_member(client, user_id)
157
+
158
+ if not is_member:
159
+ join_button = InlineKeyboardButton("ᴊᴏɪɴ ❤️🚀", url="https://t.me/jetmirror")
160
+ reply_markup = InlineKeyboardMarkup([[join_button]])
161
+ await message.reply_text("ʏᴏᴜ ᴍᴜsᴛ ᴊᴏɪɴ ᴍʏ ᴄʜᴀɴɴᴇʟ ᴛᴏ ᴜsᴇ ᴍᴇ.", reply_markup=reply_markup)
162
+ return
163
+
164
+ url = None
165
+ for word in message.text.split():
166
+ if is_valid_url(word):
167
+ url = word
168
+ break
169
+
170
+ if not url:
171
+ await message.reply_text("Please provide a valid Terabox link.")
172
+ return
173
+
174
+ encoded_url = urllib.parse.quote(url)
175
+ final_url = f"https://teradlrobot.cheemsbackup.workers.dev/?url={encoded_url}"
176
+
177
+ download = aria2.add_uris([final_url])
178
+ status_message = await message.reply_text("sᴇɴᴅɪɴɢ ʏᴏᴜ ᴛʜᴇ ᴍᴇᴅɪᴀ...🤤")
179
+
180
+ start_time = datetime.now()
181
+
182
+ while not download.is_complete:
183
+ await asyncio.sleep(15)
184
+ download.update()
185
+ progress = download.progress
186
+
187
+ elapsed_time = datetime.now() - start_time
188
+ elapsed_minutes, elapsed_seconds = divmod(elapsed_time.seconds, 60)
189
+
190
+ status_text = (
191
+ f"┏ ғɪʟᴇɴᴀᴍᴇ: {download.name}\n"
192
+ f"┠ [{'★' * int(progress / 10)}{'☆' * (10 - int(progress / 10))}] {progress:.2f}%\n"
193
+ f"┠ ᴘʀᴏᴄᴇssᴇᴅ: {format_size(download.completed_length)} ᴏғ {format_size(download.total_length)}\n"
194
+ f"┠ sᴛᴀᴛᴜs: 📥 Downloading\n"
195
+ f"┠ ᴇɴɢɪɴᴇ: <b><u>Aria2c v1.37.0</u></b>\n"
196
+ f"┠ sᴘᴇᴇᴅ: {format_size(download.download_speed)}/s\n"
197
+ f"┠ ᴇᴛᴀ: {download.eta} | ᴇʟᴀᴘsᴇᴅ: {elapsed_minutes}m {elapsed_seconds}s\n"
198
+ f"┖ ᴜsᴇʀ: <a href='tg://user?id={user_id}'>{message.from_user.first_name}</a> | ɪᴅ: {user_id}\n"
199
+ )
200
+ while True:
201
+ try:
202
+ await update_status_message(status_message, status_text)
203
+ break
204
+ except FloodWait as e:
205
+ logger.error(f"Flood wait detected! Sleeping for {e.value} seconds")
206
+ await asyncio.sleep(e.value)
207
+
208
+ file_path = download.files[0].path
209
+ caption = (
210
+ f"✨ {download.name}\n"
211
+ f"👤 ʟᴇᴇᴄʜᴇᴅ ʙʏ : <a href='tg://user?id={user_id}'>{message.from_user.first_name}</a>\n"
212
+ f"📥 ᴜsᴇʀ ʟɪɴᴋ: tg://user?id={user_id}\n\n"
213
+ "[ᴘᴏᴡᴇʀᴇᴅ ʙʏ ᴊᴇᴛ-ᴍɪʀʀᴏʀ ❤️🚀](https://t.me/JetMirror)"
214
+ )
215
+
216
+ last_update_time = time.time()
217
+ UPDATE_INTERVAL = 15
218
+
219
+ async def update_status(message, text):
220
+ nonlocal last_update_time
221
+ current_time = time.time()
222
+ if current_time - last_update_time >= UPDATE_INTERVAL:
223
+ try:
224
+ await message.edit_text(text)
225
+ last_update_time = current_time
226
+ except FloodWait as e:
227
+ logger.warning(f"FloodWait: Sleeping for {e.value}s")
228
+ await asyncio.sleep(e.value)
229
+ await update_status(message, text)
230
+ except Exception as e:
231
+ logger.error(f"Error updating status: {e}")
232
+
233
+ async def upload_progress(current, total):
234
+ progress = (current / total) * 100
235
+ elapsed_time = datetime.now() - start_time
236
+ elapsed_minutes, elapsed_seconds = divmod(elapsed_time.seconds, 60)
237
+
238
+ status_text = (
239
+ f"┏ ғɪʟᴇɴᴀᴍᴇ: {download.name}\n"
240
+ f"┠ [{'★' * int(progress / 10)}{'☆' * (10 - int(progress / 10))}] {progress:.2f}%\n"
241
+ f"┠ ᴘʀᴏᴄᴇssᴇᴅ: {format_size(current)} ᴏғ {format_size(total)}\n"
242
+ f"┠ sᴛᴀᴛᴜs: 📤 Uploading to Telegram\n"
243
+ f"┠ ᴇɴɢɪɴᴇ: <b><u>PyroFork v2.2.11</u></b>\n"
244
+ f"┠ sᴘᴇᴇᴅ: {format_size(current / elapsed_time.seconds if elapsed_time.seconds > 0 else 0)}/s\n"
245
+ f"┠ ᴇʟᴀᴘsᴇᴅ: {elapsed_minutes}m {elapsed_seconds}s\n"
246
+ f"┖ ᴜsᴇʀ: <a href='tg://user?id={user_id}'>{message.from_user.first_name}</a> | ɪᴅ: {user_id}\n"
247
+ )
248
+ await update_status(status_message, status_text)
249
+
250
+ async def split_video_with_ffmpeg(input_path, output_prefix, split_size):
251
+ try:
252
+ original_ext = os.path.splitext(input_path)[1].lower() or '.mp4'
253
+ start_time = datetime.now()
254
+ last_progress_update = time.time()
255
+
256
+ proc = await asyncio.create_subprocess_exec(
257
+ 'ffprobe', '-v', 'error', '-show_entries', 'format=duration',
258
+ '-of', 'default=noprint_wrappers=1:nokey=1', input_path,
259
+ stdout=asyncio.subprocess.PIPE,
260
+ stderr=asyncio.subprocess.PIPE
261
+ )
262
+ stdout, _ = await proc.communicate()
263
+ total_duration = float(stdout.decode().strip())
264
+
265
+ file_size = os.path.getsize(input_path)
266
+ parts = math.ceil(file_size / split_size)
267
+
268
+ if parts == 1:
269
+ return [input_path]
270
+
271
+ duration_per_part = total_duration / parts
272
+ split_files = []
273
+
274
+ for i in range(parts):
275
+ current_time = time.time()
276
+ if current_time - last_progress_update >= UPDATE_INTERVAL:
277
+ elapsed = datetime.now() - start_time
278
+ status_text = (
279
+ f"✂️ Splitting {os.path.basename(input_path)}\n"
280
+ f"Part {i+1}/{parts}\n"
281
+ f"Elapsed: {elapsed.seconds // 60}m {elapsed.seconds % 60}s"
282
+ )
283
+ await update_status(status_message, status_text)
284
+ last_progress_update = current_time
285
+
286
+ output_path = f"{output_prefix}.{i+1:03d}{original_ext}"
287
+ cmd = [
288
+ 'xtra', '-y', '-ss', str(i * duration_per_part),
289
+ '-i', input_path, '-t', str(duration_per_part),
290
+ '-c', 'copy', '-map', '0',
291
+ '-avoid_negative_ts', 'make_zero',
292
+ output_path
293
+ ]
294
+
295
+ proc = await asyncio.create_subprocess_exec(*cmd)
296
+ await proc.wait()
297
+ split_files.append(output_path)
298
+
299
+ return split_files
300
+ except Exception as e:
301
+ logger.error(f"Split error: {e}")
302
+ raise
303
+
304
+ async def handle_upload():
305
+ file_size = os.path.getsize(file_path)
306
+
307
+ if file_size > SPLIT_SIZE:
308
+ await update_status(
309
+ status_message,
310
+ f"✂️ Splitting {download.name} ({format_size(file_size)})"
311
+ )
312
+
313
+ split_files = await split_video_with_ffmpeg(
314
+ file_path,
315
+ os.path.splitext(file_path)[0],
316
+ SPLIT_SIZE
317
+ )
318
+
319
+ try:
320
+ for i, part in enumerate(split_files):
321
+ part_caption = f"{caption}\n\nPart {i+1}/{len(split_files)}"
322
+ await update_status(
323
+ status_message,
324
+ f"📤 Uploading part {i+1}/{len(split_files)}\n"
325
+ f"{os.path.basename(part)}"
326
+ )
327
+
328
+ if USER_SESSION_STRING:
329
+ sent = await user.send_video(
330
+ DUMP_CHAT_ID, part,
331
+ caption=part_caption,
332
+ progress=upload_progress
333
+ )
334
+ await app.copy_message(
335
+ message.chat.id, DUMP_CHAT_ID, sent.id
336
+ )
337
+ else:
338
+ sent = await client.send_video(
339
+ DUMP_CHAT_ID, part,
340
+ caption=part_caption,
341
+ progress=upload_progress
342
+ )
343
+ await client.send_video(
344
+ message.chat.id, sent.video.file_id,
345
+ caption=part_caption
346
+ )
347
+ os.remove(part)
348
+ finally:
349
+ for part in split_files:
350
+ try: os.remove(part)
351
+ except: pass
352
+ else:
353
+ await update_status(
354
+ status_message,
355
+ f"📤 Uploading {download.name}\n"
356
+ f"Size: {format_size(file_size)}"
357
+ )
358
+
359
+ if USER_SESSION_STRING:
360
+ sent = await user.send_video(
361
+ DUMP_CHAT_ID, file_path,
362
+ caption=caption,
363
+ progress=upload_progress
364
+ )
365
+ await app.copy_message(
366
+ message.chat.id, DUMP_CHAT_ID, sent.id
367
+ )
368
+ else:
369
+ sent = await client.send_video(
370
+ DUMP_CHAT_ID, file_path,
371
+ caption=caption,
372
+ progress=upload_progress
373
+ )
374
+ await client.send_video(
375
+ message.chat.id, sent.video.file_id,
376
+ caption=caption
377
+ )
378
+ if os.path.exists(file_path):
379
+ os.remove(file_path)
380
+
381
+ start_time = datetime.now()
382
+ await handle_upload()
383
+
384
+ try:
385
+ await status_message.delete()
386
+ await message.delete()
387
+ except Exception as e:
388
+ logger.error(f"Cleanup error: {e}")
389
+
390
+ flask_app = Flask(__name__)
391
+
392
+ @flask_app.route('/')
393
+ def home():
394
+ return render_template("index.html")
395
+
396
+ def run_flask():
397
+ flask_app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
398
+
399
+ def keep_alive():
400
+ Thread(target=run_flask).start()
401
+
402
+ async def start_user_client():
403
+ if user:
404
+ await user.start()
405
+ logger.info("User client started.")
406
+
407
+ def run_user():
408
+ loop = asyncio.new_event_loop()
409
+ asyncio.set_event_loop(loop)
410
+ loop.run_until_complete(start_user_client())
411
+
412
+ if __name__ == "__main__":
413
+ keep_alive()
414
+
415
+ if user:
416
+ logger.info("Starting user client...")
417
+ Thread(target=run_user).start()
418
+
419
+ logger.info("Starting bot client...")
420
+ app.run()