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 +21 -0
- sorocore-1.0.0/MANIFEST.in +4 -0
- sorocore-1.0.0/PKG-INFO +56 -0
- sorocore-1.0.0/README.md +34 -0
- sorocore-1.0.0/requirements.txt +1 -0
- sorocore-1.0.0/rouba_backup/__init__.py +7 -0
- sorocore-1.0.0/rouba_backup/client.py +186 -0
- sorocore-1.0.0/rouba_backup/client_backup.py +274 -0
- sorocore-1.0.0/rouba_backup/events.py +3 -0
- sorocore-1.0.0/setup.cfg +10 -0
- sorocore-1.0.0/setup.py +21 -0
- sorocore-1.0.0/sorocore/__init__.py +4 -0
- sorocore-1.0.0/sorocore/client.py +93 -0
- sorocore-1.0.0/sorocore/events.py +27 -0
- sorocore-1.0.0/sorocore.egg-info/PKG-INFO +56 -0
- sorocore-1.0.0/sorocore.egg-info/SOURCES.txt +18 -0
- sorocore-1.0.0/sorocore.egg-info/dependency_links.txt +1 -0
- sorocore-1.0.0/sorocore.egg-info/requires.txt +1 -0
- sorocore-1.0.0/sorocore.egg-info/top_level.txt +2 -0
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.
|
sorocore-1.0.0/PKG-INFO
ADDED
|
@@ -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
|
sorocore-1.0.0/README.md
ADDED
|
@@ -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,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
|
sorocore-1.0.0/setup.cfg
ADDED
sorocore-1.0.0/setup.py
ADDED
|
@@ -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,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
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
splusthon>=1.1.4
|