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.
Files changed (164) hide show
  1. {spluspy-1.0.2 → spluspy-1.0.4}/PKG-INFO +2 -2
  2. {spluspy-1.0.2 → spluspy-1.0.4}/README.rst +1 -1
  3. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/auth.py +4 -4
  4. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/soroushclient.py +352 -0
  5. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/telegrambaseclient.py +8 -1
  6. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/mtprotosender.py +7 -2
  7. spluspy-1.0.4/spluspy/updater.py +72 -0
  8. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/version.py +1 -1
  9. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/PKG-INFO +2 -2
  10. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/SOURCES.txt +1 -0
  11. {spluspy-1.0.2 → spluspy-1.0.4}/setup.cfg +0 -0
  12. {spluspy-1.0.2 → spluspy-1.0.4}/setup.py +0 -0
  13. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/__init__.py +0 -0
  14. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/_updates/__init__.py +0 -0
  15. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/_updates/entitycache.py +0 -0
  16. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/_updates/messagebox.py +0 -0
  17. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/_updates/session.py +0 -0
  18. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/__init__.py +0 -0
  19. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/account.py +0 -0
  20. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/bots.py +0 -0
  21. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/buttons.py +0 -0
  22. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/chats.py +0 -0
  23. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/dialogs.py +0 -0
  24. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/downloads.py +0 -0
  25. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/messageparse.py +0 -0
  26. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/messages.py +0 -0
  27. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/ratelimiter.py +0 -0
  28. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/updates.py +0 -0
  29. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/uploads.py +0 -0
  30. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/client/users.py +0 -0
  31. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/__init__.py +0 -0
  32. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/aes.py +0 -0
  33. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/aesctr.py +0 -0
  34. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/authkey.py +0 -0
  35. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/cdndecrypter.py +0 -0
  36. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/factorization.py +0 -0
  37. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/libssl.py +0 -0
  38. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/crypto/rsa.py +0 -0
  39. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/custom.py +0 -0
  40. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/errors/__init__.py +0 -0
  41. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/errors/common.py +0 -0
  42. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/errors/rpcbaseerrors.py +0 -0
  43. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/errors/rpcerrorlist.py +0 -0
  44. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/__init__.py +0 -0
  45. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/album.py +0 -0
  46. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/callbackquery.py +0 -0
  47. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/chataction.py +0 -0
  48. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/common.py +0 -0
  49. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/decorators.py +0 -0
  50. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/inlinequery.py +0 -0
  51. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/messagedeleted.py +0 -0
  52. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/messageedited.py +0 -0
  53. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/messageread.py +0 -0
  54. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/newmessage.py +0 -0
  55. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/raw.py +0 -0
  56. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/events/userupdate.py +0 -0
  57. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/__init__.py +0 -0
  58. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/binaryreader.py +0 -0
  59. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/html.py +0 -0
  60. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/markdown.py +0 -0
  61. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/extensions/messagepacker.py +0 -0
  62. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/functions.py +0 -0
  63. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/helpers.py +0 -0
  64. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/hints.py +0 -0
  65. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/__init__.py +0 -0
  66. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/authenticator.py +0 -0
  67. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/__init__.py +0 -0
  68. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/connection.py +0 -0
  69. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/http.py +0 -0
  70. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpabridged.py +0 -0
  71. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpfull.py +0 -0
  72. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpintermediate.py +0 -0
  73. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpmtproxy.py +0 -0
  74. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/tcpobfuscated.py +0 -0
  75. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/connection/websocket.py +0 -0
  76. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/mtprotoplainsender.py +0 -0
  77. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/mtprotostate.py +0 -0
  78. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/network/requeststate.py +0 -0
  79. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/password.py +0 -0
  80. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/requestiter.py +0 -0
  81. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/__init__.py +0 -0
  82. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/abstract.py +0 -0
  83. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/memory.py +0 -0
  84. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/sqlite.py +0 -0
  85. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sessions/string.py +0 -0
  86. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/sync.py +0 -0
  87. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/__init__.py +0 -0
  88. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/alltlobjects.py +0 -0
  89. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/__init__.py +0 -0
  90. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/gzippacked.py +0 -0
  91. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/messagecontainer.py +0 -0
  92. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/rpcresult.py +0 -0
  93. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/core/tlmessage.py +0 -0
  94. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/__init__.py +0 -0
  95. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/adminlogevent.py +0 -0
  96. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/button.py +0 -0
  97. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/chatgetter.py +0 -0
  98. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/conversation.py +0 -0
  99. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/dialog.py +0 -0
  100. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/draft.py +0 -0
  101. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/file.py +0 -0
  102. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/forward.py +0 -0
  103. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/inlinebuilder.py +0 -0
  104. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/inlineresult.py +0 -0
  105. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/inlineresults.py +0 -0
  106. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/inputsizedfile.py +0 -0
  107. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/message.py +0 -0
  108. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/messagebutton.py +0 -0
  109. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/participantpermissions.py +0 -0
  110. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/qrlogin.py +0 -0
  111. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/sendergetter.py +0 -0
  112. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/custom/types.py +0 -0
  113. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/__init__.py +0 -0
  114. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/account.py +0 -0
  115. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/auth.py +0 -0
  116. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/bots.py +0 -0
  117. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/channels.py +0 -0
  118. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/chatlists.py +0 -0
  119. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/conference.py +0 -0
  120. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/contacts.py +0 -0
  121. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/folders.py +0 -0
  122. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/help.py +0 -0
  123. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/langpack.py +0 -0
  124. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/messages.py +0 -0
  125. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/payments.py +0 -0
  126. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/phone.py +0 -0
  127. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/photos.py +0 -0
  128. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/premium.py +0 -0
  129. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/stats.py +0 -0
  130. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/stories.py +0 -0
  131. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/thirdParty.py +0 -0
  132. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/updates.py +0 -0
  133. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/upload.py +0 -0
  134. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/functions/users.py +0 -0
  135. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/patched/__init__.py +0 -0
  136. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/tlobject.py +0 -0
  137. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/__init__.py +0 -0
  138. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/account.py +0 -0
  139. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/auth.py +0 -0
  140. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/bots.py +0 -0
  141. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/channels.py +0 -0
  142. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/chatlists.py +0 -0
  143. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/conference.py +0 -0
  144. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/contacts.py +0 -0
  145. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/help.py +0 -0
  146. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/messages.py +0 -0
  147. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/payments.py +0 -0
  148. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/phone.py +0 -0
  149. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/photos.py +0 -0
  150. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/premium.py +0 -0
  151. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/stats.py +0 -0
  152. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/stickers.py +0 -0
  153. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/storage.py +0 -0
  154. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/stories.py +0 -0
  155. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/thirdParty.py +0 -0
  156. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/update.py +0 -0
  157. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/updates.py +0 -0
  158. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/upload.py +0 -0
  159. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/tl/types/users.py +0 -0
  160. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/types.py +0 -0
  161. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy/utils.py +0 -0
  162. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/dependency_links.txt +0 -0
  163. {spluspy-1.0.2 → spluspy-1.0.4}/spluspy.egg-info/requires.txt +0 -0
  164. {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.2
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 splusthon
92
+ pip install -U spluspy
93
93
 
94
94
  For faster encryption (recommended):
95
95
 
@@ -49,7 +49,7 @@ Install the latest version from PyPI:
49
49
 
50
50
  .. code-block:: sh
51
51
 
52
- pip install -U splusthon
52
+ pip install -U spluspy
53
53
 
54
54
  For faster encryption (recommended):
55
55
 
@@ -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 enter your phone (or bot token): '),
23
- password: typing.Union[typing.Callable[[], str], str] = lambda: getpass.getpass('Please enter your password: '),
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 enter the code you received: ')
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('enter code: ')
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 = 5,
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
- self._log.warning('Attempt %d at new auth_key failed: %s', attempt, e)
317
- await asyncio.sleep(self._delay)
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,3 +1,3 @@
1
1
  # Versions should comply with PEP440.
2
2
  # This line is parsed in setup.py:
3
- __version__ = '1.0.2'
3
+ __version__ = '1.0.4'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spluspy
3
- Version: 1.0.2
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 splusthon
92
+ pip install -U spluspy
93
93
 
94
94
  For faster encryption (recommended):
95
95
 
@@ -9,6 +9,7 @@ spluspy/password.py
9
9
  spluspy/requestiter.py
10
10
  spluspy/sync.py
11
11
  spluspy/types.py
12
+ spluspy/updater.py
12
13
  spluspy/utils.py
13
14
  spluspy/version.py
14
15
  spluspy.egg-info/PKG-INFO
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