CliRemote 1.7.10__tar.gz → 1.7.13__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 (47) hide show
  1. {cliremote-1.7.10 → cliremote-1.7.13}/CliRemote.egg-info/PKG-INFO +1 -1
  2. {cliremote-1.7.10 → cliremote-1.7.13}/PKG-INFO +1 -1
  3. {cliremote-1.7.10 → cliremote-1.7.13}/pyproject.toml +1 -1
  4. cliremote-1.7.13/remote/admin_manager.py +187 -0
  5. {cliremote-1.7.10 → cliremote-1.7.13}/setup.py +1 -1
  6. cliremote-1.7.10/remote/admin_manager.py +0 -125
  7. {cliremote-1.7.10 → cliremote-1.7.13}/CliRemote.egg-info/SOURCES.txt +0 -0
  8. {cliremote-1.7.10 → cliremote-1.7.13}/CliRemote.egg-info/dependency_links.txt +0 -0
  9. {cliremote-1.7.10 → cliremote-1.7.13}/CliRemote.egg-info/requires.txt +0 -0
  10. {cliremote-1.7.10 → cliremote-1.7.13}/CliRemote.egg-info/top_level.txt +0 -0
  11. {cliremote-1.7.10 → cliremote-1.7.13}/LICENSE +0 -0
  12. {cliremote-1.7.10 → cliremote-1.7.13}/MANIFEST.in +0 -0
  13. {cliremote-1.7.10 → cliremote-1.7.13}/README.md +0 -0
  14. {cliremote-1.7.10 → cliremote-1.7.13}/remote/__init__.py +0 -0
  15. {cliremote-1.7.10 → cliremote-1.7.13}/remote/account_manager.py +0 -0
  16. {cliremote-1.7.10 → cliremote-1.7.13}/remote/account_viewer.py +0 -0
  17. {cliremote-1.7.10 → cliremote-1.7.13}/remote/analytics_manager.py +0 -0
  18. {cliremote-1.7.10 → cliremote-1.7.13}/remote/batch_manager.py +0 -0
  19. {cliremote-1.7.10 → cliremote-1.7.13}/remote/block_manager.py +0 -0
  20. {cliremote-1.7.10 → cliremote-1.7.13}/remote/caption_manager.py +0 -0
  21. {cliremote-1.7.10 → cliremote-1.7.13}/remote/cleaner.py +0 -0
  22. {cliremote-1.7.10 → cliremote-1.7.13}/remote/client_manager.py +0 -0
  23. {cliremote-1.7.10 → cliremote-1.7.13}/remote/client_picker.py +0 -0
  24. {cliremote-1.7.10 → cliremote-1.7.13}/remote/config.py +0 -0
  25. {cliremote-1.7.10 → cliremote-1.7.13}/remote/device_manager.py +0 -0
  26. {cliremote-1.7.10 → cliremote-1.7.13}/remote/file_sender.py +0 -0
  27. {cliremote-1.7.10 → cliremote-1.7.13}/remote/getcode_controller.py +0 -0
  28. {cliremote-1.7.10 → cliremote-1.7.13}/remote/health.py +0 -0
  29. {cliremote-1.7.10 → cliremote-1.7.13}/remote/help_menu.py +0 -0
  30. {cliremote-1.7.10 → cliremote-1.7.13}/remote/init.py +0 -0
  31. {cliremote-1.7.10 → cliremote-1.7.13}/remote/join_controller.py +0 -0
  32. {cliremote-1.7.10 → cliremote-1.7.13}/remote/joiner.py +0 -0
  33. {cliremote-1.7.10 → cliremote-1.7.13}/remote/leave_controller.py +0 -0
  34. {cliremote-1.7.10 → cliremote-1.7.13}/remote/lefter.py +0 -0
  35. {cliremote-1.7.10 → cliremote-1.7.13}/remote/mention_manager.py +0 -0
  36. {cliremote-1.7.10 → cliremote-1.7.13}/remote/precise_engine.py +0 -0
  37. {cliremote-1.7.10 → cliremote-1.7.13}/remote/profile_info.py +0 -0
  38. {cliremote-1.7.10 → cliremote-1.7.13}/remote/profile_media.py +0 -0
  39. {cliremote-1.7.10 → cliremote-1.7.13}/remote/profile_privacy.py +0 -0
  40. {cliremote-1.7.10 → cliremote-1.7.13}/remote/spammer.py +0 -0
  41. {cliremote-1.7.10 → cliremote-1.7.13}/remote/speed_manager.py +0 -0
  42. {cliremote-1.7.10 → cliremote-1.7.13}/remote/stop_manager.py +0 -0
  43. {cliremote-1.7.10 → cliremote-1.7.13}/remote/text_manager.py +0 -0
  44. {cliremote-1.7.10 → cliremote-1.7.13}/remote/username_manager.py +0 -0
  45. {cliremote-1.7.10 → cliremote-1.7.13}/remote/utils/__init__.py +0 -0
  46. {cliremote-1.7.10 → cliremote-1.7.13}/remote/utils/sqlite_utils.py +0 -0
  47. {cliremote-1.7.10 → cliremote-1.7.13}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: CliRemote
3
- Version: 1.7.10
3
+ Version: 1.7.13
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.10
3
+ Version: 1.7.13
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.10"
7
+ version = "1.7.13"
8
8
  description = "Remote client framework for Telegram automation using Pyrogram"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -0,0 +1,187 @@
1
+ # remote/admin_manager.py
2
+ import json
3
+ import os
4
+ import sys
5
+ import logging
6
+ from pathlib import Path
7
+ from pyrogram import filters
8
+ from .config import OWNER_ID
9
+
10
+ # =============================
11
+ # تنظیم logger فایل
12
+ # =============================
13
+
14
+ def _project_root() -> Path:
15
+ """ریشه پروژه = پوشه‌ای که main.py داخلش اجرا شده. در صورت عدم دسترسی، از cwd استفاده می‌شود."""
16
+ try:
17
+ main_file = Path(sys.modules["__main__"].__file__).resolve()
18
+ return main_file.parent
19
+ except Exception:
20
+ return Path(os.getcwd()).resolve()
21
+
22
+ _PROJECT_ROOT = _project_root()
23
+ _LOG_DIR = _PROJECT_ROOT / "logs"
24
+ _LOG_DIR.mkdir(parents=True, exist_ok=True)
25
+ _LOG_PATH = _LOG_DIR / "admins_log.txt"
26
+
27
+ # logger اختصاصی این ماژول
28
+ logger = logging.getLogger("remote.admin_manager")
29
+ logger.setLevel(logging.DEBUG)
30
+
31
+ # جلوگیری از افزودن چندباره‌ی هندلر هنگام ریلود
32
+ if not any(isinstance(h, logging.FileHandler) and getattr(h, "_admin_log", False) for h in logger.handlers):
33
+ fh = logging.FileHandler(_LOG_PATH, encoding="utf-8")
34
+ fh._admin_log = True # پرچم داخلی برای تشخیص
35
+ fh.setLevel(logging.DEBUG)
36
+ fmt = logging.Formatter(
37
+ fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
38
+ datefmt="%Y-%m-%d %H:%M:%S"
39
+ )
40
+ fh.setFormatter(fmt)
41
+ logger.addHandler(fh)
42
+
43
+ logger.debug(f"Admin manager initialized. Log path: {_LOG_PATH}")
44
+
45
+ # =============================
46
+ # تنظیمات فایل ادمین‌ها
47
+ # =============================
48
+
49
+ ADMINS_FILE = "admins.json" # اگر می‌خواهی کنار main.py باشد: ( _PROJECT_ROOT / "admins.json" ).as_posix()
50
+
51
+ def load_admins() -> list[int]:
52
+ """
53
+ بارگذاری لیست ادمین‌ها از فایل.
54
+ همیشه OWNER_ID را هم به لیست اضافه می‌کند.
55
+ """
56
+ logger.debug(f"Loading admins from file: {ADMINS_FILE} | OWNER_ID: {OWNER_ID}")
57
+ s = set(OWNER_ID)
58
+ try:
59
+ if os.path.exists(ADMINS_FILE):
60
+ with open(ADMINS_FILE, "r", encoding="utf-8") as f:
61
+ data = json.load(f)
62
+ logger.info(f"admins.json loaded. Raw: {data!r}")
63
+ if isinstance(data, list):
64
+ for v in data:
65
+ try:
66
+ s.add(int(v))
67
+ except Exception as conv_err:
68
+ logger.warning(f"Skip invalid admin id in file: {v!r} | err={conv_err}")
69
+ else:
70
+ logger.info(f"admins.json not found at: {os.path.abspath(ADMINS_FILE)}")
71
+ except Exception as e:
72
+ logger.warning(f"Error loading admins: {e}", exc_info=True)
73
+
74
+ result = sorted(s)
75
+ logger.debug(f"Effective ADMINS after merge with OWNER_ID: {result}")
76
+ return result
77
+
78
+
79
+ def save_admins():
80
+ """
81
+ ذخیره‌ی ادمین‌ها در فایل.
82
+ """
83
+ try:
84
+ # نکته: در این طراحی، ADMINS شامل OWNER_ID هم می‌تواند باشد؛ مشکلی نیست
85
+ logger.debug(f"Saving ADMINS to file: {ADMINS_FILE} | Data: {ADMINS}")
86
+ with open(ADMINS_FILE, "w", encoding="utf-8") as f:
87
+ json.dump(list(ADMINS), f, ensure_ascii=False, indent=2)
88
+ logger.info(f"Admins saved to {os.path.abspath(ADMINS_FILE)}")
89
+ except Exception as e:
90
+ logger.error(f"Error saving admins: {e}", exc_info=True)
91
+
92
+
93
+ ADMINS = load_admins()
94
+ logger.info(f"Loaded admins at import time: {ADMINS}")
95
+
96
+ # فیلترهای دسترسی برای Pyrogram
97
+ admin_filter = filters.create(
98
+ lambda _, __, m: bool(getattr(m, "from_user", None)) and int(m.from_user.id) in ADMINS
99
+ )
100
+ owner_filter = filters.create(
101
+ lambda _, __, m: bool(getattr(m, "from_user", None)) and int(m.from_user.id) in OWNER_ID
102
+ )
103
+
104
+ # =============================
105
+ # فرمان‌های مدیریتی
106
+ # =============================
107
+
108
+ async def add_admin_cmd(message):
109
+ try:
110
+ uid_display = getattr(getattr(message, "from_user", None), "id", None)
111
+ logger.debug(f"add_admin_cmd triggered by user_id={uid_display} | text={message.text!r}")
112
+
113
+ parts = (message.text or "").split()
114
+ if len(parts) < 2:
115
+ logger.debug("add_admin_cmd: missing argument")
116
+ await message.reply("مثال: addadmin 123456789")
117
+ return
118
+
119
+ uid = int(parts[1])
120
+ logger.debug(f"add_admin_cmd: parsed target uid={uid}")
121
+
122
+ if uid in OWNER_ID:
123
+ logger.info(f"add_admin_cmd: uid={uid} is OWNER; skip append")
124
+ await message.reply("ادمین اصلی از قبل وجود دارد")
125
+ return
126
+
127
+ if uid not in ADMINS:
128
+ ADMINS.append(uid)
129
+ logger.info(f"Admin appended: {uid} | New ADMINS={sorted(ADMINS)}")
130
+ save_admins()
131
+ await message.reply(f"ادمین جدید اضافه شد: {uid}")
132
+ else:
133
+ logger.info(f"add_admin_cmd: uid={uid} already in ADMINS")
134
+ await message.reply("قبلاً ادمین بود")
135
+ except Exception as e:
136
+ logger.error(f"add_admin_cmd error: {e}", exc_info=True)
137
+ await message.reply(f"خطا: {e}")
138
+
139
+
140
+ async def del_admin_cmd(message):
141
+ try:
142
+ uid_display = getattr(getattr(message, "from_user", None), "id", None)
143
+ logger.debug(f"del_admin_cmd triggered by user_id={uid_display} | text={message.text!r}")
144
+
145
+ parts = (message.text or "").split()
146
+ if len(parts) < 2:
147
+ logger.debug("del_admin_cmd: missing argument")
148
+ await message.reply("مثال: deladmin 123456789")
149
+ return
150
+
151
+ uid = int(parts[1])
152
+ logger.debug(f"del_admin_cmd: parsed target uid={uid}")
153
+
154
+ if uid in OWNER_ID:
155
+ logger.info(f"del_admin_cmd: attempt to remove OWNER uid={uid} blocked")
156
+ await message.reply("❌ امکان حذف ادمین اصلی وجود ندارد")
157
+ return
158
+
159
+ if uid in ADMINS:
160
+ ADMINS.remove(uid)
161
+ logger.info(f"Admin removed: {uid} | New ADMINS={sorted(ADMINS)}")
162
+ save_admins()
163
+ await message.reply(f"ادمین حذف شد: {uid}")
164
+ else:
165
+ logger.info(f"del_admin_cmd: uid={uid} not in ADMINS")
166
+ await message.reply("کاربر ادمین نیست")
167
+ except Exception as e:
168
+ logger.error(f"del_admin_cmd error: {e}", exc_info=True)
169
+ await message.reply(f"خطا: {e}")
170
+
171
+
172
+ async def list_admins_cmd(message):
173
+ try:
174
+ uid_display = getattr(getattr(message, "from_user", None), "id", None)
175
+ logger.debug(f"list_admins_cmd triggered by user_id={uid_display}")
176
+
177
+ if not ADMINS:
178
+ logger.info("list_admins_cmd: ADMINS is empty")
179
+ await message.reply("لیست ادمین‌ها خالی است.")
180
+ return
181
+
182
+ text = "👑 <b>ADMINS:</b>\n" + "\n".join([str(x) for x in sorted(ADMINS)])
183
+ logger.debug(f"list_admins_cmd: respond with {len(ADMINS)} admins")
184
+ await message.reply(text)
185
+ except Exception as e:
186
+ logger.error(f"list_admins_cmd error: {e}", exc_info=True)
187
+ await message.reply(f"خطا: {e}")
@@ -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.10",
8
+ version="1.7.13",
9
9
  author="MrAhmadiRad",
10
10
  author_email="mohammadahmadirad69@gmail.com",
11
11
  description="A precise, async-safe, Telegram automation core (Python 3.8+)",
@@ -1,125 +0,0 @@
1
- # remote/admin_manager.py
2
- import json, os, sys, logging
3
- from pathlib import Path
4
- from pyrogram import filters
5
- from .config import OWNER_ID
6
-
7
- logger = logging.getLogger(__name__)
8
-
9
- def _project_root() -> Path:
10
- """
11
- ریشه پروژه = پوشه‌ای که main.py داخلش اجرا شده.
12
- """
13
- try:
14
- main_file = Path(sys.modules["__main__"].__file__).resolve()
15
- return main_file.parent
16
- except Exception:
17
- # fallback: اگر به هر دلیل __main__.__file__ نبود
18
- return Path(os.getcwd()).resolve()
19
-
20
- PROJECT_ROOT = _project_root()
21
- ADMINS_FILE = PROJECT_ROOT / "admins.json" # ✅ کنار main.py
22
-
23
- def _load_admins_from_file() -> list[int]:
24
- try:
25
- if ADMINS_FILE.exists():
26
- with ADMINS_FILE.open("r", encoding="utf-8") as f:
27
- data = json.load(f)
28
- if isinstance(data, list):
29
- out = []
30
- for v in data:
31
- try:
32
- out.append(int(v))
33
- except Exception:
34
- logger.warning(f"Bad admin id in file: {v!r}")
35
- return out
36
- except Exception as e:
37
- logger.warning(f"Error loading admins from {ADMINS_FILE}: {e}")
38
- return []
39
-
40
- # لیست ادمین‌های موثر (فایل + Owner)
41
- ADMINS: list[int] = []
42
-
43
- def reload_admins():
44
- """فایل را می‌خواند و با OWNER_ID ادغام می‌کند؛ نتیجه در ADMINS."""
45
- file_admins = _load_admins_from_file()
46
- s = set(file_admins) | set(OWNER_ID)
47
- global ADMINS
48
- ADMINS = sorted(s)
49
- logger.info(f"Loaded admins ({ADMINS_FILE}): {ADMINS}")
50
-
51
- def save_admins():
52
- """
53
- ذخیره در فایل کنار main.py.
54
- فقط ادمین‌های غیر-Owner را داخل فایل نگه می‌داریم (Ownerها از config می‌آیند).
55
- """
56
- try:
57
- file_list = [x for x in ADMINS if x not in set(OWNER_ID)]
58
- with ADMINS_FILE.open("w", encoding="utf-8") as f:
59
- json.dump(file_list, f, ensure_ascii=False, indent=2)
60
- logger.info(f"Saved admins to {ADMINS_FILE}: {file_list}")
61
- except Exception as e:
62
- logger.error(f"Error saving admins: {e}")
63
-
64
- # فیلترهای دسترسی
65
- admin_filter = filters.create(
66
- lambda _, __, m: bool(getattr(m, "from_user", None)) and int(m.from_user.id) in ADMINS
67
- )
68
- owner_filter = filters.create(
69
- lambda _, __, m: bool(getattr(m, "from_user", None)) and int(m.from_user.id) in OWNER_ID
70
- )
71
-
72
- # ===== فرمان‌ها =====
73
- async def add_admin_cmd(message):
74
- try:
75
- parts = (message.text or "").split()
76
- if len(parts) < 2:
77
- await message.reply("مثال: /addadmin 123456789")
78
- return
79
- uid = int(parts[1])
80
- if uid in OWNER_ID:
81
- await message.reply("ادمین اصلی از قبل وجود دارد")
82
- return
83
- if uid not in ADMINS:
84
- ADMINS.append(uid)
85
- ADMINS[:] = sorted(set(ADMINS) | set(OWNER_ID))
86
- save_admins()
87
- await message.reply(f"ادمین جدید اضافه شد: <code>{uid}</code>")
88
- logger.info(f"Admin added: {uid}")
89
- else:
90
- await message.reply("قبلاً ادمین بود")
91
- except Exception as e:
92
- logger.error(f"add_admin_cmd error: {e}", exc_info=True)
93
- await message.reply(f"خطا: {e}")
94
-
95
- async def del_admin_cmd(message):
96
- try:
97
- parts = (message.text or "").split()
98
- if len(parts) < 2:
99
- await message.reply("مثال: /deladmin 123456789")
100
- return
101
- uid = int(parts[1])
102
- if uid in OWNER_ID:
103
- await message.reply("❌ امکان حذف ادمین اصلی وجود ندارد")
104
- return
105
- if uid in ADMINS:
106
- ADMINS.remove(uid)
107
- save_admins()
108
- await message.reply(f"ادمین حذف شد: <code>{uid}</code>")
109
- logger.info(f"Admin removed: {uid}")
110
- else:
111
- await message.reply("کاربر ادمین نیست")
112
- except Exception as e:
113
- logger.error(f"del_admin_cmd error: {e}", exc_info=True)
114
- await message.reply(f"خطا: {e}")
115
-
116
- async def list_admins_cmd(message):
117
- try:
118
- if not ADMINS:
119
- await message.reply("لیست ادمین‌ها خالی است.")
120
- return
121
- text = "👑 <b>ADMINS:</b>\n" + "\n".join([f"<code>{x}</code>" for x in ADMINS])
122
- await message.reply(text, disable_web_page_preview=True)
123
- except Exception as e:
124
- logger.error(f"list_admins_cmd error: {e}", exc_info=True)
125
- await message.reply(f"خطا: {e}")
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