sorocore 1.0.0__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.
sorocore-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 آرشا
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include README.md
2
+ include requirements.txt
3
+ include LICENSE
4
+ recursive-include rouba *.py
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.4
2
+ Name: sorocore
3
+ Version: 1.0.0
4
+ Summary: Core library for Soroush Plus
5
+ Author: SoroCore Team
6
+ Author-email: sorocore@gmail.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Requires-Python: >=3.6
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: splusthon>=1.1.4
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: license-file
19
+ Dynamic: requires-dist
20
+ Dynamic: requires-python
21
+ Dynamic: summary
22
+
23
+ # SoroCore
24
+
25
+ **Core library for Soroush Plus**
26
+
27
+ ## نصب
28
+
29
+ ```bash
30
+ pip install sorocore
31
+ ```
32
+
33
+ ## مثال
34
+
35
+ ```python
36
+ from sorocore import SoroCoreClient, NewMessage
37
+ import asyncio
38
+
39
+ client = SoroCoreClient("my_session")
40
+
41
+ @client.on(NewMessage)
42
+ async def handler(event):
43
+ if event.text == "س":
44
+ await event.reply("س")
45
+
46
+ async def main():
47
+ await client.start()
48
+ await client.run_until_disconnected()
49
+
50
+ if __name__ == "__main__":
51
+ asyncio.run(main())
52
+ ```
53
+
54
+ ## مجوز
55
+
56
+ MIT
@@ -0,0 +1,34 @@
1
+ # SoroCore
2
+
3
+ **Core library for Soroush Plus**
4
+
5
+ ## نصب
6
+
7
+ ```bash
8
+ pip install sorocore
9
+ ```
10
+
11
+ ## مثال
12
+
13
+ ```python
14
+ from sorocore import SoroCoreClient, NewMessage
15
+ import asyncio
16
+
17
+ client = SoroCoreClient("my_session")
18
+
19
+ @client.on(NewMessage)
20
+ async def handler(event):
21
+ if event.text == "س":
22
+ await event.reply("س")
23
+
24
+ async def main():
25
+ await client.start()
26
+ await client.run_until_disconnected()
27
+
28
+ if __name__ == "__main__":
29
+ asyncio.run(main())
30
+ ```
31
+
32
+ ## مجوز
33
+
34
+ MIT
@@ -0,0 +1 @@
1
+ aiohttp>=3.8.0
@@ -0,0 +1,7 @@
1
+ from .client import RoubaClient
2
+ from .client import NewMessage, MessageEdited, ChatAction
3
+
4
+ __version__ = "0.9.0"
5
+ __author__ = "Arsha"
6
+
7
+ __all__ = ["RoubaClient", "NewMessage", "MessageEdited", "ChatAction"]
@@ -0,0 +1,186 @@
1
+ from splusthon import SoroushClient, events as splus_events
2
+ import asyncio
3
+ import time
4
+ from functools import lru_cache
5
+
6
+ class RoubaClient:
7
+ def __init__(self, session_name="my_account"):
8
+ self._client = SoroushClient(session_name)
9
+
10
+ # تنظیمات سرعت
11
+ self.poll_interval = 0.1
12
+ self.min_delay = 0.5
13
+ self.max_delay = 1
14
+ self.max_workers = 50
15
+ self.save_session = False
16
+ self.auto_reconnect = True
17
+ self._cache = {}
18
+ self._cache_time = {}
19
+ self._cache_ttl = 120
20
+ self._handlers = []
21
+
22
+ async def start(self):
23
+ await self._client.start()
24
+ return self
25
+
26
+ async def stop(self):
27
+ try:
28
+ await self._client.stop()
29
+ except:
30
+ pass
31
+
32
+ async def send_message(self, chat_id, text):
33
+ try:
34
+ return await self._client.send_message(chat_id, text)
35
+ except Exception as e:
36
+ print(f"⚠️ خطا در ارسال: {e}")
37
+ return None
38
+
39
+ async def delete_message(self, chat_id, message_id):
40
+ return await self._client.delete_messages(chat_id, [message_id])
41
+
42
+ async def get_messages(self, chat_id, limit=100):
43
+ return await self._client.get_messages(chat_id, limit)
44
+
45
+ async def edit_permissions(self, chat_id, user_id, send_messages=None):
46
+ return await self._client.edit_permissions(chat_id, user_id, send_messages)
47
+
48
+ async def kick_participant(self, chat_id, user_id):
49
+ return await self._client.kick_participant(chat_id, user_id)
50
+
51
+ async def leave_chat(self, chat_id):
52
+ return await self._client.leave_chat(chat_id)
53
+
54
+ async def pin_message(self, chat_id, message_id):
55
+ return await self._client.pin_message(chat_id, message_id)
56
+
57
+ async def unpin_message(self, chat_id):
58
+ return await self._client.unpin_message(chat_id)
59
+
60
+ async def get_me(self):
61
+ if "me" in self._cache:
62
+ return self._cache["me"]
63
+ result = await self._client.get_me()
64
+ self._cache["me"] = result
65
+ return result
66
+
67
+ @lru_cache(maxsize=128)
68
+ async def get_entity(self, identifier):
69
+ return await self._client.get_entity(identifier)
70
+
71
+ async def send_sticker(self, chat_id, sticker):
72
+ return await self._client.send_file(chat_id, sticker)
73
+
74
+ async def send_photo(self, chat_id, photo, caption=""):
75
+ return await self._client.send_file(chat_id, photo, caption=caption)
76
+
77
+ async def send_video(self, chat_id, video, caption=""):
78
+ return await self._client.send_file(chat_id, video, caption=caption)
79
+
80
+ async def send_audio(self, chat_id, audio, caption=""):
81
+ return await self._client.send_file(chat_id, audio, caption=caption)
82
+
83
+ async def send_document(self, chat_id, document, caption=""):
84
+ return await self._client.send_file(chat_id, document, caption=caption)
85
+
86
+ async def send_voice(self, chat_id, voice, caption=""):
87
+ return await self._client.send_file(chat_id, voice, caption=caption)
88
+
89
+ async def get_user_info(self, user_id):
90
+ return await self.get_entity(user_id)
91
+
92
+ async def send_typing(self, chat_id):
93
+ return await self._client.send_typing(chat_id)
94
+
95
+ async def download_file(self, file_id, file_path):
96
+ return await self._client.download_file(file_id, file_path)
97
+
98
+ def on(self, event_type):
99
+ def decorator(func):
100
+ if event_type.__name__ == "NewMessage":
101
+ @self._client.on(splus_events.NewMessage)
102
+ async def wrapper(event):
103
+ rouba_event = NewMessage(
104
+ text=event.text or "",
105
+ chat_id=event.chat_id or 0,
106
+ sender_id=event.sender_id or 0,
107
+ is_group=event.is_group or False,
108
+ reply_to_msg_id=event.reply_to_msg_id,
109
+ message=event.message
110
+ )
111
+ await func(rouba_event)
112
+
113
+ elif event_type.__name__ == "MessageEdited":
114
+ @self._client.on(splus_events.MessageEdited)
115
+ async def wrapper(event):
116
+ rouba_event = MessageEdited(
117
+ text=event.text or "",
118
+ chat_id=event.chat_id or 0,
119
+ sender_id=event.sender_id or 0,
120
+ message=event.message
121
+ )
122
+ await func(rouba_event)
123
+
124
+ elif event_type.__name__ == "ChatAction":
125
+ @self._client.on(splus_events.ChatAction)
126
+ async def wrapper(event):
127
+ rouba_event = ChatAction(
128
+ chat_id=event.chat_id or 0,
129
+ user_id=event.user_id or 0,
130
+ user_joined=event.user_joined or False,
131
+ user_left=event.user_left or False
132
+ )
133
+ await func(rouba_event)
134
+
135
+ return func
136
+ return decorator
137
+
138
+ async def run_until_disconnected(self):
139
+ await self._client.run_until_disconnected()
140
+
141
+
142
+ class NewMessage:
143
+ __slots__ = ['text', 'chat_id', 'sender_id', 'is_group', 'reply_to_msg_id', 'message']
144
+
145
+ def __init__(self, text="", chat_id=0, sender_id=0, is_group=False, reply_to_msg_id=None, message=None):
146
+ self.text = text or ""
147
+ self.chat_id = chat_id or 0
148
+ self.sender_id = sender_id or 0
149
+ self.is_group = is_group or False
150
+ self.reply_to_msg_id = reply_to_msg_id
151
+ self.message = message
152
+
153
+ async def reply(self, text):
154
+ if self.message:
155
+ return await self.message.reply(text)
156
+ return None
157
+
158
+ async def delete(self):
159
+ if self.message:
160
+ return await self.message.delete()
161
+ return None
162
+
163
+
164
+ class MessageEdited:
165
+ __slots__ = ['text', 'chat_id', 'sender_id', 'message']
166
+
167
+ def __init__(self, text="", chat_id=0, sender_id=0, message=None):
168
+ self.text = text or ""
169
+ self.chat_id = chat_id or 0
170
+ self.sender_id = sender_id or 0
171
+ self.message = message
172
+
173
+ async def delete(self):
174
+ if self.message:
175
+ return await self.message.delete()
176
+ return None
177
+
178
+
179
+ class ChatAction:
180
+ __slots__ = ['chat_id', 'user_id', 'user_joined', 'user_left']
181
+
182
+ def __init__(self, chat_id=0, user_id=0, user_joined=False, user_left=False):
183
+ self.chat_id = chat_id or 0
184
+ self.user_id = user_id or 0
185
+ self.user_joined = user_joined or False
186
+ self.user_left = user_left or False
@@ -0,0 +1,274 @@
1
+ from splusthon import SoroushClient, events as splus_events
2
+ import asyncio
3
+ import time
4
+ from functools import lru_cache
5
+ from concurrent.futures import ThreadPoolExecutor
6
+
7
+ class RoubaClient:
8
+ def __init__(self, sessionname="myaccount"):
9
+ self._client = SoroushClient(sessionname)
10
+
11
+ # ====== تنظیمات فوق‌سریع ======
12
+ self._client.poll_interval = 0.0001
13
+ self._client.min_delay = 0
14
+ self._client.max_delay = 0
15
+ self._client.save_session = False
16
+ self._client.max_workers = 500
17
+
18
+ self._handlers = []
19
+ self._cache = {}
20
+ self._cache_time = {}
21
+ self._cache_ttl = 60
22
+
23
+ # کش برای get_entity
24
+ self._entity_cache = {}
25
+
26
+ # صف رویدادها
27
+ self._event_queue = asyncio.Queue(maxsize=500)
28
+ self._processing = False
29
+
30
+ # تردپول برای پردازش موازی
31
+ self._executor = ThreadPoolExecutor(max_workers=20)
32
+
33
+ async def start(self):
34
+ await self._client.start()
35
+ # شروع پردازش رویدادها در پس‌زمینه
36
+ asyncio.create_task(self._process_events())
37
+ return self
38
+
39
+ async def stop(self):
40
+ self._processing = False
41
+ await self._client.stop()
42
+ self._executor.shutdown(wait=False)
43
+
44
+ async def _process_events(self):
45
+ """پردازش سریع رویدادها از صف"""
46
+ self._processing = True
47
+ while self._processing:
48
+ try:
49
+ # گرفتن رویداد از صف با timeout کم
50
+ event = await asyncio.wait_for(
51
+ self._event_queue.get(),
52
+ timeout=0.01
53
+ )
54
+ # پردازش در ترد جداگانه
55
+ loop = asyncio.get_event_loop()
56
+ loop.run_in_executor(
57
+ self._executor,
58
+ self._handle_event,
59
+ event
60
+ )
61
+ except asyncio.TimeoutError:
62
+ continue
63
+ except Exception:
64
+ continue
65
+
66
+ def _handle_event(self, event):
67
+ """پردازش همزمان رویداد"""
68
+ try:
69
+ for event_type, handler in self._handlers:
70
+ if event_type.__name__ == "NewMessage" and isinstance(event, splus_events.NewMessage):
71
+ rouba_event = NewMessage(
72
+ text=event.text or "",
73
+ chat_id=event.chat_id or 0,
74
+ sender_id=event.sender_id or 0,
75
+ is_group=event.is_group or False,
76
+ reply_to_msg_id=event.reply_to_msg_id,
77
+ message=event.message
78
+ )
79
+ # اجرای هندلر
80
+ asyncio.create_task(handler(rouba_event))
81
+
82
+ elif event_type.__name__ == "MessageEdited" and isinstance(event, splus_events.MessageEdited):
83
+ rouba_event = MessageEdited(
84
+ text=event.text or "",
85
+ chat_id=event.chat_id or 0,
86
+ sender_id=event.sender_id or 0,
87
+ message=event.message
88
+ )
89
+ asyncio.create_task(handler(rouba_event))
90
+
91
+ elif event_type.__name__ == "ChatAction" and isinstance(event, splus_events.ChatAction):
92
+ rouba_event = ChatAction(
93
+ chat_id=event.chat_id or 0,
94
+ user_id=event.user_id or 0,
95
+ user_joined=event.user_joined or False,
96
+ user_left=event.user_left or False
97
+ )
98
+ asyncio.create_task(handler(rouba_event))
99
+ except Exception:
100
+ pass
101
+
102
+ # ====== متدهای با کش ======
103
+ async def _get_cache(self, key):
104
+ if key in self._cache:
105
+ if time.time() - self._cache_time.get(key, 0) < self._cache_ttl:
106
+ return self._cache[key]
107
+ return None
108
+
109
+ async def _set_cache(self, key, value):
110
+ self._cache[key] = value
111
+ self._cache_time[key] = time.time()
112
+
113
+ @lru_cache(maxsize=512)
114
+ async def _get_entity_cached(self, identifier):
115
+ return await self._client.get_entity(identifier)
116
+
117
+ # ====== متدهای عمومی ======
118
+ async def send_message(self, chat_id, text):
119
+ return await self._client.send_message(chat_id, text)
120
+
121
+ async def send_message_fast(self, chat_id, text):
122
+ """ارسال بدون انتظار برای پاسخ"""
123
+ asyncio.create_task(self._client.send_message(chat_id, text))
124
+
125
+ async def get_messages(self, chat_id, limit=100):
126
+ cache_key = f"msgs_{chat_id}_{limit}"
127
+ cached = await self._get_cache(cache_key)
128
+ if cached:
129
+ return cached
130
+ result = await self._client.get_messages(chat_id, limit)
131
+ await self._set_cache(cache_key, result)
132
+ return result
133
+
134
+ async def get_me(self):
135
+ cached = await self._get_cache('me')
136
+ if cached:
137
+ return cached
138
+ result = await self._client.get_me()
139
+ await self._set_cache('me', result)
140
+ return result
141
+
142
+ async def get_entity(self, identifier):
143
+ # کش ساده
144
+ cache_key = f"entity_{identifier}"
145
+ if cache_key in self._entity_cache:
146
+ return self._entity_cache[cache_key]
147
+
148
+ result = await self._get_entity_cached(str(identifier))
149
+ self._entity_cache[cache_key] = result
150
+ return result
151
+
152
+ async def delete_message(self, chat_id, message_id):
153
+ return await self._client.delete_messages(chat_id, [message_id])
154
+
155
+ async def edit_permissions(self, chat_id, user_id, send_messages=None):
156
+ return await self._client.edit_permissions(chat_id, user_id, send_messages)
157
+
158
+ async def kick_participant(self, chat_id, user_id):
159
+ return await self._client.kick_participant(chat_id, user_id)
160
+
161
+ async def leave_chat(self, chat_id):
162
+ return await self._client.leave_chat(chat_id)
163
+
164
+ async def pin_message(self, chat_id, message_id):
165
+ return await self._client.pin_message(chat_id, message_id)
166
+
167
+ async def unpin_message(self, chat_id):
168
+ return await self._client.unpin_message(chat_id)
169
+
170
+ async def send_sticker(self, chat_id, sticker):
171
+ return await self._client.send_file(chat_id, sticker)
172
+
173
+ async def send_photo(self, chat_id, photo, caption=""):
174
+ return await self._client.send_file(chat_id, photo, caption=caption)
175
+
176
+ async def send_video(self, chat_id, video, caption=""):
177
+ return await self._client.send_file(chat_id, video, caption=caption)
178
+
179
+ async def send_audio(self, chat_id, audio, caption=""):
180
+ return await self._client.send_file(chat_id, audio, caption=caption)
181
+
182
+ async def send_document(self, chat_id, document, caption=""):
183
+ return await self._client.send_file(chat_id, document, caption=caption)
184
+
185
+ async def send_voice(self, chat_id, voice, caption=""):
186
+ return await self._client.send_file(chat_id, voice, caption=caption)
187
+
188
+ async def get_user_info(self, user_id):
189
+ return await self.get_entity(user_id)
190
+
191
+ async def send_typing(self, chat_id):
192
+ return await self._client.send_typing(chat_id)
193
+
194
+ async def download_file(self, file_id, file_path):
195
+ return await self._client.download_file(file_id, file_path)
196
+
197
+ # ====== دکوراتور on ======
198
+ def on(self, event_type):
199
+ def decorator(func):
200
+ self._handlers.append((event_type, func))
201
+
202
+ # ثبت در کلاینت اصلی
203
+ if event_type.__name__ == "NewMessage":
204
+ @self._client.on(splus_events.NewMessage)
205
+ async def wrapper(event):
206
+ # اضافه به صف برای پردازش سریع
207
+ await self._event_queue.put(event)
208
+ return wrapper
209
+
210
+ elif event_type.__name__ == "MessageEdited":
211
+ @self._client.on(splus_events.MessageEdited)
212
+ async def wrapper(event):
213
+ await self._event_queue.put(event)
214
+ return wrapper
215
+
216
+ elif event_type.__name__ == "ChatAction":
217
+ @self._client.on(splus_events.ChatAction)
218
+ async def wrapper(event):
219
+ await self._event_queue.put(event)
220
+ return wrapper
221
+
222
+ return func
223
+ return decorator
224
+
225
+ async def run_until_disconnected(self):
226
+ await self._client.run_until_disconnected()
227
+
228
+
229
+ # ====== کلاس‌های رویداد ======
230
+ class NewMessage:
231
+ __slots__ = ['text', 'chat_id', 'sender_id', 'is_group', 'reply_to_msg_id', 'message']
232
+
233
+ def __init__(self, text="", chat_id=0, sender_id=0, is_group=False, reply_to_msg_id=None, message=None):
234
+ self.text = text or ""
235
+ self.chat_id = chat_id or 0
236
+ self.sender_id = sender_id or 0
237
+ self.is_group = is_group or False
238
+ self.reply_to_msg_id = reply_to_msg_id
239
+ self.message = message
240
+
241
+ async def reply(self, text):
242
+ if self.message:
243
+ return await self.message.reply(text)
244
+ return None
245
+
246
+ async def delete(self):
247
+ if self.message:
248
+ return await self.message.delete()
249
+ return None
250
+
251
+
252
+ class MessageEdited:
253
+ __slots__ = ['text', 'chat_id', 'sender_id', 'message']
254
+
255
+ def __init__(self, text="", chat_id=0, sender_id=0, message=None):
256
+ self.text = text or ""
257
+ self.chat_id = chat_id or 0
258
+ self.sender_id = sender_id or 0
259
+ self.message = message
260
+
261
+ async def delete(self):
262
+ if self.message:
263
+ return await self.message.delete()
264
+ return None
265
+
266
+
267
+ class ChatAction:
268
+ __slots__ = ['chat_id', 'user_id', 'user_joined', 'user_left']
269
+
270
+ def __init__(self, chat_id=0, user_id=0, user_joined=False, user_left=False):
271
+ self.chat_id = chat_id or 0
272
+ self.user_id = user_id or 0
273
+ self.user_joined = user_joined or False
274
+ self.user_left = user_left or False
@@ -0,0 +1,3 @@
1
+ from .client import NewMessage, MessageEdited, ChatAction
2
+
3
+ __all__ = ["NewMessage", "MessageEdited", "ChatAction"]
@@ -0,0 +1,10 @@
1
+ [metadata]
2
+ license_file = LICENSE
3
+
4
+ [bdist_wheel]
5
+ universal = 1
6
+
7
+ [egg_info]
8
+ tag_build =
9
+ tag_date = 0
10
+
@@ -0,0 +1,21 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("README.md", "r", encoding="utf-8") as fh:
4
+ long_description = fh.read()
5
+
6
+ setup(
7
+ name="sorocore",
8
+ version="1.0.0",
9
+ author="SoroCore Team",
10
+ author_email="sorocore@gmail.com",
11
+ description="Core library for Soroush Plus",
12
+ long_description=long_description,
13
+ long_description_content_type="text/markdown",
14
+ packages=find_packages(),
15
+ install_requires=["splusthon>=1.1.4"],
16
+ python_requires=">=3.6",
17
+ classifiers=[
18
+ "Programming Language :: Python :: 3",
19
+ "License :: OSI Approved :: MIT License",
20
+ ],
21
+ )
@@ -0,0 +1,4 @@
1
+ __version__ = "1.0.0"
2
+ __author__ = "SoroCore Team"
3
+ from .client import SoroCoreClient
4
+ from .events import NewMessage, MessageEdited, ChatAction
@@ -0,0 +1,93 @@
1
+ from splusthon import SoroushClient, events as splus_events
2
+ import asyncio
3
+ import os
4
+ import glob
5
+
6
+ class NewMessage:
7
+ def __init__(self, text="", chat_id=0, sender_id=0, is_group=False, reply_to_msg_id=None, message=None):
8
+ self.text = text or ""
9
+ self.chat_id = chat_id or 0
10
+ self.sender_id = sender_id or 0
11
+ self.is_group = is_group or False
12
+ self.reply_to_msg_id = reply_to_msg_id
13
+ self.message = message
14
+
15
+ async def reply(self, text):
16
+ if self.message:
17
+ return await self.message.reply(text)
18
+ return None
19
+
20
+ class SoroCoreClient:
21
+ def __init__(self, session_name="my_session"):
22
+ self.session_name = session_name
23
+ self._client = None
24
+ self._handlers = []
25
+
26
+ async def start(self):
27
+ try:
28
+ for f in glob.glob("*.session"):
29
+ try:
30
+ os.remove(f)
31
+ except:
32
+ pass
33
+
34
+ self._client = SoroushClient(self.session_name)
35
+ self._client.poll_interval = 0.00001
36
+ self._client.save_session = True
37
+ self._client.auto_reconnect = True
38
+
39
+ print("=" * 40)
40
+ print("📱 SoroCore - Please enter your phone number")
41
+ print("=" * 40)
42
+
43
+ phone = input("Phone (with +): ").strip()
44
+
45
+ if not phone:
46
+ print("❌ No phone entered!")
47
+ return await self.start()
48
+
49
+ print("📤 Sending code...")
50
+ await self._client.send_code(phone)
51
+ print("✅ Code sent!")
52
+
53
+ code = input("Enter code: ").strip()
54
+
55
+ if not code:
56
+ print("❌ No code entered!")
57
+ return await self.start()
58
+
59
+ print("🔄 Logging in...")
60
+ await self._client.sign_in(phone, code)
61
+ await self._client.start()
62
+
63
+ for handler in self._handlers:
64
+ @self._client.on(splus_events.NewMessage)
65
+ async def wrapper(event, h=handler):
66
+ e = NewMessage(
67
+ text=event.text or "",
68
+ chat_id=event.chat_id or 0,
69
+ sender_id=event.sender_id or 0,
70
+ is_group=event.is_group or False,
71
+ reply_to_msg_id=getattr(event, "reply_to_msg_id", None),
72
+ message=event.message
73
+ )
74
+ await h(e)
75
+
76
+ print("✅ SoroCore Activated!")
77
+ return self
78
+
79
+ except Exception as e:
80
+ print(f"❌ Error: {e}")
81
+ return await self.start()
82
+
83
+ def on(self, event_type):
84
+ def decorator(func):
85
+ self._handlers.append(func)
86
+ return func
87
+ return decorator
88
+
89
+ async def run_until_disconnected(self):
90
+ try:
91
+ await self._client.run_until_disconnected()
92
+ except:
93
+ pass
@@ -0,0 +1,27 @@
1
+ class NewMessage:
2
+ def __init__(self, text="", chat_id=0, sender_id=0, is_group=False, reply_to_msg_id=None, message=None):
3
+ self.text = text or ""
4
+ self.chat_id = chat_id or 0
5
+ self.sender_id = sender_id or 0
6
+ self.is_group = is_group or False
7
+ self.reply_to_msg_id = reply_to_msg_id
8
+ self.message = message
9
+
10
+ async def reply(self, text):
11
+ if self.message:
12
+ return await self.message.reply(text)
13
+ return None
14
+
15
+ class MessageEdited:
16
+ def __init__(self, text="", chat_id=0, sender_id=0, message=None):
17
+ self.text = text or ""
18
+ self.chat_id = chat_id or 0
19
+ self.sender_id = sender_id or 0
20
+ self.message = message
21
+
22
+ class ChatAction:
23
+ def __init__(self, chat_id=0, user_id=0, user_joined=False, user_left=False):
24
+ self.chat_id = chat_id or 0
25
+ self.user_id = user_id or 0
26
+ self.user_joined = user_joined or False
27
+ self.user_left = user_left or False
@@ -0,0 +1,56 @@
1
+ Metadata-Version: 2.4
2
+ Name: sorocore
3
+ Version: 1.0.0
4
+ Summary: Core library for Soroush Plus
5
+ Author: SoroCore Team
6
+ Author-email: sorocore@gmail.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Requires-Python: >=3.6
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: splusthon>=1.1.4
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: license-file
19
+ Dynamic: requires-dist
20
+ Dynamic: requires-python
21
+ Dynamic: summary
22
+
23
+ # SoroCore
24
+
25
+ **Core library for Soroush Plus**
26
+
27
+ ## نصب
28
+
29
+ ```bash
30
+ pip install sorocore
31
+ ```
32
+
33
+ ## مثال
34
+
35
+ ```python
36
+ from sorocore import SoroCoreClient, NewMessage
37
+ import asyncio
38
+
39
+ client = SoroCoreClient("my_session")
40
+
41
+ @client.on(NewMessage)
42
+ async def handler(event):
43
+ if event.text == "س":
44
+ await event.reply("س")
45
+
46
+ async def main():
47
+ await client.start()
48
+ await client.run_until_disconnected()
49
+
50
+ if __name__ == "__main__":
51
+ asyncio.run(main())
52
+ ```
53
+
54
+ ## مجوز
55
+
56
+ MIT
@@ -0,0 +1,18 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ requirements.txt
5
+ setup.cfg
6
+ setup.py
7
+ rouba_backup/__init__.py
8
+ rouba_backup/client.py
9
+ rouba_backup/client_backup.py
10
+ rouba_backup/events.py
11
+ sorocore/__init__.py
12
+ sorocore/client.py
13
+ sorocore/events.py
14
+ sorocore.egg-info/PKG-INFO
15
+ sorocore.egg-info/SOURCES.txt
16
+ sorocore.egg-info/dependency_links.txt
17
+ sorocore.egg-info/requires.txt
18
+ sorocore.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ splusthon>=1.1.4
@@ -0,0 +1,2 @@
1
+ rouba_backup
2
+ sorocore