spluspy 2.2.7__tar.gz → 2.2.9__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.
- {spluspy-2.2.7/spluspy.egg-info → spluspy-2.2.9}/PKG-INFO +4 -3
- {spluspy-2.2.7 → spluspy-2.2.9}/README.md +3 -2
- {spluspy-2.2.7 → spluspy-2.2.9}/pyproject.toml +1 -1
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/__init__.py +2 -1
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/downloads.py +13 -2
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/extra.py +16 -3
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/telegrambaseclient.py +1 -1
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/updates.py +2 -18
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/uploads.py +111 -90
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/users.py +16 -2
- spluspy-2.2.9/spluspy/enums.py +144 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/common.py +9 -3
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/mtprotosender.py +51 -2
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/sessions/memory.py +11 -3
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/message.py +22 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/utils.py +4 -14
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/version.py +1 -1
- {spluspy-2.2.7 → spluspy-2.2.9/spluspy.egg-info}/PKG-INFO +4 -3
- spluspy-2.2.7/spluspy/enums.py +0 -17
- {spluspy-2.2.7 → spluspy-2.2.9}/LICENSE +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/setup.cfg +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/_updates/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/_updates/entitycache.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/_updates/messagebox.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/_updates/session.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/admin.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/account.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/auth.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/buttons.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/chats.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/dialogs.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/messageparse.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/messages.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/client/soroushclient.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/crypto/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/crypto/aes.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/crypto/aesctr.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/crypto/authkey.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/crypto/cdndecrypter.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/crypto/factorization.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/crypto/libssl.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/crypto/rsa.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/custom.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/errors/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/errors/common.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/errors/exceptions.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/errors/rpcbaseerrors.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/errors/rpcerrorlist.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/album.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/chataction.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/messagedeleted.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/messageedited.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/messageread.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/newmessage.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/raw.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/events/userupdate.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/extensions/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/extensions/binaryreader.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/extensions/html.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/extensions/markdown.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/extensions/messagepacker.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/filters.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/functions.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/helpers.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/hints.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/authenticator.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/connection.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/http.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/tcpabridged.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/tcpfull.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/tcpintermediate.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/tcpmtproxy.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/tcpobfuscated.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/connection/websocket.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/mtprotoplainsender.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/mtprotostate.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/network/requeststate.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/password.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/requestiter.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/resolvers.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/sessions/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/sessions/abstract.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/sessions/sqlite.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/sessions/string.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/sync.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/alltlobjects.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/core/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/core/gzippacked.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/core/messagecontainer.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/core/rpcresult.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/core/tlmessage.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/adminlogevent.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/button.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/chatgetter.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/conversation.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/dialog.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/draft.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/file.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/forward.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/inputsizedfile.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/messagebutton.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/participantpermissions.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/qrlogin.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/sendergetter.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/custom/types.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/account.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/auth.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/bots.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/channels.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/chatlists.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/conference.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/contacts.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/folders.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/help.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/langpack.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/messages.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/payments.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/phone.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/photos.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/premium.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/stats.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/stories.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/thirdParty.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/updates.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/upload.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/functions/users.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/patched/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/tlobject.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/__init__.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/account.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/auth.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/bots.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/channels.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/chatlists.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/conference.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/contacts.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/help.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/messages.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/payments.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/phone.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/photos.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/premium.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/stats.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/stickers.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/storage.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/stories.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/thirdParty.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/update.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/updates.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/upload.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy/tl/types/users.py +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy.egg-info/SOURCES.txt +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy.egg-info/dependency_links.txt +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy.egg-info/requires.txt +0 -0
- {spluspy-2.2.7 → spluspy-2.2.9}/spluspy.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spluspy
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.9
|
|
4
4
|
Summary: High-performance Python Self-Bot Framework for Soroush Plus
|
|
5
5
|
Author: Ali Mirshekari
|
|
6
6
|
License: MIT
|
|
@@ -26,7 +26,8 @@ Requires-Dist: rsa
|
|
|
26
26
|
Requires-Dist: pyaes
|
|
27
27
|
Dynamic: license-file
|
|
28
28
|
|
|
29
|
-
# SplusPy v2.2.
|
|
29
|
+
# SplusPy v2.2.9
|
|
30
|
+
|
|
30
31
|
|
|
31
32
|
**A fast, minimal, and fully-featured self-bot framework**
|
|
32
33
|
|
|
@@ -36,7 +37,7 @@ Dynamic: license-file
|
|
|
36
37
|
|
|
37
38
|
SplusPy is a Python library designed specifically for building **Soroush Plus self-bots** (userbots). It provides a clean, intuitive API for automating your personal Soroush Plus account with ease.
|
|
38
39
|
|
|
39
|
-
> ⚠️ **Note:** This is a **self-bot framework** — it operates on your personal account, not a bot account. Please adhere to
|
|
40
|
+
> ⚠️ **Note:** This is a **self-bot framework** — it operates on your personal account, not a bot account. Please adhere to Soroush's Terms of Service.
|
|
40
41
|
|
|
41
42
|
---
|
|
42
43
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
# SplusPy v2.2.
|
|
1
|
+
# SplusPy v2.2.9
|
|
2
|
+
|
|
2
3
|
|
|
3
4
|
**A fast, minimal, and fully-featured self-bot framework**
|
|
4
5
|
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
|
|
9
10
|
SplusPy is a Python library designed specifically for building **Soroush Plus self-bots** (userbots). It provides a clean, intuitive API for automating your personal Soroush Plus account with ease.
|
|
10
11
|
|
|
11
|
-
> ⚠️ **Note:** This is a **self-bot framework** — it operates on your personal account, not a bot account. Please adhere to
|
|
12
|
+
> ⚠️ **Note:** This is a **self-bot framework** — it operates on your personal account, not a bot account. Please adhere to Soroush's Terms of Service.
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
@@ -4,11 +4,12 @@ from .tl.custom import Button
|
|
|
4
4
|
from .tl import patched as _ # import for its side-effects
|
|
5
5
|
from . import version, events, utils, errors, functions, custom
|
|
6
6
|
from .filters import filters
|
|
7
|
+
from .enums import MessageMediaType
|
|
7
8
|
|
|
8
9
|
__version__ = version.__version__
|
|
9
10
|
|
|
10
11
|
__all__ = [
|
|
11
|
-
'Client', 'Button', 'filters',
|
|
12
|
+
'Client', 'Button', 'filters', 'MessageMediaType',
|
|
12
13
|
'functions', 'custom', 'errors',
|
|
13
14
|
'events', 'utils', 'connection'
|
|
14
15
|
]
|
|
@@ -118,6 +118,17 @@ class _DirectDownloadIter(RequestIter):
|
|
|
118
118
|
self._exported = True
|
|
119
119
|
return await self._request()
|
|
120
120
|
|
|
121
|
+
except errors.RPCError as e:
|
|
122
|
+
err_msg = str(e).upper()
|
|
123
|
+
if "FILE_REQUEST_RECEIVED_ON_CONNECTION_SERVER" in err_msg or "422" in err_msg:
|
|
124
|
+
self.client._log[__name__].info('File download must be on Media DC; switching to DC 5')
|
|
125
|
+
if self._exported and getattr(self, '_sender', None):
|
|
126
|
+
await self.client._return_exported_sender(self._sender)
|
|
127
|
+
self._sender = await self.client._borrow_exported_sender(5)
|
|
128
|
+
self._exported = True
|
|
129
|
+
return await self._request()
|
|
130
|
+
raise
|
|
131
|
+
|
|
121
132
|
except (errors.FilerefUpgradeNeededError, errors.FileReferenceExpiredError) as e:
|
|
122
133
|
# Only implemented for documents which are the ones that may take that long to download
|
|
123
134
|
if not self._msg_data \
|
|
@@ -142,7 +153,7 @@ class _DirectDownloadIter(RequestIter):
|
|
|
142
153
|
return await self._request()
|
|
143
154
|
|
|
144
155
|
async def close(self):
|
|
145
|
-
if
|
|
156
|
+
if getattr(self, '_sender', None) is None:
|
|
146
157
|
return
|
|
147
158
|
|
|
148
159
|
try:
|
|
@@ -1093,4 +1104,4 @@ class DownloadMethods:
|
|
|
1093
1104
|
return result
|
|
1094
1105
|
i += 1
|
|
1095
1106
|
|
|
1096
|
-
# endregion
|
|
1107
|
+
# endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import typing
|
|
2
2
|
from ..tl import functions, types
|
|
3
|
-
from .. import helpers, utils, hints
|
|
3
|
+
from .. import helpers, utils, hints, errors
|
|
4
4
|
|
|
5
5
|
if typing.TYPE_CHECKING:
|
|
6
6
|
from .soroushclient import SoroushClient
|
|
@@ -224,9 +224,9 @@ class ExtraMethods:
|
|
|
224
224
|
The full chat info (FullChannel or FullChat).
|
|
225
225
|
"""
|
|
226
226
|
entity = await self.get_input_entity(chat_id)
|
|
227
|
-
|
|
227
|
+
try:
|
|
228
228
|
return await self(functions.channels.GetFullChannelRequest(entity))
|
|
229
|
-
|
|
229
|
+
except errors.BadRequestError:
|
|
230
230
|
return await self(functions.messages.GetFullChatRequest(entity.chat_id))
|
|
231
231
|
|
|
232
232
|
async def get_chat_info(self: 'SoroushClient', chat_id):
|
|
@@ -237,10 +237,23 @@ class ExtraMethods:
|
|
|
237
237
|
"""Alias for get_entity. Returns the entity for the given user."""
|
|
238
238
|
return await self.get_entity(user_id)
|
|
239
239
|
|
|
240
|
+
async def get_full_user(self: 'SoroushClient', user_id):
|
|
241
|
+
"""Fetches full user profile information."""
|
|
242
|
+
try:
|
|
243
|
+
entity = await self.get_input_entity(user_id)
|
|
244
|
+
return await self(functions.users.GetFullUserRequest(id=entity))
|
|
245
|
+
except Exception:
|
|
246
|
+
return None
|
|
247
|
+
|
|
240
248
|
async def get_full_chat(self: 'SoroushClient', chat_id):
|
|
241
249
|
"""Alias for get_chat. Returns full chat/channel info."""
|
|
242
250
|
return await self.get_chat(chat_id)
|
|
243
251
|
|
|
252
|
+
async def is_public_chat(self: 'SoroushClient', chat_id: 'hints.EntityLike') -> bool:
|
|
253
|
+
"""Check if a chat is public (has a username) or not."""
|
|
254
|
+
entity = await self.get_entity(chat_id)
|
|
255
|
+
return bool(getattr(entity, 'username', None))
|
|
256
|
+
|
|
244
257
|
async def get_dialogs(
|
|
245
258
|
self: 'SoroushClient',
|
|
246
259
|
limit: int = 0,
|
|
@@ -855,7 +855,7 @@ class SoroushPlusBaseClient(abc.ABC):
|
|
|
855
855
|
# Soroush: map all DCs to splus.ir servers
|
|
856
856
|
if not cdn:
|
|
857
857
|
domain = '.splus.ir'
|
|
858
|
-
if dc_id in (1, 2, 3, 4
|
|
858
|
+
if dc_id in (1, 2, 3, 4):
|
|
859
859
|
ip = f'im-server{domain}'
|
|
860
860
|
elif dc_id == 6:
|
|
861
861
|
ip = f'im-server{domain}'
|
|
@@ -298,6 +298,8 @@ class UpdateMethods:
|
|
|
298
298
|
event = None
|
|
299
299
|
if isinstance(update, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
|
|
300
300
|
event = NewMessage.build(update, None, self._mb_entity_cache.self_id)
|
|
301
|
+
if event is None and isinstance(update.message, types.MessageService):
|
|
302
|
+
event = ChatAction.build(update, None, self._mb_entity_cache.self_id)
|
|
301
303
|
elif isinstance(update, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
|
|
302
304
|
event = MessageEdited.build(update, None, self._mb_entity_cache.self_id)
|
|
303
305
|
elif isinstance(update, (types.UpdateDeleteMessages, types.UpdateDeleteChannelMessages)):
|
|
@@ -317,24 +319,6 @@ class UpdateMethods:
|
|
|
317
319
|
types.UpdateChannelUserTyping,
|
|
318
320
|
)):
|
|
319
321
|
event = UserUpdate.build(update, None, self._mb_entity_cache.self_id)
|
|
320
|
-
elif isinstance(update, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
|
|
321
|
-
# Check for service messages that are ChatActions
|
|
322
|
-
msg = update.message
|
|
323
|
-
if isinstance(msg, types.MessageService) and isinstance(msg.action, (
|
|
324
|
-
types.MessageActionChatJoinedByLink,
|
|
325
|
-
types.MessageActionChatAddUser,
|
|
326
|
-
types.MessageActionChatDeleteUser,
|
|
327
|
-
types.MessageActionChatCreate,
|
|
328
|
-
types.MessageActionChannelCreate,
|
|
329
|
-
types.MessageActionChatEditTitle,
|
|
330
|
-
types.MessageActionChatEditPhoto,
|
|
331
|
-
types.MessageActionChatDeletePhoto,
|
|
332
|
-
types.MessageActionPinMessage,
|
|
333
|
-
types.MessageActionGameScore,
|
|
334
|
-
)):
|
|
335
|
-
event = ChatAction.build(update, None, self._mb_entity_cache.self_id)
|
|
336
|
-
else:
|
|
337
|
-
event = NewMessage.build(update, None, self._mb_entity_cache.self_id)
|
|
338
322
|
|
|
339
323
|
# For Raw handlers, always dispatch with the raw update
|
|
340
324
|
raw_event = update
|
|
@@ -9,7 +9,7 @@ from io import BytesIO
|
|
|
9
9
|
|
|
10
10
|
from ..crypto import AES
|
|
11
11
|
|
|
12
|
-
from .. import utils, helpers, hints
|
|
12
|
+
from .. import utils, helpers, hints, errors
|
|
13
13
|
from ..tl import types, functions, custom
|
|
14
14
|
|
|
15
15
|
try:
|
|
@@ -666,96 +666,117 @@ class UploadMethods:
|
|
|
666
666
|
if isinstance(file, (types.InputFile, types.InputFileBig)):
|
|
667
667
|
return file # Already uploaded
|
|
668
668
|
|
|
669
|
+
media_sender = None
|
|
670
|
+
media_dc = 5 # دیتاسنتر اختصاصی فایلهای سروش پلاس
|
|
671
|
+
|
|
669
672
|
pos = 0
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
if not part_size_kb:
|
|
675
|
-
part_size_kb = utils.get_appropriated_part_size(file_size)
|
|
676
|
-
|
|
677
|
-
if part_size_kb > 512:
|
|
678
|
-
raise ValueError('The part size must be less or equal to 512KB')
|
|
679
|
-
|
|
680
|
-
part_size = int(part_size_kb * 1024)
|
|
681
|
-
if part_size % 1024 != 0:
|
|
682
|
-
raise ValueError(
|
|
683
|
-
'The part size must be evenly divisible by 1024')
|
|
684
|
-
|
|
685
|
-
# Set a default file name if None was specified
|
|
686
|
-
file_id = helpers.generate_random_long()
|
|
687
|
-
if not file_name:
|
|
688
|
-
file_name = stream.name or str(file_id)
|
|
689
|
-
|
|
690
|
-
# If the file name lacks extension, add it if possible.
|
|
691
|
-
# Else SoroushPlus complains with `PHOTO_EXT_INVALID_ERROR`
|
|
692
|
-
# even if the uploaded image is indeed a photo.
|
|
693
|
-
if not os.path.splitext(file_name)[-1]:
|
|
694
|
-
file_name += utils._get_extension(stream)
|
|
695
|
-
|
|
696
|
-
# Determine whether the file is too big (over 10MB) or not
|
|
697
|
-
# SoroushPlus does make a distinction between smaller or larger files
|
|
698
|
-
is_big = file_size > 10 * 1024 * 1024
|
|
699
|
-
hash_md5 = hashlib.md5()
|
|
700
|
-
|
|
701
|
-
part_count = (file_size + part_size - 1) // part_size
|
|
702
|
-
self._log[__name__].info('Uploading file of %d bytes in %d chunks of %d',
|
|
703
|
-
file_size, part_count, part_size)
|
|
704
|
-
|
|
705
|
-
pos = 0
|
|
706
|
-
for part_index in range(part_count):
|
|
707
|
-
# Read the file by in chunks of size part_size
|
|
708
|
-
part = await helpers._maybe_await(stream.read(part_size))
|
|
709
|
-
|
|
710
|
-
if not isinstance(part, bytes):
|
|
711
|
-
raise TypeError(
|
|
712
|
-
'file descriptor returned {}, not bytes (you must '
|
|
713
|
-
'open the file in bytes mode)'.format(type(part)))
|
|
714
|
-
|
|
715
|
-
# `file_size` could be wrong in which case `part` may not be
|
|
716
|
-
# `part_size` before reaching the end.
|
|
717
|
-
if len(part) != part_size and part_index < part_count - 1:
|
|
718
|
-
raise ValueError(
|
|
719
|
-
'read less than {} before reaching the end; either '
|
|
720
|
-
'`file_size` or `read` are wrong'.format(part_size))
|
|
721
|
-
|
|
722
|
-
pos += len(part)
|
|
723
|
-
|
|
724
|
-
# Encryption part if needed
|
|
725
|
-
if key and iv:
|
|
726
|
-
part = AES.encrypt_ige(part, key, iv)
|
|
727
|
-
|
|
728
|
-
if not is_big:
|
|
729
|
-
# Bit odd that MD5 is only needed for small files and not
|
|
730
|
-
# big ones with more chance for corruption, but that's
|
|
731
|
-
# what SoroushPlus wants.
|
|
732
|
-
hash_md5.update(part)
|
|
733
|
-
|
|
734
|
-
# The SavePartRequest is different depending on whether
|
|
735
|
-
# the file is too large or not (over or less than 10MB)
|
|
736
|
-
if is_big:
|
|
737
|
-
request = functions.upload.SaveBigFilePartRequest(
|
|
738
|
-
file_id, part_index, part_count, part)
|
|
739
|
-
else:
|
|
740
|
-
request = functions.upload.SaveFilePartRequest(
|
|
741
|
-
file_id, part_index, part)
|
|
742
|
-
|
|
743
|
-
result = await self(request)
|
|
744
|
-
if result:
|
|
745
|
-
self._log[__name__].debug('Uploaded %d/%d',
|
|
746
|
-
part_index + 1, part_count)
|
|
747
|
-
if progress_callback:
|
|
748
|
-
await helpers._maybe_await(progress_callback(pos, file_size))
|
|
749
|
-
else:
|
|
750
|
-
raise RuntimeError(
|
|
751
|
-
'Failed to upload file part {}.'.format(part_index))
|
|
673
|
+
try:
|
|
674
|
+
async with helpers._FileStream(file, file_size=file_size) as stream:
|
|
675
|
+
# Opening the stream will determine the correct file size
|
|
676
|
+
file_size = stream.file_size
|
|
752
677
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
678
|
+
if not part_size_kb:
|
|
679
|
+
part_size_kb = utils.get_appropriated_part_size(file_size)
|
|
680
|
+
|
|
681
|
+
if part_size_kb > 512:
|
|
682
|
+
raise ValueError('The part size must be less or equal to 512KB')
|
|
683
|
+
|
|
684
|
+
part_size = int(part_size_kb * 1024)
|
|
685
|
+
if part_size % 1024 != 0:
|
|
686
|
+
raise ValueError(
|
|
687
|
+
'The part size must be evenly divisible by 1024')
|
|
688
|
+
|
|
689
|
+
# Set a default file name if None was specified
|
|
690
|
+
file_id = helpers.generate_random_long()
|
|
691
|
+
if not file_name:
|
|
692
|
+
file_name = stream.name or str(file_id)
|
|
693
|
+
|
|
694
|
+
# If the file name lacks extension, add it if possible.
|
|
695
|
+
# Else SoroushPlus complains with `PHOTO_EXT_INVALID_ERROR`
|
|
696
|
+
# even if the uploaded image is indeed a photo.
|
|
697
|
+
if not os.path.splitext(file_name)[-1]:
|
|
698
|
+
file_name += utils._get_extension(stream)
|
|
699
|
+
|
|
700
|
+
# Determine whether the file is too big (over 10MB) or not
|
|
701
|
+
# SoroushPlus does make a distinction between smaller or larger files
|
|
702
|
+
is_big = file_size > 10 * 1024 * 1024
|
|
703
|
+
hash_md5 = hashlib.md5()
|
|
704
|
+
|
|
705
|
+
part_count = (file_size + part_size - 1) // part_size
|
|
706
|
+
self._log[__name__].info('Uploading file of %d bytes in %d chunks of %d',
|
|
707
|
+
file_size, part_count, part_size)
|
|
708
|
+
|
|
709
|
+
pos = 0
|
|
710
|
+
for part_index in range(part_count):
|
|
711
|
+
# Read the file by in chunks of size part_size
|
|
712
|
+
part = await helpers._maybe_await(stream.read(part_size))
|
|
713
|
+
|
|
714
|
+
if not isinstance(part, bytes):
|
|
715
|
+
raise TypeError(
|
|
716
|
+
'file descriptor returned {}, not bytes (you must '
|
|
717
|
+
'open the file in bytes mode)'.format(type(part)))
|
|
718
|
+
|
|
719
|
+
# `file_size` could be wrong in which case `part` may not be
|
|
720
|
+
# `part_size` before reaching the end.
|
|
721
|
+
if len(part) != part_size and part_index < part_count - 1:
|
|
722
|
+
raise ValueError(
|
|
723
|
+
'read less than {} before reaching the end; either '
|
|
724
|
+
'`file_size` or `read` are wrong'.format(part_size))
|
|
725
|
+
|
|
726
|
+
pos += len(part)
|
|
727
|
+
|
|
728
|
+
# Encryption part if needed
|
|
729
|
+
if key and iv:
|
|
730
|
+
part = AES.encrypt_ige(part, key, iv)
|
|
731
|
+
|
|
732
|
+
if not is_big:
|
|
733
|
+
# Bit odd that MD5 is only needed for small files and not
|
|
734
|
+
# big ones with more chance for corruption, but that's
|
|
735
|
+
# what SoroushPlus wants.
|
|
736
|
+
hash_md5.update(part)
|
|
737
|
+
|
|
738
|
+
# The SavePartRequest is different depending on whether
|
|
739
|
+
# the file is too large or not (over or less than 10MB)
|
|
740
|
+
if is_big:
|
|
741
|
+
request = functions.upload.SaveBigFilePartRequest(
|
|
742
|
+
file_id, part_index, part_count, part)
|
|
743
|
+
else:
|
|
744
|
+
request = functions.upload.SaveFilePartRequest(
|
|
745
|
+
file_id, part_index, part)
|
|
746
|
+
|
|
747
|
+
# ارسال ریکوئست آپلود با هندل کردن اتصال سرور مدیا
|
|
748
|
+
if media_sender:
|
|
749
|
+
result = await self._call(media_sender, request)
|
|
750
|
+
else:
|
|
751
|
+
try:
|
|
752
|
+
result = await self(request)
|
|
753
|
+
except errors.RPCError as e:
|
|
754
|
+
err_msg = str(e).upper()
|
|
755
|
+
if "FILE_REQUEST_RECEIVED_ON_CONNECTION_SERVER" in err_msg or "422" in err_msg:
|
|
756
|
+
self._log[__name__].info('Switching to Media DC (DC 5) for upload...')
|
|
757
|
+
media_sender = await self._borrow_exported_sender(media_dc)
|
|
758
|
+
result = await self._call(media_sender, request)
|
|
759
|
+
else:
|
|
760
|
+
raise
|
|
761
|
+
|
|
762
|
+
if result:
|
|
763
|
+
self._log[__name__].debug('Uploaded %d/%d',
|
|
764
|
+
part_index + 1, part_count)
|
|
765
|
+
if progress_callback:
|
|
766
|
+
await helpers._maybe_await(progress_callback(pos, file_size))
|
|
767
|
+
else:
|
|
768
|
+
raise RuntimeError(
|
|
769
|
+
'Failed to upload file part {}.'.format(part_index))
|
|
770
|
+
|
|
771
|
+
if is_big:
|
|
772
|
+
return types.InputFileBig(file_id, part_count, file_name)
|
|
773
|
+
else:
|
|
774
|
+
return custom.InputSizedFile(
|
|
775
|
+
file_id, part_count, file_name, md5=hash_md5, size=file_size
|
|
776
|
+
)
|
|
777
|
+
finally:
|
|
778
|
+
if media_sender:
|
|
779
|
+
await self._return_exported_sender(media_sender)
|
|
759
780
|
|
|
760
781
|
# endregion
|
|
761
782
|
|
|
@@ -864,4 +885,4 @@ class UploadMethods:
|
|
|
864
885
|
)
|
|
865
886
|
return file_handle, media, as_image
|
|
866
887
|
|
|
867
|
-
# endregion
|
|
888
|
+
# endregion
|
|
@@ -483,6 +483,18 @@ class UserMethods:
|
|
|
483
483
|
'GetUsersRequest with access_hash=0 failed for user %s, '
|
|
484
484
|
'trying contacts fallback', peer.user_id)
|
|
485
485
|
|
|
486
|
+
# SoroushPlus groups are channels. A bare positive ID may actually
|
|
487
|
+
# be a group, so try resolving it as a channel before giving up.
|
|
488
|
+
try:
|
|
489
|
+
channels = await self(functions.channels.GetChannelsRequest([
|
|
490
|
+
types.InputChannel(peer.user_id, access_hash=0)]))
|
|
491
|
+
if channels.chats:
|
|
492
|
+
return utils.get_input_peer(channels.chats[0])
|
|
493
|
+
except errors.RPCError:
|
|
494
|
+
_log.debug(
|
|
495
|
+
'GetChannelsRequest with access_hash=0 failed for %s',
|
|
496
|
+
peer.user_id)
|
|
497
|
+
|
|
486
498
|
# Fallback: search contacts for the user by ID
|
|
487
499
|
try:
|
|
488
500
|
contacts = (await self(
|
|
@@ -510,8 +522,10 @@ class UserMethods:
|
|
|
510
522
|
)
|
|
511
523
|
|
|
512
524
|
async def _get_peer(self: 'SoroushClient', peer: 'hints.EntityLike'):
|
|
513
|
-
|
|
514
|
-
|
|
525
|
+
if isinstance(peer, int):
|
|
526
|
+
i, cls = utils.resolve_id(await self.get_peer_id(peer))
|
|
527
|
+
return cls(i)
|
|
528
|
+
return utils.get_peer(peer)
|
|
515
529
|
|
|
516
530
|
async def get_peer_id(
|
|
517
531
|
self: 'SoroushClient',
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MessageMediaType(Enum):
|
|
5
|
+
PHOTO = "photo"
|
|
6
|
+
VIDEO = "video"
|
|
7
|
+
VIDEO_NOTE = "video_note"
|
|
8
|
+
DOCUMENT = "document"
|
|
9
|
+
AUDIO = "audio"
|
|
10
|
+
VOICE = "voice"
|
|
11
|
+
STICKER = "sticker"
|
|
12
|
+
ANIMATION = "animation"
|
|
13
|
+
GIF = "gif"
|
|
14
|
+
WEB_PAGE = "web_page"
|
|
15
|
+
GEO = "geo"
|
|
16
|
+
GEO_LIVE = "geo_live"
|
|
17
|
+
CONTACT = "contact"
|
|
18
|
+
GAME = "game"
|
|
19
|
+
POLL = "poll"
|
|
20
|
+
DICE = "dice"
|
|
21
|
+
VENUE = "venue"
|
|
22
|
+
STORY = "story"
|
|
23
|
+
GIVEAWAY = "giveaway"
|
|
24
|
+
INVOICE = "invoice"
|
|
25
|
+
UNSUPPORTED = "unsupported"
|
|
26
|
+
EMPTY = "empty"
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_media(cls, media):
|
|
30
|
+
"""
|
|
31
|
+
Detect MessageMediaType from a MessageMedia object.
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
from spluspy.enums import MessageMediaType
|
|
35
|
+
media_type = MessageMediaType.from_media(message.media)
|
|
36
|
+
"""
|
|
37
|
+
from .tl import types
|
|
38
|
+
|
|
39
|
+
if media is None or isinstance(media, types.MessageMediaEmpty):
|
|
40
|
+
return cls.EMPTY
|
|
41
|
+
|
|
42
|
+
if isinstance(media, types.MessageMediaPhoto):
|
|
43
|
+
return cls.PHOTO
|
|
44
|
+
|
|
45
|
+
if isinstance(media, types.MessageMediaDocument):
|
|
46
|
+
doc = media.document
|
|
47
|
+
if doc is None or isinstance(doc, types.DocumentEmpty):
|
|
48
|
+
return cls.DOCUMENT
|
|
49
|
+
|
|
50
|
+
attrs = {type(a): a for a in doc.attributes}
|
|
51
|
+
|
|
52
|
+
if types.DocumentAttributeSticker in attrs:
|
|
53
|
+
return cls.STICKER
|
|
54
|
+
|
|
55
|
+
if types.DocumentAttributeAnimated in attrs:
|
|
56
|
+
if types.DocumentAttributeVideo in attrs:
|
|
57
|
+
return cls.ANIMATION
|
|
58
|
+
return cls.GIF
|
|
59
|
+
|
|
60
|
+
if types.DocumentAttributeVideo in attrs:
|
|
61
|
+
vid = attrs[types.DocumentAttributeVideo]
|
|
62
|
+
if vid.round_message:
|
|
63
|
+
return cls.VIDEO_NOTE
|
|
64
|
+
return cls.VIDEO
|
|
65
|
+
|
|
66
|
+
if types.DocumentAttributeAudio in attrs:
|
|
67
|
+
aud = attrs[types.DocumentAttributeAudio]
|
|
68
|
+
if aud.voice:
|
|
69
|
+
return cls.VOICE
|
|
70
|
+
return cls.AUDIO
|
|
71
|
+
|
|
72
|
+
return cls.DOCUMENT
|
|
73
|
+
|
|
74
|
+
if isinstance(media, types.MessageMediaWebPage):
|
|
75
|
+
return cls.WEB_PAGE
|
|
76
|
+
|
|
77
|
+
if isinstance(media, types.MessageMediaGeo):
|
|
78
|
+
return cls.GEO
|
|
79
|
+
|
|
80
|
+
if isinstance(media, types.MessageMediaGeoLive):
|
|
81
|
+
return cls.GEO_LIVE
|
|
82
|
+
|
|
83
|
+
if isinstance(media, types.MessageMediaContact):
|
|
84
|
+
return cls.CONTACT
|
|
85
|
+
|
|
86
|
+
if isinstance(media, types.MessageMediaGame):
|
|
87
|
+
return cls.GAME
|
|
88
|
+
|
|
89
|
+
if isinstance(media, types.MessageMediaPoll):
|
|
90
|
+
return cls.POLL
|
|
91
|
+
|
|
92
|
+
if isinstance(media, types.MessageMediaDice):
|
|
93
|
+
return cls.DICE
|
|
94
|
+
|
|
95
|
+
if isinstance(media, types.MessageMediaVenue):
|
|
96
|
+
return cls.VENUE
|
|
97
|
+
|
|
98
|
+
if isinstance(media, types.MessageMediaStory):
|
|
99
|
+
return cls.STORY
|
|
100
|
+
|
|
101
|
+
if isinstance(media, types.MessageMediaGiveaway):
|
|
102
|
+
return cls.GIVEAWAY
|
|
103
|
+
|
|
104
|
+
if isinstance(media, types.MessageMediaInvoice):
|
|
105
|
+
return cls.INVOICE
|
|
106
|
+
|
|
107
|
+
if isinstance(media, types.MessageMediaUnsupported):
|
|
108
|
+
return cls.UNSUPPORTED
|
|
109
|
+
|
|
110
|
+
return cls.EMPTY
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def from_message(cls, message):
|
|
114
|
+
"""
|
|
115
|
+
Detect MessageMediaType from a Message object.
|
|
116
|
+
|
|
117
|
+
Usage:
|
|
118
|
+
from spluspy.enums import MessageMediaType
|
|
119
|
+
media_type = MessageMediaType.from_message(event.message)
|
|
120
|
+
"""
|
|
121
|
+
if hasattr(message, 'media'):
|
|
122
|
+
return cls.from_media(message.media)
|
|
123
|
+
return cls.EMPTY
|
|
124
|
+
|
|
125
|
+
def is_image(self):
|
|
126
|
+
return self == self.PHOTO
|
|
127
|
+
|
|
128
|
+
def is_video(self):
|
|
129
|
+
return self in (self.VIDEO, self.VIDEO_NOTE, self.ANIMATION)
|
|
130
|
+
|
|
131
|
+
def is_audio(self):
|
|
132
|
+
return self in (self.AUDIO, self.VOICE)
|
|
133
|
+
|
|
134
|
+
def is_document(self):
|
|
135
|
+
return self == self.DOCUMENT
|
|
136
|
+
|
|
137
|
+
def is_sticker(self):
|
|
138
|
+
return self == self.STICKER
|
|
139
|
+
|
|
140
|
+
def is_animation(self):
|
|
141
|
+
return self in (self.ANIMATION, self.GIF)
|
|
142
|
+
|
|
143
|
+
def is_media(self):
|
|
144
|
+
return self not in (self.EMPTY, self.UNSUPPORTED)
|
|
@@ -19,9 +19,15 @@ async def _into_id_set(client, chats):
|
|
|
19
19
|
for chat in chats:
|
|
20
20
|
if isinstance(chat, int):
|
|
21
21
|
if chat < 0:
|
|
22
|
-
|
|
22
|
+
# Explicitly marked IDs (e.g. legacy "-100...") are kept, and
|
|
23
|
+
# their unmarked form is also added so both styles match.
|
|
24
|
+
result.add(chat)
|
|
25
|
+
result.add(utils.resolve_id(chat)[0])
|
|
23
26
|
else:
|
|
24
|
-
|
|
27
|
+
# A bare positive ID in SoroushPlus can be a user or a group
|
|
28
|
+
# (channels), so add every possible representation to match
|
|
29
|
+
# whichever type the chat actually is.
|
|
30
|
+
result.update({
|
|
25
31
|
utils.get_peer_id(types.PeerUser(chat)),
|
|
26
32
|
utils.get_peer_id(types.PeerChat(chat)),
|
|
27
33
|
utils.get_peer_id(types.PeerChannel(chat)),
|
|
@@ -122,7 +128,7 @@ class EventBuilder(abc.ABC):
|
|
|
122
128
|
return
|
|
123
129
|
|
|
124
130
|
if self.filters:
|
|
125
|
-
if not await self.filters(event.client, event
|
|
131
|
+
if not await self.filters(event.client, event):
|
|
126
132
|
return
|
|
127
133
|
|
|
128
134
|
if not self.func:
|