PySPlus 0.3__py3-none-any.whl → 0.5__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.
pysplus/Client.py CHANGED
@@ -7,7 +7,9 @@ from selenium.webdriver.chrome.options import Options
7
7
  from webdriver_manager.chrome import ChromeDriverManager
8
8
  from bs4 import BeautifulSoup
9
9
  from .colors import *
10
- from typing import Optional
10
+ from .async_sync import *
11
+ from typing import Optional,Literal
12
+ from traceback import format_exc
11
13
  import time,os,json,asyncio,logging,pickle
12
14
 
13
15
  logging.getLogger('selenium').setLevel(logging.WARNING)
@@ -35,7 +37,6 @@ class Client:
35
37
  self.time_out = text_json_py_slpus_session["time_out"]
36
38
  self.user_agent = text_json_py_slpus_session["user_agent"]
37
39
  self.display_welcome = text_json_py_slpus_session["display_welcome"]
38
- asyncio.run(self.login())
39
40
  else:
40
41
  if not number_phone:
41
42
  number_phone = input("Enter your phone number : ")
@@ -46,21 +47,21 @@ class Client:
46
47
  number_phone = input("Enter your phone number : ")
47
48
  if number_phone.startswith("0"):
48
49
  number_phone = number_phone[1:]
49
- is_login = asyncio.run(self.login())
50
+ is_login = self.login()
50
51
  if not is_login:
51
52
  print("Error Login !")
52
53
  exit()
53
- text_json_py_slpus_session = {
54
- "name_session": name_session,
55
- "number_phone":number_phone,
56
- "user_agent": user_agent,
57
- "time_out": time_out,
58
- "display_welcome": display_welcome,
59
- }
60
- with open(name, "w", encoding="utf-8") as file:
61
- json.dump(
62
- text_json_py_slpus_session, file, ensure_ascii=False, indent=4
63
- )
54
+ # text_json_py_slpus_session = {
55
+ # "name_session": name_session,
56
+ # "number_phone":number_phone,
57
+ # "user_agent": user_agent,
58
+ # "time_out": time_out,
59
+ # "display_welcome": display_welcome,
60
+ # }
61
+ # with open(name, "w", encoding="utf-8") as file:
62
+ # json.dump(
63
+ # text_json_py_slpus_session, file, ensure_ascii=False, indent=4
64
+ # )
64
65
  self.time_out = time_out
65
66
  self.user_agent = user_agent
66
67
  self.number_phone = number_phone
@@ -77,6 +78,7 @@ class Client:
77
78
  if not number.startswith("9"):
78
79
  return False
79
80
  return True
81
+ @async_to_sync
80
82
  async def login(self) -> bool:
81
83
  """لاگین / login"""
82
84
  chrome_options = Options()
@@ -86,23 +88,23 @@ class Client:
86
88
  chrome_options.add_argument("--lang=fa")
87
89
  chrome_options.add_experimental_option("detach", True)
88
90
  service = Service(ChromeDriverManager().install())
89
- driver = webdriver.Chrome(service=service, options=chrome_options)
90
91
  self.driver = webdriver.Chrome(service=service, options=chrome_options)
91
- wait = WebDriverWait(driver, 15)
92
+ wait = WebDriverWait(self.driver, 30)
92
93
  try:
93
- driver.get("https://web.splus.ir")
94
+ self.driver.get("https://web.splus.ir")
95
+ wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
94
96
  time.sleep(1)
95
97
  is_open_cookies = False
96
98
  if os.path.exists(self.name_cookies):
97
99
  with open(self.name_cookies, 'rb') as file:
98
100
  cookies = pickle.load(file)
99
101
  for cookie in cookies:
100
- driver.add_cookie(cookie)
102
+ self.driver.add_cookie(cookie)
101
103
  is_open_cookies = True
102
104
  if is_open_cookies:
103
- driver.refresh()
105
+ self.driver.refresh()
104
106
  try:
105
- understand_button = WebDriverWait(driver, 3).until(
107
+ understand_button = WebDriverWait(self.driver, 3).until(
106
108
  EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), 'متوجه شدم')]"))
107
109
  )
108
110
  understand_button.click()
@@ -124,25 +126,47 @@ class Client:
124
126
  code_input = wait.until(
125
127
  EC.presence_of_element_located((By.CSS_SELECTOR, "input#sign-in-code"))
126
128
  )
127
- self.code_html = driver.page_source
129
+ self.code_html = self.driver.page_source
128
130
  code_input.clear()
129
131
  code_input.send_keys(verification_code)
130
132
  time.sleep(5)
131
- self.code_html = driver.page_source
133
+ self.code_html = self.driver.page_source
132
134
  messages = await self.get_chat_ids()
133
135
  while not messages:
134
136
  time.sleep(1)
135
- self.code_html = driver.page_source
137
+ self.code_html = self.driver.page_source
136
138
  messages = await self.get_chat_ids()
137
139
  with open(self.name_cookies, 'wb') as file:
138
- pickle.dump(driver.get_cookies(), file)
140
+ pickle.dump(self.driver.get_cookies(), file)
139
141
  return True
140
142
  except Exception as e:
141
- driver.save_screenshot("error_screenshot.png")
143
+ print("/*-+123456789*-+")
144
+ print(format_exc())
145
+ print("123456789*-+")
146
+ self.driver.save_screenshot("error_screenshot.png")
142
147
  print("ERROR :")
143
148
  print(e)
144
149
  print("ERROR SAVED : error_screenshot.png")
145
150
  return False
151
+
152
+ @async_to_sync
153
+ async def get_type_chat_id(
154
+ self,
155
+ chat_id:str
156
+ ) -> Literal["Channel","Group","Bot","User",None]:
157
+ """getting chat id type / گرفتن نوع چت آیدی"""
158
+ if chat_id.startswith("-"):
159
+ if len(chat_id) == 11:
160
+ return "Channel"
161
+ elif len(chat_id) == 12:
162
+ return "Group"
163
+ if len(chat_id) == 6:
164
+ return "User"
165
+ elif len(chat_id) == 8:
166
+ return "Bot"
167
+ return None
168
+
169
+ @async_to_sync
146
170
  async def get_chat_ids(self) -> list:
147
171
  """گرفتن چت آیدی ها / getting chat ids"""
148
172
  soup = BeautifulSoup(self.code_html, "html.parser")
@@ -162,24 +186,82 @@ class Client:
162
186
  if a!=None:
163
187
  chat = str(a["href"]).replace("#","")
164
188
  chats.append(chat)
165
- else:
166
- print("❌ تگ ریشه پیدا نشد!")
167
189
  return chats
168
- async def send_text(self,chat_id:str,text:str) -> bool:
190
+
191
+ @async_to_sync
192
+ async def get_chats(self) -> list:
193
+ """گرفتن چت ها / getting chats"""
194
+ soup = BeautifulSoup(self.code_html, "html.parser")
195
+ root = soup.select_one(
196
+ "body > #UiLoader > div.Transition.full-height > "
197
+ "#Main.left-column-shown.left-column-open > "
198
+ "#LeftColumn > #LeftColumn-main > div.Transition > "
199
+ "div.ChatFolders.not-open.not-shown > div.Transition > "
200
+ "div.chat-list.custom-scroll > div[style*='position: relative']"
201
+ )
202
+ chats_ = []
203
+ chats = []
204
+ if root:
205
+ divs = root.find_all("div", recursive=True)
206
+ for div in divs:
207
+ anchors = div.find_all("a", href=True)
208
+ for a in anchors:
209
+ if a!=None:
210
+ chat = str(a["href"]).replace("#","")
211
+ chats_.append(chat)
212
+ for chat in chats_:
213
+ type_chat = await self.get_type_chat_id(chat)
214
+ chats.append({
215
+ "chat_id":chat,
216
+ "type_chat":type_chat
217
+ })
218
+ return chats
219
+
220
+ @async_to_sync
221
+ async def open_chat(self, chat_id: str) -> bool:
222
+ """opening chat / باز کردن چت"""
223
+ try:
224
+ self.driver.get("https://web.splus.ir")
225
+ WebDriverWait(self.driver, 60).until(
226
+ EC.presence_of_element_located((By.CSS_SELECTOR, "div.chat-list, div[role='main']"))
227
+ )
228
+ chat_link = WebDriverWait(self.driver, 20).until(
229
+ EC.element_to_be_clickable((By.CSS_SELECTOR, f'a[href="#{chat_id}"]'))
230
+ )
231
+ chat_link.click()
232
+ print(f"✅ Chat {chat_id} opened.")
233
+ WebDriverWait(self.driver, 30).until(
234
+ EC.presence_of_element_located((By.CSS_SELECTOR, "div[contenteditable='true']"))
235
+ )
236
+ return True
237
+ except Exception as e:
238
+ print("❌ Error in open_chat : ", e)
239
+ self.driver.save_screenshot("open_chat_error.png")
240
+ return False
241
+
242
+ @async_to_sync
243
+ async def send_text(self, chat_id: str, text: str) -> bool:
169
244
  """ارسال متن / sending text"""
170
245
  try:
171
- self.driver.get(f"https://web.splus.ir/#{chat_id}")
172
- time.sleep(3)
173
- input_box = WebDriverWait(self.driver, 15).until(
174
- EC.presence_of_element_located((By.CSS_SELECTOR, "div.input-message-input"))
246
+ await self.open_chat(chat_id)
247
+ WebDriverWait(self.driver, 25).until(
248
+ EC.presence_of_element_located((By.CSS_SELECTOR, "div[contenteditable='true']"))
175
249
  )
176
- input_box.click()
177
- input_box.send_keys(text)
178
- send_button = WebDriverWait(self.driver, 15).until(
179
- EC.element_to_be_clickable((By.CSS_SELECTOR, "button.Button.send"))
250
+ input_box = self.driver.find_element(By.CSS_SELECTOR, "div[contenteditable='true']")
251
+ self.driver.execute_script("""
252
+ arguments[0].innerText = arguments[1];
253
+ arguments[0].dispatchEvent(new Event('input', { bubbles: true }));
254
+ """, input_box, text)
255
+ send_button = WebDriverWait(self.driver, 30).until(
256
+ EC.element_to_be_clickable((
257
+ By.CSS_SELECTOR,
258
+ "button.Button.send.main-button.default.secondary.round.click-allowed"
259
+ ))
180
260
  )
181
261
  send_button.click()
262
+ print("✅ Message sent successfully.")
182
263
  return True
183
264
  except Exception as e:
184
- print("Error in send_text:", e)
265
+ print(f"Error in send_text : {e}")
266
+ self.driver.save_screenshot("send_text_error.png")
185
267
  return False
pysplus/async_sync.py ADDED
@@ -0,0 +1,15 @@
1
+ import asyncio
2
+ from functools import wraps
3
+
4
+ def async_to_sync(func):
5
+ """دکوراتور برای تبدیل تابع async به sync"""
6
+ @wraps(func)
7
+ def wrapper(*args, **kwargs):
8
+ try:
9
+ loop = asyncio.get_running_loop()
10
+ async def coro_wrapper():
11
+ return await func(*args, **kwargs)
12
+ return coro_wrapper()
13
+ except RuntimeError:
14
+ return asyncio.run(func(*args, **kwargs))
15
+ return wrapper
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySPlus
3
- Version: 0.3
3
+ Version: 0.5
4
4
  Summary: the library SPlus platform for bots.
5
5
  Home-page: https://github.com/OandONE/SPlus
6
6
  Author: seyyed mohamad hosein moosavi raja(01)
@@ -21,11 +21,11 @@ Dynamic: requires-dist
21
21
  Dynamic: requires-python
22
22
  Dynamic: summary
23
23
 
24
- # fast rub
24
+ # PySPlus
25
25
 
26
26
  This Python library is for SPlus platform bots and is currently being updated.
27
27
 
28
- ## fast rub
28
+ ## PySPlus
29
29
 
30
30
  - 1 fast
31
31
  - 2 simple syntax
@@ -0,0 +1,8 @@
1
+ pysplus/Client.py,sha256=QuNKFuDiSaysh93_0wfXKsY_PGCg1sEqYGdvuTLQRaU,11552
2
+ pysplus/__init__.py,sha256=D6b12F-lYPY38W7ymcNtCgUQb7tu79scbEcbDjIRR5c,97
3
+ pysplus/async_sync.py,sha256=d9VSE7_A7zgOI8BAlZoxfm8LdkdWxyZdpgAEOrRpQcg,489
4
+ pysplus/colors.py,sha256=SwcpovYEff7gDHMtWZAjYnVSbvhqSiHXlAoa4eSJ9RM,556
5
+ pysplus-0.5.dist-info/METADATA,sha256=yqXKWChLEIVeFXJR5-l4anNFJyA2z8pjHVmT2EVM0Sc,854
6
+ pysplus-0.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ pysplus-0.5.dist-info/top_level.txt,sha256=h2PKSbKoDxAHsNE8pxuQY8VllsI-4KQW_Udcd7DKQkA,8
8
+ pysplus-0.5.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- pysplus/Client.py,sha256=emZEP-Ct22GkmR_GsofohEUUBh-hMrbMTBPFlPFuiak,8256
2
- pysplus/__init__.py,sha256=D6b12F-lYPY38W7ymcNtCgUQb7tu79scbEcbDjIRR5c,97
3
- pysplus/colors.py,sha256=SwcpovYEff7gDHMtWZAjYnVSbvhqSiHXlAoa4eSJ9RM,556
4
- pysplus-0.3.dist-info/METADATA,sha256=6kCTAaI-d-0XxjA94i_uilP1cGePT3gEoj0SSgeQx-Q,856
5
- pysplus-0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
- pysplus-0.3.dist-info/top_level.txt,sha256=h2PKSbKoDxAHsNE8pxuQY8VllsI-4KQW_Udcd7DKQkA,8
7
- pysplus-0.3.dist-info/RECORD,,
File without changes