CliRemote 1.7.1__tar.gz → 1.7.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {cliremote-1.7.1 → cliremote-1.7.3}/CliRemote.egg-info/PKG-INFO +1 -1
  2. {cliremote-1.7.1 → cliremote-1.7.3}/PKG-INFO +1 -1
  3. {cliremote-1.7.1 → cliremote-1.7.3}/pyproject.toml +1 -1
  4. {cliremote-1.7.1 → cliremote-1.7.3}/remote/account_manager.py +134 -133
  5. {cliremote-1.7.1 → cliremote-1.7.3}/remote/client_manager.py +10 -1
  6. {cliremote-1.7.1 → cliremote-1.7.3}/setup.py +1 -1
  7. {cliremote-1.7.1 → cliremote-1.7.3}/CliRemote.egg-info/SOURCES.txt +0 -0
  8. {cliremote-1.7.1 → cliremote-1.7.3}/CliRemote.egg-info/dependency_links.txt +0 -0
  9. {cliremote-1.7.1 → cliremote-1.7.3}/CliRemote.egg-info/requires.txt +0 -0
  10. {cliremote-1.7.1 → cliremote-1.7.3}/CliRemote.egg-info/top_level.txt +0 -0
  11. {cliremote-1.7.1 → cliremote-1.7.3}/LICENSE +0 -0
  12. {cliremote-1.7.1 → cliremote-1.7.3}/MANIFEST.in +0 -0
  13. {cliremote-1.7.1 → cliremote-1.7.3}/README.md +0 -0
  14. {cliremote-1.7.1 → cliremote-1.7.3}/remote/__init__.py +0 -0
  15. {cliremote-1.7.1 → cliremote-1.7.3}/remote/account_viewer.py +0 -0
  16. {cliremote-1.7.1 → cliremote-1.7.3}/remote/admin_manager.py +0 -0
  17. {cliremote-1.7.1 → cliremote-1.7.3}/remote/analytics_manager.py +0 -0
  18. {cliremote-1.7.1 → cliremote-1.7.3}/remote/batch_manager.py +0 -0
  19. {cliremote-1.7.1 → cliremote-1.7.3}/remote/block_manager.py +0 -0
  20. {cliremote-1.7.1 → cliremote-1.7.3}/remote/caption_manager.py +0 -0
  21. {cliremote-1.7.1 → cliremote-1.7.3}/remote/cleaner.py +0 -0
  22. {cliremote-1.7.1 → cliremote-1.7.3}/remote/client_picker.py +0 -0
  23. {cliremote-1.7.1 → cliremote-1.7.3}/remote/config.py +0 -0
  24. {cliremote-1.7.1 → cliremote-1.7.3}/remote/device_manager.py +0 -0
  25. {cliremote-1.7.1 → cliremote-1.7.3}/remote/file_sender.py +0 -0
  26. {cliremote-1.7.1 → cliremote-1.7.3}/remote/getcode_controller.py +0 -0
  27. {cliremote-1.7.1 → cliremote-1.7.3}/remote/health.py +0 -0
  28. {cliremote-1.7.1 → cliremote-1.7.3}/remote/help_menu.py +0 -0
  29. {cliremote-1.7.1 → cliremote-1.7.3}/remote/init.py +0 -0
  30. {cliremote-1.7.1 → cliremote-1.7.3}/remote/join_controller.py +0 -0
  31. {cliremote-1.7.1 → cliremote-1.7.3}/remote/joiner.py +0 -0
  32. {cliremote-1.7.1 → cliremote-1.7.3}/remote/leave_controller.py +0 -0
  33. {cliremote-1.7.1 → cliremote-1.7.3}/remote/lefter.py +0 -0
  34. {cliremote-1.7.1 → cliremote-1.7.3}/remote/mention_manager.py +0 -0
  35. {cliremote-1.7.1 → cliremote-1.7.3}/remote/precise_engine.py +0 -0
  36. {cliremote-1.7.1 → cliremote-1.7.3}/remote/profile_info.py +0 -0
  37. {cliremote-1.7.1 → cliremote-1.7.3}/remote/profile_media.py +0 -0
  38. {cliremote-1.7.1 → cliremote-1.7.3}/remote/profile_privacy.py +0 -0
  39. {cliremote-1.7.1 → cliremote-1.7.3}/remote/spammer.py +0 -0
  40. {cliremote-1.7.1 → cliremote-1.7.3}/remote/speed_manager.py +0 -0
  41. {cliremote-1.7.1 → cliremote-1.7.3}/remote/stop_manager.py +0 -0
  42. {cliremote-1.7.1 → cliremote-1.7.3}/remote/text_manager.py +0 -0
  43. {cliremote-1.7.1 → cliremote-1.7.3}/remote/username_manager.py +0 -0
  44. {cliremote-1.7.1 → cliremote-1.7.3}/remote/utils/__init__.py +0 -0
  45. {cliremote-1.7.1 → cliremote-1.7.3}/remote/utils/sqlite_utils.py +0 -0
  46. {cliremote-1.7.1 → cliremote-1.7.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: CliRemote
3
- Version: 1.7.1
3
+ Version: 1.7.3
4
4
  Summary: Remote client framework for Telegram automation using Pyrogram
5
5
  Home-page: https://github.com/MohammadAhmadi-R/CliRemote
6
6
  Author: MrAhmadiRad
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: CliRemote
3
- Version: 1.7.1
3
+ Version: 1.7.3
4
4
  Summary: Remote client framework for Telegram automation using Pyrogram
5
5
  Home-page: https://github.com/MohammadAhmadi-R/CliRemote
6
6
  Author: MrAhmadiRad
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "CliRemote"
7
- version = "1.7.1"
7
+ version = "1.7.3"
8
8
  description = "Remote client framework for Telegram automation using Pyrogram"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -245,149 +245,150 @@ def accounts() -> List[str]:
245
245
  def get_active_accounts() -> Set[str]:
246
246
  return set(accounts())
247
247
 
248
- # ============================================================
249
- # 🗑️ حذف اکانت
250
- # ============================================================
251
- async def delete_account_cmd(message) -> None:
252
- """
253
- حذف اکانت مشخص شده
254
- دستور: /del <phone_number>
255
- """
248
+
249
+ login = {}
250
+
251
+ # ==========================
252
+ # افزودن اکانت جدید
253
+ # ==========================
254
+ async def add_account_cmd(message, get_app_info):
256
255
  try:
257
- # استخراج شماره تلفن از پیام
258
- command_parts = message.text.split()
259
- if len(command_parts) < 2:
260
- await message.reply_text("⚠️ لطفاً شماره تلفن اکانت را وارد کنید:\n`/del 989123456789`")
256
+ parts = message.text.split(' ', 1)
257
+ if len(parts) < 2:
258
+ await message.reply('مثال: `add +989123456789`')
261
259
  return
262
260
 
263
- phone_number = command_parts[1].strip()
264
-
265
- # بررسی وجود اکانت
266
- if phone_number not in get_active_accounts():
267
- await message.reply_text(f"❌ اکانت `{phone_number}` یافت نشد.")
261
+ phone_number = parts[1].strip()
262
+ session_file = os.path.join(ACCOUNTS_FOLDER, f'{phone_number}.session')
263
+
264
+ if os.path.exists(session_file):
265
+ await message.reply('این اکانت وجود دارد!')
268
266
  return
269
267
 
270
- # توقف کلاینت اگر در حال اجراست
271
- if phone_number in client_pool:
272
- try:
273
- cli = client_pool[phone_number]
274
- if getattr(cli, "is_connected", False):
275
- await cli.stop()
276
- client_pool.pop(phone_number, None)
277
- client_locks.pop(phone_number, None)
278
- logger.info(f"{phone_number}: 📴 Client stopped for deletion.")
279
- except Exception as e:
280
- logger.warning(f"{phone_number}: ⚠️ Error stopping client before deletion - {e}")
281
-
282
- # حذف فایل‌های session
283
- session_deleted = False
284
- data_deleted = False
285
-
286
- session_files = [
287
- os.path.join(ACCOUNTS_FOLDER, f"{phone_number}.session"),
288
- os.path.join(ACCOUNTS_FOLDER, phone_number), # برای حالت‌های مختلف نام session
289
- f"{phone_number}.session", # در صورت وجود در مسیر جاری
290
- ]
291
-
292
- for session_file in session_files:
293
- if os.path.exists(session_file):
294
- try:
295
- os.remove(session_file)
296
- session_deleted = True
297
- logger.info(f"{phone_number}: 🗑️ Session file deleted → {session_file}")
298
- except Exception as e:
299
- logger.error(f"{phone_number}: ⚠️ Error deleting session file {session_file} - {e}")
300
-
301
- # حذف فایل داده‌های اکانت
302
- data_file = os.path.join(ACCOUNTS_DATA_FOLDER, f"{phone_number}.json")
303
- if os.path.exists(data_file):
304
- try:
305
- os.remove(data_file)
306
- data_deleted = True
307
- logger.info(f"{phone_number}: 🗑️ Account data deleted → {data_file}")
308
- except Exception as e:
309
- logger.error(f"{phone_number}: ⚠️ Error deleting account data {data_file} - {e}")
310
-
311
- # ارسال نتیجه به کاربر
312
- if session_deleted or data_deleted:
313
- await message.reply_text(f"✅ اکانت `{phone_number}` با موفقیت حذف شد.\n"
314
- f"• فایل session: {'✅' if session_deleted else '❌'}\n"
315
- f"• فایل داده: {'✅' if data_deleted else '❌'}")
316
- logger.info(f"{phone_number}: ✅ Account deletion completed.")
317
- else:
318
- await message.reply_text(f"⚠️ هیچ فایلی برای اکانت `{phone_number}` یافت نشد.")
319
-
268
+ global login
269
+ api = get_app_info()
270
+ if not api or len(api) < 2:
271
+ await message.reply('مشکل در API!')
272
+ return
273
+
274
+ login['id'] = int(api[1])
275
+ login['hash'] = api[0]
276
+ login['number'] = phone_number
277
+ login['api_data'] = {
278
+ 'api_id': api[1],
279
+ 'api_hash': api[0],
280
+ 'phone_number': phone_number,
281
+ 'session': phone_number,
282
+ '2fa_password': None
283
+ }
284
+
285
+ try:
286
+ login['client'] = Client(name=session_file.replace('.session', ''), api_id=login['id'], api_hash=login['hash'])
287
+ await login['client'].connect()
288
+ login['response'] = await login['client'].send_code(phone_number)
289
+ await message.reply(f'✅ کد تأیید به {phone_number} ارسال شد.\n`code 12345`')
290
+ except errors.BadRequest as e:
291
+ await message.reply(f'Bad request: {str(e)}')
292
+ except errors.FloodWait as e:
293
+ await message.reply(f'Flood wait: {e.value} sec')
294
+ except Exception as e:
295
+ await message.reply(f'Connection error: {str(e)}')
320
296
  except Exception as e:
321
- error_msg = f"💥 خطا در حذف اکانت: {str(e)}"
322
- logger.error(f"delete_account_cmd error: {traceback.format_exc()}")
323
- await message.reply_text(error_msg)
297
+ await message.reply(f'خطا: {str(e)}')
324
298
 
325
299
 
326
- # ============================================================
327
- # 🗑️ حذف تمامی اکانت‌ها
328
- # ============================================================
329
- async def delete_all_accounts_cmd(message) -> None:
330
- """
331
- حذف تمامی اکانت‌ها
332
- دستور: /delall
333
- """
300
+ # ==========================
301
+ # تأیید کد ورود
302
+ # ==========================
303
+ async def set_code_cmd(message):
304
+ global login
305
+ parts = message.text.split(' ', 1)
306
+ if len(parts) < 2:
307
+ await message.reply('`code 12345`')
308
+ return
309
+ code = parts[1].strip()
310
+
334
311
  try:
335
- # گرفتن تایید از کاربر
336
- confirm_text = "⚠️ **آیا مطمئن هستید که می‌خواهید تمامی اکانت‌ها را حذف کنید؟**\n\n"
337
- confirm_text += "این عمل غیرقابل بازگشت است!\n"
338
- confirm_text += "برای تایید، دستور زیر را ارسال کنید:\n`/delall confirm`"
339
-
340
- command_parts = message.text.split()
341
- if len(command_parts) < 2 or command_parts[1].strip().lower() != "confirm":
342
- await message.reply_text(confirm_text)
343
- return
312
+ await login['client'].sign_in(login['number'], login['response'].phone_code_hash, code)
313
+ await login['client'].disconnect()
314
+ save_account_data(login['number'], login['api_data'])
315
+ await message.reply(f" اکانت اضافه شد!\n├ شماره: {login['number']}")
316
+ login = {}
317
+ except errors.SessionPasswordNeeded:
318
+ await message.reply('🔒 لطفا رمز را با `pass your_password` بدهید')
319
+ except errors.BadRequest:
320
+ await message.reply('ورود با مشکل مواجه شد')
321
+ except Exception as e:
322
+ await message.reply(f'⚠️ خطا در ورود: {e}')
344
323
 
345
- # توقف تمام کلاینت‌ها
346
- await stop_all_clients()
347
324
 
348
- # لیست تمام اکانت‌ها
349
- all_accounts = get_active_accounts()
350
- deleted_sessions = 0
351
- deleted_data_files = 0
352
-
353
- # حذف تمام فایل‌های session
354
- if os.path.exists(ACCOUNTS_FOLDER):
355
- for filename in os.listdir(ACCOUNTS_FOLDER):
356
- if filename.endswith('.session'):
357
- try:
358
- file_path = os.path.join(ACCOUNTS_FOLDER, filename)
359
- os.remove(file_path)
360
- deleted_sessions += 1
361
- logger.info(f"🗑️ Session file deleted → {filename}")
362
- except Exception as e:
363
- logger.error(f"⚠️ Error deleting session file {filename} - {e}")
364
-
365
- # حذف تمام فایل‌های داده
366
- if os.path.exists(ACCOUNTS_DATA_FOLDER):
367
- for filename in os.listdir(ACCOUNTS_DATA_FOLDER):
368
- if filename.endswith('.json'):
369
- try:
370
- file_path = os.path.join(ACCOUNTS_DATA_FOLDER, filename)
371
- os.remove(file_path)
372
- deleted_data_files += 1
373
- logger.info(f"🗑️ Account data deleted → {filename}")
374
- except Exception as e:
375
- logger.error(f"⚠️ Error deleting account data {filename} - {e}")
376
-
377
- # پاک کردن کش داخلی
378
- client_pool.clear()
379
- client_locks.clear()
380
-
381
- # ارسال نتیجه به کاربر
382
- result_msg = (f"✅ **حذف کامل اکانت‌ها انجام شد**\n\n"
383
- f"• تعداد فایل‌های session حذف شده: `{deleted_sessions}`\n"
384
- f"• تعداد فایل‌های داده حذف شده: `{deleted_data_files}`\n"
385
- f"• تعداد اکانت‌های شناسایی شده: `{len(all_accounts)}`")
386
-
387
- await message.reply_text(result_msg)
388
- logger.info(f"🎯 All accounts deletion completed: {deleted_sessions} sessions, {deleted_data_files} data files")
325
+ # ==========================
326
+ # افزودن رمز دومرحله‌ای
327
+ # ==========================
328
+ async def set_2fa_cmd(message):
329
+ global login
330
+ parts = message.text.split(' ', 1)
331
+ if len(parts) < 2:
332
+ await message.reply('`pass my_password`')
333
+ return
334
+ password = parts[1].strip()
335
+ try:
336
+ await login['client'].check_password(password)
337
+ login['api_data']['2fa_password'] = password
338
+ save_account_data(login['number'], login['api_data'])
339
+ await message.reply(f"✅ اکانت با موفقیت اضافه شد!\n├ شماره: {login['number']}")
340
+ await login['client'].disconnect()
341
+ login = {}
342
+ except errors.BadRequest:
343
+ await message.reply('رمز اشتباه است!')
344
+ except Exception as e:
345
+ await message.reply(f'⚠️ خطا در ثبت پسورد: {e}')
346
+
389
347
 
348
+ # ==========================
349
+ # حذف یک اکانت خاص
350
+ # ==========================
351
+ def remove_client_from_pool(phone_number: str):
352
+ cli = client_pool.get(phone_number)
353
+ if cli:
354
+ try:
355
+ asyncio.create_task(cli.stop())
356
+ except:
357
+ pass
358
+ client_pool.pop(phone_number, None)
359
+ client_locks.pop(phone_number, None)
360
+
361
+
362
+ async def delete_account_cmd(message):
363
+ try:
364
+ phone_number = message.text.split()[1]
365
+ main_path = f'{ACCOUNTS_FOLDER}/{phone_number}.session'
366
+ remove_client_from_pool(phone_number)
367
+ if os.path.isfile(main_path):
368
+ os.unlink(main_path)
369
+ await message.reply('<b>Account deleted successfully.</b>')
370
+ else:
371
+ await message.reply('<b>Account not found in database.</b>')
372
+ except IndexError:
373
+ await message.reply('Please enter phone number')
374
+ except Exception as e:
375
+ await message.reply(f'<b>Error deleting account: {str(e)}</b>')
376
+
377
+
378
+ # ==========================
379
+ # حذف تمام اکانت‌ها
380
+ # ==========================
381
+ async def delete_all_accounts_cmd(message):
382
+ try:
383
+ accountss = accounts()
384
+ count = len(accountss)
385
+ await stop_all_clients()
386
+ for session in accountss:
387
+ main_path = f'{ACCOUNTS_FOLDER}/{session}.session'
388
+ try:
389
+ os.unlink(main_path)
390
+ except Exception:
391
+ pass
392
+ await message.reply(f'<b>{count} accounts deleted.</b>')
390
393
  except Exception as e:
391
- error_msg = f"💥 خطا در حذف کامل اکانت‌ها: {str(e)}"
392
- logger.error(f"delete_all_accounts_cmd error: {traceback.format_exc()}")
393
- await message.reply_text(error_msg)
394
+ await message.reply(f'<b>Error deleting all accounts: {str(e)}</b>')
@@ -278,4 +278,13 @@ async def get_any_client(message=None) -> Optional[object]:
278
278
  logger.warning("get_any_client: failed start %s: %s: %s", phone, type(e).__name__, e)
279
279
 
280
280
  logger.error("get_any_client: could not get any client")
281
- return None
281
+ return None
282
+
283
+ def get_app_info() -> List[str]:
284
+ try:
285
+ apis = {1: ['debac98afc137d3a82df5454f345bf02', 23523087], 2: ['b86bbf4b700b4e922fff2c05b3b8985f', 17221354], 3: ['2345124333c84e4f72441606a08e882c', 21831682], 4: ['1ebc2808ef58a95bc796590151c3e0d5', 14742007], 5: ['b8eff20a7e8adcdaa3daa3bc789a5b41', 12176206]}
286
+ return apis[random.randint(1, 5)]
287
+ except Exception as e:
288
+ logger.error(f'Error reading app info: {e}')
289
+ return []
290
+
@@ -5,7 +5,7 @@ with open("README.md", encoding="utf-8") as f:
5
5
 
6
6
  setup(
7
7
  name="CliRemote",
8
- version="1.7.1",
8
+ version="1.7.3",
9
9
  author="MrAhmadiRad",
10
10
  author_email="mohammadahmadirad69@gmail.com",
11
11
  description="A precise, async-safe, Telegram automation core (Python 3.8+)",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes