CliRemote 1.7.14__py3-none-any.whl → 1.8.3__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: CliRemote
3
- Version: 1.7.14
3
+ Version: 1.8.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,4 +1,4 @@
1
- cliremote-1.7.14.dist-info/licenses/LICENSE,sha256=O-0zMbcEi6wXz1DiSdVgzMlQjJcNqNe5KDv08uYzqR0,1055
1
+ cliremote-1.8.3.dist-info/licenses/LICENSE,sha256=O-0zMbcEi6wXz1DiSdVgzMlQjJcNqNe5KDv08uYzqR0,1055
2
2
  remote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  remote/account_manager.py,sha256=TepnGIoE2hU-j_NmU5ByoS-JrboE0w3A1bYmQoQX5h8,15176
4
4
  remote/account_viewer.py,sha256=j46KSjbgrBmBi7UxFeJ5tCwHIe0QvCvphkirGIbB2oo,5192
@@ -22,18 +22,18 @@ remote/joiner.py,sha256=CXTQ-l6CysqZSkYP1GUV1LM1qlh5wD4jBj_og_FVW1I,7773
22
22
  remote/leave_controller.py,sha256=TIShgxCMiKyBn9ZdQZYm6Kf89GgDaoPCRH7pxqq9FC8,1167
23
23
  remote/lefter.py,sha256=jxZmkl3NIe1c-WeVES8WBX21hW-eocfxfePvxddHdi0,6090
24
24
  remote/mention_manager.py,sha256=I75ezmVZM0lYrgk8OQ2p-VETLLwM5FiW83tiBgbQ1CY,3257
25
- remote/precise_engine.py,sha256=39FjbHPirH_IXnkbvlEiyu7O0636_0btlRwIS8oiKxA,1562
25
+ remote/precise_engine.py,sha256=3LhyDcITIfscCgYTwWyJ-CTAWylrufqHeURR1FAwKvA,641
26
26
  remote/profile_info.py,sha256=Us5mz6sdV_5-5wRx6F3S6rtj2m6vaP_HOrCBLgHXpD4,1992
27
27
  remote/profile_media.py,sha256=lD_uIb0U3jeH_dpa4SNbF0wr1DQiQ5OfbTCOubcm9Us,2264
28
28
  remote/profile_privacy.py,sha256=LrRZbbqhaYdl4JzBMJrl-D-N8y1AG2LR1DDzv-tmlV0,2298
29
- remote/spammer.py,sha256=ywrqWyxsVfVVLaryPhgdOTT8IQVB2EO3eA3gmYQ3bvw,13176
29
+ remote/spammer.py,sha256=lKALyfX3hInsJmR6qVb5xxAdM-GkW2s42e6gqTyIo1k,11820
30
30
  remote/speed_manager.py,sha256=fIWSQAP9qW8AHZtMZq0MrC4_nvxcTFU1SBU75kpRzB8,1115
31
31
  remote/stop_manager.py,sha256=UXzKJTblEyQqCjp7fenvQ51Q96Unx05WeOiuFMdj25M,1151
32
32
  remote/text_manager.py,sha256=C2wNSXPSCDu8NSD3RsfbKmUQMWOYd1B5N4tzy-Jsriw,2195
33
33
  remote/username_manager.py,sha256=nMNdke-2FIv86xR1Y6rR-43oUoQu_3Khw8wEo54noXI,3388
34
34
  remote/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  remote/utils/sqlite_utils.py,sha256=5i0oUXsBgKC_8qHZPJ-Gyhp9D1TwqKHVvuZRIhKpS6w,1260
36
- cliremote-1.7.14.dist-info/METADATA,sha256=byGeVYjwKOlm5Qm8bdk1hLNfvv-7YymdLxgV27YTndA,1203
37
- cliremote-1.7.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
- cliremote-1.7.14.dist-info/top_level.txt,sha256=yBZidJ6zCix_a2ubGlYaewvlzBFXWbckQt20dudxJ1E,7
39
- cliremote-1.7.14.dist-info/RECORD,,
36
+ cliremote-1.8.3.dist-info/METADATA,sha256=OsHKIAwSjhPU2NGE8vUv8FuKc9xNe4tUwTadfrJk_z4,1202
37
+ cliremote-1.8.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
+ cliremote-1.8.3.dist-info/top_level.txt,sha256=yBZidJ6zCix_a2ubGlYaewvlzBFXWbckQt20dudxJ1E,7
39
+ cliremote-1.8.3.dist-info/RECORD,,
remote/precise_engine.py CHANGED
@@ -1,45 +1,19 @@
1
1
  # antispam_core/precise_engine.py
2
- import asyncio
3
- import time
2
+ import asyncio, time
4
3
 
5
4
  class PreciseTicker:
6
- """
7
- A drift-free ticker.
8
- Usage:
9
- ticker = PreciseTicker(interval=1.0)
10
- while running:
11
- # do work
12
- await ticker.sleep()
13
- Behavior:
14
- - Ensures interval spacing between wakes without accumulating drift.
15
- - If the work took longer than the interval, it schedules next wake as now + interval
16
- (so it doesn't try to "catch up" by sleeping negative amounts).
17
- - On first use, it sets the baseline relative to time.perf_counter().
18
- """
19
5
  def __init__(self, interval: float):
20
- if interval <= 0:
21
- raise ValueError("interval must be > 0")
22
6
  self.interval = float(interval)
23
- self.next_tick = None
7
+ self.next_tick = time.perf_counter()
24
8
 
25
9
  async def sleep(self):
26
- now = time.perf_counter()
27
- if self.next_tick is None:
28
- # first tick: schedule next at now + interval
29
- self.next_tick = now + self.interval
30
-
31
- delay = self.next_tick - now
32
-
10
+ """خواب دقیق بدون drift در زمان"""
11
+ self.next_tick += self.interval
12
+ delay = self.next_tick - time.perf_counter()
33
13
  if delay > 0:
34
- # normal case: wait remaining time
35
14
  await asyncio.sleep(delay)
36
- # advance to next slot
37
- self.next_tick += self.interval
38
15
  else:
39
- # work took longer than interval; reset baseline to now + interval
40
- self.next_tick = now + self.interval
41
- # don't sleep now (we are already late)
16
+ self.next_tick = time.perf_counter() # ریست در صورت عقب افتادن
42
17
 
43
18
  def reset(self):
44
- """Reset baseline so next sleep schedules from current time."""
45
- self.next_tick = None
19
+ self.next_tick = time.perf_counter()
remote/spammer.py CHANGED
@@ -30,7 +30,7 @@ if not any(
30
30
  # ============================================================
31
31
  # ✅ پیکربندی ایمن و پارامترهای پیش‌فرض
32
32
  # ============================================================
33
- MAX_RETRIES = 2 # تلاش مجدد حداکثر برای هر ارسال
33
+ MAX_RETRIES = 3 # تلاش مجدد حداکثر برای هر ارسال
34
34
  BASE_BACKOFF = 1.5 # ضریب بک‌آف برای retries (s)
35
35
  FLOOD_COOLDOWN_CAP = 3600 # حداکثر زمان cooldown برای FloodWait (s)
36
36
 
@@ -45,23 +45,6 @@ if not hasattr(client_manager, "client_locks"):
45
45
  # ============================================================
46
46
  # 🧰 توابع کمکی
47
47
  # ============================================================
48
- def is_in_cooldown(phone: str) -> bool:
49
- ts = _account_cooldowns.get(phone)
50
- if not ts:
51
- return False
52
- return ts > asyncio.get_event_loop().time()
53
-
54
- def set_cooldown(phone: str, seconds: float):
55
- resume = asyncio.get_event_loop().time() + seconds
56
- _account_cooldowns[phone] = resume
57
- logger.info(f"{phone}: ⏳ Put on cooldown for {seconds:.1f}s (resume @ {resume:.1f})")
58
-
59
- def clear_expired_cooldowns():
60
- now = asyncio.get_event_loop().time()
61
- expired = [p for p, t in _account_cooldowns.items() if t <= now]
62
- for p in expired:
63
- _account_cooldowns.pop(p, None)
64
- logger.info(f"{p}: ✅ Cooldown expired")
65
48
 
66
49
  async def _attempt_send(cli, acc_phone: str, target: str, text: str):
67
50
  """Try to send once, raising exceptions up to caller to handle specialized behavior."""
@@ -82,10 +65,6 @@ async def safe_send(acc_phone: str, spam_config: dict, text: str, remove_client_
82
65
  بازگشت: True اگر ارسال موفق باشد، False در غیر این صورت.
83
66
  """
84
67
  try:
85
- # اگر اکانت در cooldown است، زود بازگردان False (بدون تلاش)
86
- if is_in_cooldown(acc_phone):
87
- logger.info(f"{acc_phone}: ⚠️ Skipping send because account is in cooldown.")
88
- return False
89
68
 
90
69
  cli = await client_manager.get_or_start_client(acc_phone)
91
70
  if not cli:
@@ -122,8 +101,7 @@ async def safe_send(acc_phone: str, spam_config: dict, text: str, remove_client_
122
101
  wait = e.value if hasattr(e, "value") else getattr(e, "x", 0)
123
102
  # حداقل و حداکثر را منطقی حفظ کن
124
103
  wait = max(1, min(wait, FLOOD_COOLDOWN_CAP))
125
- logger.warning(f"{acc_phone}: ⏰ FloodWait {wait}s (code:{getattr(e, 'value', 'n/a')})")
126
- set_cooldown(acc_phone, wait)
104
+ logger.warning(f"{acc_phone}: ⏰ FloodWait {wait}s (code:{getattr(e, 'value', 'n/a')})")
127
105
  # صبر در این تابع به اندازهٔ wait ضروری نیست — cooldown کافی است.
128
106
  return False
129
107
 
@@ -189,8 +167,7 @@ async def run_spammer(spam_config: dict, get_spam_texts, make_mention_html, remo
189
167
 
190
168
  try:
191
169
  while spam_config.get("run", False):
192
- # cleanup expired cooldowns
193
- clear_expired_cooldowns()
170
+ # cleanup expired cooldowns
194
171
 
195
172
  # refresh active accounts (live snapshot)
196
173
  active_accounts: Set[str] = set(client_manager.get_active_accounts())
@@ -200,12 +177,8 @@ async def run_spammer(spam_config: dict, get_spam_texts, make_mention_html, remo
200
177
  continue
201
178
 
202
179
  # filter out accounts currently in cooldown
203
- acc_list = sorted([a for a in active_accounts if not is_in_cooldown(a)])
204
- if not acc_list:
205
- # همه در cooldown هستند — کمی صبر کن و ادامه بده
206
- logger.info("تمام اکانت‌ها در cooldown هستند؛ کمی صبر می‌کنیم...")
207
- await asyncio.sleep(min(5, base_delay))
208
- continue
180
+ acc_list = sorted([a for a in active_accounts])
181
+
209
182
 
210
183
  texts = get_spam_texts()
211
184
  if not texts: