understanding commited on
Commit
64f07e7
Β·
verified Β·
1 Parent(s): 00c95d7

Update bot.py

Browse files
Files changed (1) hide show
  1. bot.py +66 -76
bot.py CHANGED
@@ -1,3 +1,5 @@
 
 
1
  import asyncio
2
  import logging
3
  import os
@@ -7,7 +9,7 @@ import time
7
  from typing import Dict
8
 
9
  from aiogram import Bot, Dispatcher, types, F
10
- from aiogram.filters import CommandStart, Command
11
  from aiogram.types import Message, FSInputFile
12
  from aiogram.enums import ParseMode
13
  from aiogram.exceptions import TelegramBadRequest
@@ -42,7 +44,6 @@ bot = Bot(
42
  dp = Dispatcher()
43
  TASK_QUEUE = asyncio.Queue()
44
  BATCH_JOBS: Dict[str, Dict] = {}
45
- BOT_START_TIME = time.time()
46
 
47
  # --- Worker Logic ---
48
  async def link_processor_worker(worker_id: int):
@@ -73,10 +74,7 @@ async def link_processor_worker(worker_id: int):
73
  if error:
74
  raise ValueError(error)
75
 
76
- local_filepath, thumb_path, download_error = await terabox.download_terabox_file(
77
- download_url,
78
- raw_filename
79
- )
80
  if download_error:
81
  raise ValueError(download_error)
82
 
@@ -85,8 +83,7 @@ async def link_processor_worker(worker_id: int):
85
  'path': local_filepath,
86
  'name': raw_filename,
87
  'size': os.path.getsize(local_filepath),
88
- 'short_id': short_id,
89
- 'thumb': thumb_path
90
  }
91
 
92
  except Exception as e:
@@ -100,12 +97,18 @@ async def link_processor_worker(worker_id: int):
100
  batch_info["failed_links"].append({"link": original_link, "error": error_msg})
101
 
102
  processed, total = batch_info['processed_links'], batch_info['total_links']
103
- eta_sec = ((time.time() - batch_info['start_time']) / processed) * (total - processed) if processed > 0 else 0
 
104
 
105
  try:
106
- await batch_info["status_message"].edit_text(
107
- f"<b>πŸ”§ Batch `{batch_id[:6]}` in progress...</b>\n"
108
- f"Processed: {processed}/{total} | ETA: {int(eta_sec)} sec"
 
 
 
 
 
109
  )
110
  except TelegramBadRequest:
111
  pass
@@ -116,29 +119,17 @@ async def link_processor_worker(worker_id: int):
116
 
117
  TASK_QUEUE.task_done()
118
 
119
- async def send_and_cache_file(chat_id: int, file_info: dict, caption: str, reply_to: int) -> Message:
120
  file_path_or_id = file_info.get('file_id') or FSInputFile(file_info['path'], filename=file_info['name'])
121
  media_type = file_info.get('type')
122
  filename = file_info.get('name') or file_info.get('filename')
123
 
124
- video_exts = ('.mp4', '.mkv', '.mov', '.avi', '.webm')
125
- audio_exts = ('.mp3', '.flac', '.ogg', '.wav')
126
-
127
- sent_message = None
128
- if media_type == 'video' or filename.lower().endswith(video_exts):
129
- sent_message = await bot.send_video(chat_id, file_path_or_id, caption=caption, supports_streaming=True, reply_to_message_id=reply_to)
130
- media_type = 'video'
131
- elif media_type == 'audio' or filename.lower().endswith(audio_exts):
132
- sent_message = await bot.send_audio(chat_id, file_path_or_id, caption=caption, reply_to_message_id=reply_to)
133
- media_type = 'audio'
134
- else:
135
- sent_message = await bot.send_document(chat_id, file_path_or_id, caption=caption, reply_to_message_id=reply_to)
136
- media_type = 'document'
137
 
138
  if not file_info.get('cached') and sent_message:
139
- file_id_to_cache = getattr(sent_message, media_type).file_id
140
  await db_utils.add_to_cache(
141
- file_info['short_id'], file_id_to_cache, filename, media_type, file_info['size']
142
  )
143
 
144
  return sent_message
@@ -148,23 +139,32 @@ async def handle_batch_completion(batch_id: str):
148
  if not batch:
149
  return
150
 
151
- status_msg = batch["status_message"]
152
  successful_downloads = batch["successful_downloads"]
153
 
154
  try:
155
  if not successful_downloads:
156
  failed_links_text = "\n".join(
157
- [f"- {x['link']} \u2192 {x['error']}" for x in batch['failed_links']]
158
  )
159
- await status_msg.edit_text(
160
- f"<b>❌ Batch `{batch_id[:6]}` failed. No files could be processed.</b>\nDetails:\n{failed_links_text}"
 
 
 
 
 
161
  )
162
  return
163
 
164
- await status_msg.edit_text(
165
- f"πŸ“₯ Batch `{batch_id[:6]}` downloaded. Preparing to send {len(successful_downloads)} files..."
 
 
 
 
166
  )
167
 
 
168
  if config.FORWARD_CHANNEL_ID:
169
  await bot.forward_message(
170
  config.FORWARD_CHANNEL_ID,
@@ -173,30 +173,36 @@ async def handle_batch_completion(batch_id: str):
173
  )
174
  for item in successful_downloads:
175
  caption = f"`{item.get('name') or item.get('filename')}`"
176
- await send_and_cache_file(config.FORWARD_CHANNEL_ID, item, caption, reply_to=None)
177
  await asyncio.sleep(1)
178
 
179
  for item in successful_downloads:
180
  caption = f"`{item.get('name') or item.get('filename')}`"
181
- await send_and_cache_file(batch["source_chat_id"], item, caption, reply_to=batch['source_message_id'])
182
 
183
- summary = f"βœ… Batch `{batch_id[:6]}` complete: {len(successful_downloads)} files sent."
184
  if batch["failed_links"]:
185
  summary += f"\n❌ {len(batch['failed_links'])} links failed."
186
 
187
- await status_msg.edit_text(summary)
 
 
 
 
188
 
189
  except Exception as e:
190
  logger.error(f"Error during batch completion for {batch_id}: {e}", exc_info=True)
191
- await status_msg.edit_text(
192
- f"A critical error occurred while sending files for batch `{batch_id[:6]}`."
 
 
 
 
193
  )
194
  finally:
195
  for item in successful_downloads:
196
  if not item.get('cached') and os.path.exists(item['path']):
197
  os.remove(item['path'])
198
- if item.get('thumb') and os.path.exists(item['thumb']):
199
- os.remove(item['thumb'])
200
 
201
  del BATCH_JOBS[batch_id]
202
 
@@ -205,37 +211,17 @@ async def handle_batch_completion(batch_id: str):
205
  async def start_handler(message: Message):
206
  text = (
207
  "πŸ‘‹ <b>Welcome to the Terabox Downloader Bot!</b>\n\n"
208
- "πŸ“₯ Send me any valid Terabox link (supports multi-link batch).\n\n"
209
- f"πŸ“’ Make sure you are a member of: @{config.FORCE_SUB_CHANNEL_USERNAME}\n\n"
210
- "πŸš€ Features:\n"
211
- "- Multi batch link\n"
212
- "- Auto cache\n"
213
- "- Progress bar + ETA\n"
214
- "- No ffmpeg re-encode\n"
215
- "- Auto forward\n"
216
- "\nβœ… <i>Send links below:</i>"
217
  )
218
- await message.reply(text)
219
-
220
- @dp.message(Command("admin"))
221
- async def admin_handler(message: Message):
222
- if message.from_user.id != config.OWNER_ID:
223
- return
224
-
225
- users = await db_utils.get_all_active_user_ids_db()
226
- uptime_sec = int(time.time() - BOT_START_TIME)
227
-
228
- text = (
229
- f"πŸ“… <b>Admin Panel</b>\n\n"
230
- f"πŸ•° Uptime: {uptime_sec} sec\n"
231
- f"πŸ“Š Total users: {len(users)}\n"
232
- f"πŸ”’ Queue size: {TASK_QUEUE.qsize()}\n"
233
- f"πŸ”§ Workers: {config.CONCURRENT_WORKERS}\n"
234
- f"πŸ“ Forward Channel: {config.FORWARD_CHANNEL_ID}\n"
235
- f"πŸ“’ Force Sub Channel: @{config.FORCE_SUB_CHANNEL_USERNAME}\n"
236
- f"πŸ‘¨β€πŸ“‘ Worker URL: {config.TERABOX_WORKER_URL}"
237
  )
238
- await message.reply(text)
239
 
240
  @dp.message(F.text | F.caption)
241
  async def message_handler(message: Message):
@@ -248,7 +234,7 @@ async def message_handler(message: Message):
248
  message.from_user.first_name
249
  )
250
 
251
- links = list(set(re.findall(r'https?://[^\s<>"]+', message.text or message.caption or "")))
252
  terabox_links = [link for link in links if any(domain in link for domain in [
253
  "terabox.com", "teraboxapp.com", "terasharelink.com", "1024tera.com",
254
  "freeterabox.com", "4funbox.com", "box-links.com"
@@ -258,8 +244,13 @@ async def message_handler(message: Message):
258
  return
259
 
260
  batch_id = str(uuid.uuid4())
261
- status_msg = await message.reply(
262
- f"βœ… Found {len(terabox_links)} links. Queued as batch `{batch_id[:6]}`.",
 
 
 
 
 
263
  reply_to_message_id=message.message_id
264
  )
265
 
@@ -271,7 +262,7 @@ async def message_handler(message: Message):
271
  "source_chat_id": message.chat.id,
272
  "source_user_id": message.from_user.id,
273
  "source_message_id": message.message_id,
274
- "status_message": status_msg,
275
  "lock": asyncio.Lock(),
276
  "start_time": time.time()
277
  }
@@ -290,5 +281,4 @@ def start_bot():
290
  dp.startup.register(on_startup)
291
  dp.message.register(message_handler)
292
  dp.message.register(start_handler, CommandStart())
293
- dp.message.register(admin_handler, Command("admin"))
294
  return dp, bot
 
1
+ # bot.py
2
+
3
  import asyncio
4
  import logging
5
  import os
 
9
  from typing import Dict
10
 
11
  from aiogram import Bot, Dispatcher, types, F
12
+ from aiogram.filters import CommandStart
13
  from aiogram.types import Message, FSInputFile
14
  from aiogram.enums import ParseMode
15
  from aiogram.exceptions import TelegramBadRequest
 
44
  dp = Dispatcher()
45
  TASK_QUEUE = asyncio.Queue()
46
  BATCH_JOBS: Dict[str, Dict] = {}
 
47
 
48
  # --- Worker Logic ---
49
  async def link_processor_worker(worker_id: int):
 
74
  if error:
75
  raise ValueError(error)
76
 
77
+ local_filepath, download_error = await terabox.download_terabox_file(download_url, raw_filename)
 
 
 
78
  if download_error:
79
  raise ValueError(download_error)
80
 
 
83
  'path': local_filepath,
84
  'name': raw_filename,
85
  'size': os.path.getsize(local_filepath),
86
+ 'short_id': short_id
 
87
  }
88
 
89
  except Exception as e:
 
97
  batch_info["failed_links"].append({"link": original_link, "error": error_msg})
98
 
99
  processed, total = batch_info['processed_links'], batch_info['total_links']
100
+
101
+ eta_sec = max(1, int((time.time() - batch_info["start_time"]) / processed * (total - processed)))
102
 
103
  try:
104
+ await bot.edit_message_text(
105
+ chat_id=batch_info["source_chat_id"],
106
+ message_id=batch_info["status_message_id"],
107
+ text=(
108
+ f"βš™οΈ Batch <code>{batch_id[:6]}</code> in progress... "
109
+ f"{processed}/{total} links processed.\n"
110
+ f"⏳ ETA: ~{eta_sec}s"
111
+ )
112
  )
113
  except TelegramBadRequest:
114
  pass
 
119
 
120
  TASK_QUEUE.task_done()
121
 
122
+ async def send_and_cache_file(chat_id: int, file_info: dict, caption: str) -> Message:
123
  file_path_or_id = file_info.get('file_id') or FSInputFile(file_info['path'], filename=file_info['name'])
124
  media_type = file_info.get('type')
125
  filename = file_info.get('name') or file_info.get('filename')
126
 
127
+ sent_message = await bot.send_document(chat_id, file_path_or_id, caption=caption)
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  if not file_info.get('cached') and sent_message:
130
+ file_id_to_cache = sent_message.document.file_id
131
  await db_utils.add_to_cache(
132
+ file_info['short_id'], file_id_to_cache, filename, 'document', file_info['size']
133
  )
134
 
135
  return sent_message
 
139
  if not batch:
140
  return
141
 
 
142
  successful_downloads = batch["successful_downloads"]
143
 
144
  try:
145
  if not successful_downloads:
146
  failed_links_text = "\n".join(
147
+ [f"- {x['link']} β†’ {x['error']}" for x in batch['failed_links']]
148
  )
149
+ await bot.edit_message_text(
150
+ chat_id=batch["source_chat_id"],
151
+ message_id=batch["status_message_id"],
152
+ text=(
153
+ f"❌ Batch <code>{batch_id[:6]}</code> failed. No files could be processed.\n"
154
+ f"<b>Details:</b>\n{failed_links_text}"
155
+ )
156
  )
157
  return
158
 
159
+ await bot.edit_message_text(
160
+ chat_id=batch["source_chat_id"],
161
+ message_id=batch["status_message_id"],
162
+ text=(
163
+ f"βœ… Batch <code>{batch_id[:6]}</code> downloaded. Sending {len(successful_downloads)} files..."
164
+ )
165
  )
166
 
167
+ # Forward original message if enabled
168
  if config.FORWARD_CHANNEL_ID:
169
  await bot.forward_message(
170
  config.FORWARD_CHANNEL_ID,
 
173
  )
174
  for item in successful_downloads:
175
  caption = f"`{item.get('name') or item.get('filename')}`"
176
+ await send_and_cache_file(config.FORWARD_CHANNEL_ID, item, caption)
177
  await asyncio.sleep(1)
178
 
179
  for item in successful_downloads:
180
  caption = f"`{item.get('name') or item.get('filename')}`"
181
+ await send_and_cache_file(batch["source_chat_id"], item, caption)
182
 
183
+ summary = f"βœ… Batch <code>{batch_id[:6]}</code> complete: {len(successful_downloads)} files sent."
184
  if batch["failed_links"]:
185
  summary += f"\n❌ {len(batch['failed_links'])} links failed."
186
 
187
+ await bot.edit_message_text(
188
+ chat_id=batch["source_chat_id"],
189
+ message_id=batch["status_message_id"],
190
+ text=summary
191
+ )
192
 
193
  except Exception as e:
194
  logger.error(f"Error during batch completion for {batch_id}: {e}", exc_info=True)
195
+ await bot.edit_message_text(
196
+ chat_id=batch["source_chat_id"],
197
+ message_id=batch["status_message_id"],
198
+ text=(
199
+ f"⚠️ A critical error occurred while sending files for batch <code>{batch_id[:6]}</code>."
200
+ )
201
  )
202
  finally:
203
  for item in successful_downloads:
204
  if not item.get('cached') and os.path.exists(item['path']):
205
  os.remove(item['path'])
 
 
206
 
207
  del BATCH_JOBS[batch_id]
208
 
 
211
  async def start_handler(message: Message):
212
  text = (
213
  "πŸ‘‹ <b>Welcome to the Terabox Downloader Bot!</b>\n\n"
214
+ "πŸ“₯ Send me any valid Terabox link and I will fetch the file and send it to you.\n\n"
215
+ f"πŸ“’ Please make sure you are a member of: @{config.FORCE_SUB_CHANNEL_USERNAME}\n\n"
216
+ "πŸš€ Supports batch links & auto-caching.\n"
217
+ "πŸ’Ύ Fast & lightweight.\n\n"
218
+ "βœ… <i>Just send your link below ⬇️</i>"
 
 
 
 
219
  )
220
+ await bot.send_message(
221
+ chat_id=message.chat.id,
222
+ text=text,
223
+ reply_to_message_id=message.message_id
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  )
 
225
 
226
  @dp.message(F.text | F.caption)
227
  async def message_handler(message: Message):
 
234
  message.from_user.first_name
235
  )
236
 
237
+ links = list(set(re.findall(r'https?://[^\s<>"\']+', message.text or message.caption or "")))
238
  terabox_links = [link for link in links if any(domain in link for domain in [
239
  "terabox.com", "teraboxapp.com", "terasharelink.com", "1024tera.com",
240
  "freeterabox.com", "4funbox.com", "box-links.com"
 
244
  return
245
 
246
  batch_id = str(uuid.uuid4())
247
+
248
+ status_msg = await bot.send_message(
249
+ chat_id=message.chat.id,
250
+ text=(
251
+ f"βœ… Found {len(terabox_links)} links. Queued as batch <code>{batch_id[:6]}</code>.\n"
252
+ f"⏳ Please wait..."
253
+ ),
254
  reply_to_message_id=message.message_id
255
  )
256
 
 
262
  "source_chat_id": message.chat.id,
263
  "source_user_id": message.from_user.id,
264
  "source_message_id": message.message_id,
265
+ "status_message_id": status_msg.message_id,
266
  "lock": asyncio.Lock(),
267
  "start_time": time.time()
268
  }
 
281
  dp.startup.register(on_startup)
282
  dp.message.register(message_handler)
283
  dp.message.register(start_handler, CommandStart())
 
284
  return dp, bot