spluspy 1.0.2__tar.gz → 1.0.4__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-1.0.2 → spluspy-1.0.4}/PKG-INFO +2 -2
- {spluspy-1.0.2 → spluspy-1.0.4}/README.rst +1 -1
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/auth.py +4 -4
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/soroushclient.py +352 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/telegrambaseclient.py +8 -1
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/mtprotosender.py +7 -2
- spluspy-1.0.4/spluspy/updater.py +72 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/version.py +1 -1
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/PKG-INFO +2 -2
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/SOURCES.txt +1 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/setup.cfg +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/setup.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/_updates/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/_updates/entitycache.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/_updates/messagebox.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/_updates/session.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/account.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/bots.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/buttons.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/chats.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/dialogs.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/downloads.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/messageparse.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/messages.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/ratelimiter.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/updates.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/uploads.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/users.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/aes.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/aesctr.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/authkey.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/cdndecrypter.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/factorization.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/libssl.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/rsa.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/custom.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/errors/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/errors/common.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/errors/rpcbaseerrors.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/errors/rpcerrorlist.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/album.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/callbackquery.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/chataction.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/common.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/decorators.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/inlinequery.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/messagedeleted.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/messageedited.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/messageread.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/newmessage.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/raw.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/userupdate.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/binaryreader.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/html.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/markdown.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/messagepacker.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/functions.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/helpers.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/hints.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/authenticator.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/connection.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/http.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpabridged.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpfull.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpintermediate.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpmtproxy.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpobfuscated.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/websocket.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/mtprotoplainsender.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/mtprotostate.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/requeststate.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/password.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/requestiter.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/abstract.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/memory.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/sqlite.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/string.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sync.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/alltlobjects.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/gzippacked.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/messagecontainer.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/rpcresult.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/tlmessage.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/adminlogevent.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/button.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/chatgetter.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/conversation.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/dialog.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/draft.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/file.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/forward.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/inlinebuilder.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/inlineresult.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/inlineresults.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/inputsizedfile.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/message.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/messagebutton.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/participantpermissions.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/qrlogin.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/sendergetter.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/types.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/account.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/auth.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/bots.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/channels.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/chatlists.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/conference.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/contacts.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/folders.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/help.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/langpack.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/messages.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/payments.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/phone.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/photos.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/premium.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/stats.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/stories.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/thirdParty.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/updates.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/upload.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/users.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/patched/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/tlobject.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/__init__.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/account.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/auth.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/bots.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/channels.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/chatlists.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/conference.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/contacts.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/help.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/messages.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/payments.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/phone.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/photos.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/premium.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/stats.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/stickers.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/storage.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/stories.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/thirdParty.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/update.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/updates.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/upload.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/users.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/types.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/utils.py +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/dependency_links.txt +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/requires.txt +0 -0
- {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spluspy
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Soroush Plus library for Python
|
|
5
5
|
Home-page: https://github.com/Itskillmaster/spluspy
|
|
6
6
|
Download-URL: https://github.com/Itskillmaster/spluspy/releases
|
|
@@ -89,7 +89,7 @@ Install the latest version from PyPI:
|
|
|
89
89
|
|
|
90
90
|
.. code-block:: sh
|
|
91
91
|
|
|
92
|
-
pip install -U
|
|
92
|
+
pip install -U spluspy
|
|
93
93
|
|
|
94
94
|
For faster encryption (recommended):
|
|
95
95
|
|
|
@@ -19,8 +19,8 @@ class AuthMethods:
|
|
|
19
19
|
|
|
20
20
|
def start(
|
|
21
21
|
self: 'SoroushClient',
|
|
22
|
-
phone: typing.Union[typing.Callable[[], str], str] = lambda: input('Please
|
|
23
|
-
password: typing.Union[typing.Callable[[], str], str] = lambda: getpass.getpass('Please
|
|
22
|
+
phone: typing.Union[typing.Callable[[], str], str] = lambda: input('Please Enter The Phone Number Like This ( 989123456789 ): '),
|
|
23
|
+
password: typing.Union[typing.Callable[[], str], str] = lambda: getpass.getpass('Please Enter The Password: '),
|
|
24
24
|
*,
|
|
25
25
|
bot_token: str = None,
|
|
26
26
|
force_sms: bool = False,
|
|
@@ -99,7 +99,7 @@ class AuthMethods:
|
|
|
99
99
|
"""
|
|
100
100
|
if code_callback is None:
|
|
101
101
|
def code_callback():
|
|
102
|
-
return input('Please
|
|
102
|
+
return input('Please Enter The Code: ')
|
|
103
103
|
elif not callable(code_callback):
|
|
104
104
|
raise ValueError(
|
|
105
105
|
'The code_callback parameter needs to be a callable '
|
|
@@ -333,7 +333,7 @@ class AuthMethods:
|
|
|
333
333
|
phone = '+34 123 123 123'
|
|
334
334
|
await client.sign_in(phone) # send code
|
|
335
335
|
|
|
336
|
-
code = input('
|
|
336
|
+
code = input('Please Enter The Code: ')
|
|
337
337
|
await client.sign_in(phone, code)
|
|
338
338
|
"""
|
|
339
339
|
me = None
|
|
@@ -636,6 +636,358 @@ class SoroushClient(
|
|
|
636
636
|
|
|
637
637
|
# endregion
|
|
638
638
|
|
|
639
|
+
# region Convenience methods - Messages
|
|
640
|
+
|
|
641
|
+
async def edit_message(self, *args, **kwargs):
|
|
642
|
+
"""Edit a message. Shortcut for client.edit_message(...)."""
|
|
643
|
+
return await super().edit_message(*args, **kwargs)
|
|
644
|
+
|
|
645
|
+
async def delete_message(self, message):
|
|
646
|
+
"""
|
|
647
|
+
Delete a single message.
|
|
648
|
+
|
|
649
|
+
Arguments
|
|
650
|
+
message: The message to delete (ID, Message object, or list).
|
|
651
|
+
|
|
652
|
+
Example
|
|
653
|
+
.. code-block:: python
|
|
654
|
+
|
|
655
|
+
await client.delete_message(msg)
|
|
656
|
+
await client.delete_message(12345)
|
|
657
|
+
"""
|
|
658
|
+
return await self.delete_messages(message)
|
|
659
|
+
|
|
660
|
+
async def delete_messages(self, *args, **kwargs):
|
|
661
|
+
"""Delete one or more messages."""
|
|
662
|
+
return await super().delete_messages(*args, **kwargs)
|
|
663
|
+
|
|
664
|
+
async def forward_message(self, entity, messages, from_peer=None):
|
|
665
|
+
"""
|
|
666
|
+
Forward a single message.
|
|
667
|
+
|
|
668
|
+
Arguments
|
|
669
|
+
entity: Destination chat.
|
|
670
|
+
messages: The message to forward.
|
|
671
|
+
from_peer: Source chat (required if messages is an ID).
|
|
672
|
+
|
|
673
|
+
Example
|
|
674
|
+
.. code-block:: python
|
|
675
|
+
|
|
676
|
+
await client.forward_message(chat, message)
|
|
677
|
+
await client.forward_message(chat, 12345, from_peer=source_chat)
|
|
678
|
+
"""
|
|
679
|
+
return await self.forward_messages(entity, messages, from_peer=from_peer)
|
|
680
|
+
|
|
681
|
+
async def mark_as_read(self, entity, message=None, max_id=0):
|
|
682
|
+
"""
|
|
683
|
+
Mark messages as read.
|
|
684
|
+
|
|
685
|
+
Arguments
|
|
686
|
+
entity: The chat to mark as read.
|
|
687
|
+
message: Specific message to mark as read.
|
|
688
|
+
max_id: Mark all messages up to this ID as read.
|
|
689
|
+
|
|
690
|
+
Example
|
|
691
|
+
.. code-block:: python
|
|
692
|
+
|
|
693
|
+
await client.mark_as_read(chat)
|
|
694
|
+
await client.mark_as_read(chat, message)
|
|
695
|
+
"""
|
|
696
|
+
if message is not None:
|
|
697
|
+
msg_id = self._get_message_id(message)
|
|
698
|
+
return await self.send_read_acknowledge(entity, max_id=msg_id)
|
|
699
|
+
return await self.send_read_acknowledge(entity, max_id=max_id)
|
|
700
|
+
|
|
701
|
+
# endregion
|
|
702
|
+
|
|
703
|
+
# region Convenience methods - Send Media
|
|
704
|
+
|
|
705
|
+
async def send_voice(self, entity, file, *, caption=None, **kwargs):
|
|
706
|
+
"""
|
|
707
|
+
Send a voice note. Shortcut for send_audio with voice_note=True.
|
|
708
|
+
|
|
709
|
+
Example
|
|
710
|
+
.. code-block:: python
|
|
711
|
+
|
|
712
|
+
await client.send_voice(chat, 'voice.ogg')
|
|
713
|
+
"""
|
|
714
|
+
return await self.send_audio(entity, file, caption=caption, voice_note=True, **kwargs)
|
|
715
|
+
|
|
716
|
+
async def send_video_note(self, entity, file, **kwargs):
|
|
717
|
+
"""
|
|
718
|
+
Send a round video note.
|
|
719
|
+
|
|
720
|
+
Example
|
|
721
|
+
.. code-block:: python
|
|
722
|
+
|
|
723
|
+
await client.send_video_note(chat, 'round.mp4')
|
|
724
|
+
"""
|
|
725
|
+
return await self.send_file(entity, file, video_note=True, **kwargs)
|
|
726
|
+
|
|
727
|
+
async def send_sticker(self, entity, sticker, **kwargs):
|
|
728
|
+
"""
|
|
729
|
+
Send a sticker.
|
|
730
|
+
|
|
731
|
+
Example
|
|
732
|
+
.. code-block:: python
|
|
733
|
+
|
|
734
|
+
await client.send_sticker(chat, 'sticker.webp')
|
|
735
|
+
"""
|
|
736
|
+
return await self.send_file(entity, sticker, **kwargs)
|
|
737
|
+
|
|
738
|
+
async def send_gif(self, entity, gif, *, caption=None, **kwargs):
|
|
739
|
+
"""
|
|
740
|
+
Send an animated GIF.
|
|
741
|
+
|
|
742
|
+
Example
|
|
743
|
+
.. code-block:: python
|
|
744
|
+
|
|
745
|
+
await client.send_gif(chat, 'animation.gif')
|
|
746
|
+
"""
|
|
747
|
+
return await self.send_file(entity, gif, caption=caption, **kwargs)
|
|
748
|
+
|
|
749
|
+
async def send_animation(self, entity, file, *, caption=None, **kwargs):
|
|
750
|
+
"""
|
|
751
|
+
Send an animation (GIF). Alias for send_gif.
|
|
752
|
+
|
|
753
|
+
Example
|
|
754
|
+
.. code-block:: python
|
|
755
|
+
|
|
756
|
+
await client.send_animation(chat, 'animation.gif')
|
|
757
|
+
"""
|
|
758
|
+
return await self.send_gif(entity, file, caption=caption, **kwargs)
|
|
759
|
+
|
|
760
|
+
async def send_location(self, entity, latitude, longitude, **kwargs):
|
|
761
|
+
"""
|
|
762
|
+
Send a geographic location.
|
|
763
|
+
|
|
764
|
+
Arguments
|
|
765
|
+
entity: Who will receive the location.
|
|
766
|
+
latitude: Latitude coordinate.
|
|
767
|
+
longitude: Longitude coordinate.
|
|
768
|
+
|
|
769
|
+
Example
|
|
770
|
+
.. code-block:: python
|
|
771
|
+
|
|
772
|
+
await client.send_location(chat, 35.6892, 51.3890)
|
|
773
|
+
"""
|
|
774
|
+
from ..tl import types
|
|
775
|
+
media = types.InputMediaGeoPoint(
|
|
776
|
+
types.InputGeoPoint(latitude, longitude)
|
|
777
|
+
)
|
|
778
|
+
return await self.send_file(entity, media, **kwargs)
|
|
779
|
+
|
|
780
|
+
async def send_contact(self, entity, phone_number, first_name, last_name='', **kwargs):
|
|
781
|
+
"""
|
|
782
|
+
Send a contact.
|
|
783
|
+
|
|
784
|
+
Arguments
|
|
785
|
+
entity: Who will receive the contact.
|
|
786
|
+
phone_number: Phone number of the contact.
|
|
787
|
+
first_name: First name of the contact.
|
|
788
|
+
last_name: Last name of the contact.
|
|
789
|
+
|
|
790
|
+
Example
|
|
791
|
+
.. code-block:: python
|
|
792
|
+
|
|
793
|
+
await client.send_contact(chat, '+989123456789', 'Ali')
|
|
794
|
+
"""
|
|
795
|
+
from ..tl import types
|
|
796
|
+
media = types.InputMediaContact(
|
|
797
|
+
phone_number=phone_number,
|
|
798
|
+
first_name=first_name,
|
|
799
|
+
last_name=last_name,
|
|
800
|
+
vcard=''
|
|
801
|
+
)
|
|
802
|
+
return await self.send_file(entity, media, **kwargs)
|
|
803
|
+
|
|
804
|
+
async def send_poll(self, entity, question, options, **kwargs):
|
|
805
|
+
"""
|
|
806
|
+
Send a poll.
|
|
807
|
+
|
|
808
|
+
Arguments
|
|
809
|
+
entity: Who will receive the poll.
|
|
810
|
+
question: The poll question.
|
|
811
|
+
options: List of answer options (strings).
|
|
812
|
+
|
|
813
|
+
Example
|
|
814
|
+
.. code-block:: python
|
|
815
|
+
|
|
816
|
+
await client.send_poll(chat, 'Favorite color?', ['Red', 'Blue', 'Green'])
|
|
817
|
+
"""
|
|
818
|
+
from ..tl import types
|
|
819
|
+
poll = types.InputMediaPoll(
|
|
820
|
+
poll=types.Poll(
|
|
821
|
+
id=0,
|
|
822
|
+
question=question,
|
|
823
|
+
answers=[
|
|
824
|
+
types.PollAnswer(text=opt, option=bytes([i]))
|
|
825
|
+
for i, opt in enumerate(options)
|
|
826
|
+
],
|
|
827
|
+
multiple_answers=False,
|
|
828
|
+
closed=False,
|
|
829
|
+
public_voters=False,
|
|
830
|
+
native=True,
|
|
831
|
+
quiz=False
|
|
832
|
+
)
|
|
833
|
+
)
|
|
834
|
+
return await self.send_file(entity, poll, **kwargs)
|
|
835
|
+
|
|
836
|
+
async def send_dice(self, entity, emoji='🎲', **kwargs):
|
|
837
|
+
"""
|
|
838
|
+
Send a dice animation.
|
|
839
|
+
|
|
840
|
+
Arguments
|
|
841
|
+
entity: Who will receive the dice.
|
|
842
|
+
emoji: The emoji for the dice ('🎲', '🏀', '⚽', '🎯', '🎰', '🎳').
|
|
843
|
+
|
|
844
|
+
Example
|
|
845
|
+
.. code-block:: python
|
|
846
|
+
|
|
847
|
+
await client.send_dice(chat)
|
|
848
|
+
await client.send_dice(chat, emoji='🎯')
|
|
849
|
+
"""
|
|
850
|
+
from ..tl import types
|
|
851
|
+
media = types.InputMediaDice(emoji)
|
|
852
|
+
return await self.send_file(entity, media, **kwargs)
|
|
853
|
+
|
|
854
|
+
# endregion
|
|
855
|
+
|
|
856
|
+
# region Convenience methods - Chat Info
|
|
857
|
+
|
|
858
|
+
async def get_chat(self, entity):
|
|
859
|
+
"""
|
|
860
|
+
Get full chat/channel information.
|
|
861
|
+
|
|
862
|
+
Arguments
|
|
863
|
+
entity: The chat or channel entity.
|
|
864
|
+
|
|
865
|
+
Example
|
|
866
|
+
.. code-block:: python
|
|
867
|
+
|
|
868
|
+
chat = await client.get_chat(chat)
|
|
869
|
+
print(chat.title)
|
|
870
|
+
"""
|
|
871
|
+
return await self.get_entity(entity)
|
|
872
|
+
|
|
873
|
+
async def leave_chat(self, entity):
|
|
874
|
+
"""
|
|
875
|
+
Leave a chat or channel.
|
|
876
|
+
|
|
877
|
+
Arguments
|
|
878
|
+
entity: The chat or channel to leave.
|
|
879
|
+
|
|
880
|
+
Example
|
|
881
|
+
.. code-block:: python
|
|
882
|
+
|
|
883
|
+
await client.leave_chat(chat)
|
|
884
|
+
"""
|
|
885
|
+
from .. import helpers
|
|
886
|
+
entity = await self.get_input_entity(entity)
|
|
887
|
+
ty = helpers._entity_type(entity)
|
|
888
|
+
if ty == helpers._EntityType.CHANNEL:
|
|
889
|
+
from ..tl import functions
|
|
890
|
+
return await self(functions.channels.LeaveChannelRequest(entity))
|
|
891
|
+
else:
|
|
892
|
+
from ..tl import functions, types
|
|
893
|
+
return await self(functions.messages.DeleteChatUserRequest(
|
|
894
|
+
entity.chat_id,
|
|
895
|
+
types.InputPeerSelf()
|
|
896
|
+
))
|
|
897
|
+
|
|
898
|
+
async def get_me(self, input_peer=False):
|
|
899
|
+
"""
|
|
900
|
+
Get the current logged-in user.
|
|
901
|
+
|
|
902
|
+
Arguments
|
|
903
|
+
input_peer: If True, return InputPeer instead of User.
|
|
904
|
+
|
|
905
|
+
Example
|
|
906
|
+
.. code-block:: python
|
|
907
|
+
|
|
908
|
+
me = await client.get_me()
|
|
909
|
+
print(me.first_name)
|
|
910
|
+
"""
|
|
911
|
+
return await super().get_me(input_peer=input_peer)
|
|
912
|
+
|
|
913
|
+
async def get_entity(self, *args, **kwargs):
|
|
914
|
+
"""Get an entity by ID, username, phone, or peer."""
|
|
915
|
+
return await super().get_entity(*args, **kwargs)
|
|
916
|
+
|
|
917
|
+
async def get_input_entity(self, *args, **kwargs):
|
|
918
|
+
"""Get an InputPeer for the given entity."""
|
|
919
|
+
return await super().get_input_entity(*args, **kwargs)
|
|
920
|
+
|
|
921
|
+
async def get_peer_id(self, *args, **kwargs):
|
|
922
|
+
"""Get the integer ID for the given entity."""
|
|
923
|
+
return await super().get_peer_id(*args, **kwargs)
|
|
924
|
+
|
|
925
|
+
# endregion
|
|
926
|
+
|
|
927
|
+
# region Convenience methods - Chat Actions
|
|
928
|
+
|
|
929
|
+
async def start_typing(self, entity):
|
|
930
|
+
"""Show typing indicator."""
|
|
931
|
+
return await self.action(entity, 'typing').__aenter__()
|
|
932
|
+
|
|
933
|
+
async def stop_typing(self, entity):
|
|
934
|
+
"""Cancel typing indicator."""
|
|
935
|
+
return await self.action(entity, 'cancel')
|
|
936
|
+
|
|
937
|
+
# endregion
|
|
938
|
+
|
|
939
|
+
# region Convenience methods - File Download
|
|
940
|
+
|
|
941
|
+
async def download_media(self, *args, **kwargs):
|
|
942
|
+
"""Download media from a message."""
|
|
943
|
+
return await super().download_media(*args, **kwargs)
|
|
944
|
+
|
|
945
|
+
async def download_file(self, *args, **kwargs):
|
|
946
|
+
"""Download a file. Alias for download_media."""
|
|
947
|
+
return await self.download_media(*args, **kwargs)
|
|
948
|
+
|
|
949
|
+
# endregion
|
|
950
|
+
|
|
951
|
+
# region Convenience methods - Iterators
|
|
952
|
+
|
|
953
|
+
def iter_messages(self, *args, **kwargs):
|
|
954
|
+
"""Iterator over messages."""
|
|
955
|
+
return super().iter_messages(*args, **kwargs)
|
|
956
|
+
|
|
957
|
+
def iter_participants(self, *args, **kwargs):
|
|
958
|
+
"""Iterator over chat participants."""
|
|
959
|
+
return super().iter_participants(*args, **kwargs)
|
|
960
|
+
|
|
961
|
+
def iter_dialogs(self, *args, **kwargs):
|
|
962
|
+
"""Iterator over dialogs."""
|
|
963
|
+
return super().iter_dialogs(*args, **kwargs)
|
|
964
|
+
|
|
965
|
+
# endregion
|
|
966
|
+
|
|
967
|
+
# region Convenience methods - Aliases
|
|
968
|
+
|
|
969
|
+
# send_message already exists in MessageMethods
|
|
970
|
+
# send_file already exists in UploadMethods
|
|
971
|
+
# edit_message already exists in MessageMethods
|
|
972
|
+
# delete_messages already exists in MessageMethods
|
|
973
|
+
# forward_messages already exists in MessageMethods
|
|
974
|
+
# get_messages already exists in MessageMethods
|
|
975
|
+
# send_read_acknowledge already exists in MessageMethods
|
|
976
|
+
|
|
977
|
+
async def get_messages(self, *args, **kwargs):
|
|
978
|
+
"""Get messages from a chat."""
|
|
979
|
+
return await super().get_messages(*args, **kwargs)
|
|
980
|
+
|
|
981
|
+
async def get_dialogs(self, *args, **kwargs):
|
|
982
|
+
"""Get list of dialogs."""
|
|
983
|
+
return await super().get_dialogs(*args, **kwargs)
|
|
984
|
+
|
|
985
|
+
async def get_participants(self, *args, **kwargs):
|
|
986
|
+
"""Get list of participants."""
|
|
987
|
+
return await super().get_participants(*args, **kwargs)
|
|
988
|
+
|
|
989
|
+
# endregion
|
|
990
|
+
|
|
639
991
|
def __repr__(self):
|
|
640
992
|
connected = self.is_connected()
|
|
641
993
|
try:
|
|
@@ -251,7 +251,7 @@ class TelegramBaseClient(abc.ABC):
|
|
|
251
251
|
local_addr: typing.Union[str, tuple] = None,
|
|
252
252
|
timeout: int = 10,
|
|
253
253
|
request_retries: int = 5,
|
|
254
|
-
connection_retries: int =
|
|
254
|
+
connection_retries: int = 10,
|
|
255
255
|
retry_delay: int = 1,
|
|
256
256
|
auto_reconnect: bool = True,
|
|
257
257
|
sequential_updates: bool = False,
|
|
@@ -680,6 +680,13 @@ class TelegramBaseClient(abc.ABC):
|
|
|
680
680
|
self._updates_handle = self.loop.create_task(self._update_loop())
|
|
681
681
|
self._keepalive_handle = self.loop.create_task(self._keepalive_loop())
|
|
682
682
|
|
|
683
|
+
# Check for library updates in background
|
|
684
|
+
try:
|
|
685
|
+
from ..updater import check_for_updates
|
|
686
|
+
self.loop.create_task(check_for_updates())
|
|
687
|
+
except Exception:
|
|
688
|
+
pass
|
|
689
|
+
|
|
683
690
|
def is_connected(self: 'SoroushClient') -> bool:
|
|
684
691
|
"""
|
|
685
692
|
Returns `True` if the user has connected.
|
|
@@ -313,8 +313,13 @@ class MTProtoSender:
|
|
|
313
313
|
self._log.debug('auth_key generation success!')
|
|
314
314
|
return True
|
|
315
315
|
except (SecurityError, AssertionError) as e:
|
|
316
|
-
|
|
317
|
-
|
|
316
|
+
# Exponential backoff: 2s, 4s, 8s, 16s, 30s (max)
|
|
317
|
+
delay = min(2 ** attempt, 30)
|
|
318
|
+
self._log.warning(
|
|
319
|
+
'Attempt %d at new auth_key failed: %s (retrying in %ds)',
|
|
320
|
+
attempt, e, delay
|
|
321
|
+
)
|
|
322
|
+
await asyncio.sleep(delay)
|
|
318
323
|
return False
|
|
319
324
|
|
|
320
325
|
async def _disconnect(self, error=None):
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Automatic update checker for SPlusPy.
|
|
3
|
+
|
|
4
|
+
Checks PyPI for new versions and prints a notice to the user.
|
|
5
|
+
Non-blocking, runs in background, checks once per session.
|
|
6
|
+
"""
|
|
7
|
+
import asyncio
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
from .version import __version__
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
PYPI_URL = 'https://pypi.org/pypi/spluspy/json'
|
|
15
|
+
_timeout = 10
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _parse_version(version_str):
|
|
19
|
+
"""Parse version string into tuple of ints."""
|
|
20
|
+
try:
|
|
21
|
+
return tuple(int(p) for p in version_str.strip().split('.')[:3])
|
|
22
|
+
except (ValueError, AttributeError):
|
|
23
|
+
return (0, 0, 0)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def check_for_updates():
|
|
27
|
+
"""
|
|
28
|
+
Check PyPI for newer version. Prints notice if update available.
|
|
29
|
+
Runs silently in background, never crashes the app.
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
import urllib.request
|
|
33
|
+
import json
|
|
34
|
+
|
|
35
|
+
loop = asyncio.get_event_loop()
|
|
36
|
+
|
|
37
|
+
def _fetch():
|
|
38
|
+
try:
|
|
39
|
+
req = urllib.request.Request(
|
|
40
|
+
PYPI_URL,
|
|
41
|
+
headers={'Accept': 'application/json'}
|
|
42
|
+
)
|
|
43
|
+
with urllib.request.urlopen(req, timeout=_timeout) as resp:
|
|
44
|
+
data = json.loads(resp.read().decode())
|
|
45
|
+
return data.get('info', {}).get('version')
|
|
46
|
+
except Exception:
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
latest = await asyncio.wait_for(
|
|
50
|
+
loop.run_in_executor(None, _fetch),
|
|
51
|
+
timeout=_timeout
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if not latest:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
current = _parse_version(__version__)
|
|
58
|
+
new = _parse_version(latest)
|
|
59
|
+
|
|
60
|
+
if new > current:
|
|
61
|
+
print(
|
|
62
|
+
f'\n'
|
|
63
|
+
f'========================================\n'
|
|
64
|
+
f' SPlusPy Update Available!\n'
|
|
65
|
+
f' Current version: v{__version__}\n'
|
|
66
|
+
f' Latest version: v{latest}\n'
|
|
67
|
+
f' Update command: pip install -U spluspy=={latest}\n'
|
|
68
|
+
f'========================================\n'
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
except Exception:
|
|
72
|
+
pass # Never let update check crash the app
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spluspy
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Soroush Plus library for Python
|
|
5
5
|
Home-page: https://github.com/Itskillmaster/spluspy
|
|
6
6
|
Download-URL: https://github.com/Itskillmaster/spluspy/releases
|
|
@@ -89,7 +89,7 @@ Install the latest version from PyPI:
|
|
|
89
89
|
|
|
90
90
|
.. code-block:: sh
|
|
91
91
|
|
|
92
|
-
pip install -U
|
|
92
|
+
pip install -U spluspy
|
|
93
93
|
|
|
94
94
|
For faster encryption (recommended):
|
|
95
95
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|