spluspy 2.1.1__tar.gz → 2.1.2__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 (307) hide show
  1. {spluspy-2.1.1 → spluspy-2.1.2}/PKG-INFO +1 -1
  2. {spluspy-2.1.1 → spluspy-2.1.2}/pyproject.toml +1 -1
  3. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/__version__.py +1 -1
  4. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/version.py +1 -1
  5. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/client/chat_mixin.py +466 -0
  6. {spluspy-2.1.1 → spluspy-2.1.2}/.gitignore +0 -0
  7. {spluspy-2.1.1 → spluspy-2.1.2}/CHANGELOG.md +0 -0
  8. {spluspy-2.1.1 → spluspy-2.1.2}/CONTRIBUTING.md +0 -0
  9. {spluspy-2.1.1 → spluspy-2.1.2}/Dockerfile +0 -0
  10. {spluspy-2.1.1 → spluspy-2.1.2}/LICENSE +0 -0
  11. {spluspy-2.1.1 → spluspy-2.1.2}/MANIFEST.in +0 -0
  12. {spluspy-2.1.1 → spluspy-2.1.2}/README.md +0 -0
  13. {spluspy-2.1.1 → spluspy-2.1.2}/README.rst +0 -0
  14. {spluspy-2.1.1 → spluspy-2.1.2}/examples/01_hello_bot.py +0 -0
  15. {spluspy-2.1.1 → spluspy-2.1.2}/examples/02_echo_bot.py +0 -0
  16. {spluspy-2.1.1 → spluspy-2.1.2}/examples/03_command_bot.py +0 -0
  17. {spluspy-2.1.1 → spluspy-2.1.2}/examples/04_private_only.py +0 -0
  18. {spluspy-2.1.1 → spluspy-2.1.2}/examples/05_group_only.py +0 -0
  19. {spluspy-2.1.1 → spluspy-2.1.2}/examples/06_regex_bot.py +0 -0
  20. {spluspy-2.1.1 → spluspy-2.1.2}/examples/07_user_filter.py +0 -0
  21. {spluspy-2.1.1 → spluspy-2.1.2}/examples/08_combined_filters.py +0 -0
  22. {spluspy-2.1.1 → spluspy-2.1.2}/examples/09_inline_keyboard.py +0 -0
  23. {spluspy-2.1.1 → spluspy-2.1.2}/examples/10_reply_keyboard.py +0 -0
  24. {spluspy-2.1.1 → spluspy-2.1.2}/examples/11_message_actions.py +0 -0
  25. {spluspy-2.1.1 → spluspy-2.1.2}/examples/12_media_bot.py +0 -0
  26. {spluspy-2.1.1 → spluspy-2.1.2}/examples/13_fsm_bot.py +0 -0
  27. {spluspy-2.1.1 → spluspy-2.1.2}/examples/14_plugin_bot.py +0 -0
  28. {spluspy-2.1.1 → spluspy-2.1.2}/examples/15_middleware_bot.py +0 -0
  29. {spluspy-2.1.1 → spluspy-2.1.2}/examples/16_scheduler_bot.py +0 -0
  30. {spluspy-2.1.1 → spluspy-2.1.2}/examples/17_conversation.py +0 -0
  31. {spluspy-2.1.1 → spluspy-2.1.2}/examples/18_chat_management.py +0 -0
  32. {spluspy-2.1.1 → spluspy-2.1.2}/examples/19_event_types.py +0 -0
  33. {spluspy-2.1.1 → spluspy-2.1.2}/examples/20_sync_bot.py +0 -0
  34. {spluspy-2.1.1 → spluspy-2.1.2}/examples/21_album_handler.py +0 -0
  35. {spluspy-2.1.1 → spluspy-2.1.2}/examples/22_download_bot.py +0 -0
  36. {spluspy-2.1.1 → spluspy-2.1.2}/examples/23_url_button.py +0 -0
  37. {spluspy-2.1.1 → spluspy-2.1.2}/examples/24_string_session.py +0 -0
  38. {spluspy-2.1.1 → spluspy-2.1.2}/examples/25_error_handling.py +0 -0
  39. {spluspy-2.1.1 → spluspy-2.1.2}/examples/25_working_bot.py +0 -0
  40. {spluspy-2.1.1 → spluspy-2.1.2}/examples/26_message_entities.py +0 -0
  41. {spluspy-2.1.1 → spluspy-2.1.2}/examples/27_search_messages.py +0 -0
  42. {spluspy-2.1.1 → spluspy-2.1.2}/examples/28_poll_bot.py +0 -0
  43. {spluspy-2.1.1 → spluspy-2.1.2}/examples/29_dice_bot.py +0 -0
  44. {spluspy-2.1.1 → spluspy-2.1.2}/examples/30_cache_bot.py +0 -0
  45. {spluspy-2.1.1 → spluspy-2.1.2}/examples/31_reaction_bot.py +0 -0
  46. {spluspy-2.1.1 → spluspy-2.1.2}/examples/32_mark_read_bot.py +0 -0
  47. {spluspy-2.1.1 → spluspy-2.1.2}/examples/33_context_manager.py +0 -0
  48. {spluspy-2.1.1 → spluspy-2.1.2}/examples/34_user_info.py +0 -0
  49. {spluspy-2.1.1 → spluspy-2.1.2}/examples/35_chat_info.py +0 -0
  50. {spluspy-2.1.1 → spluspy-2.1.2}/examples/36_forward_copy.py +0 -0
  51. {spluspy-2.1.1 → spluspy-2.1.2}/examples/37_admin_bot.py +0 -0
  52. {spluspy-2.1.1 → spluspy-2.1.2}/examples/38_media_filters.py +0 -0
  53. {spluspy-2.1.1 → spluspy-2.1.2}/examples/39_status_bot.py +0 -0
  54. {spluspy-2.1.1 → spluspy-2.1.2}/examples/40_delete_detection.py +0 -0
  55. {spluspy-2.1.1 → spluspy-2.1.2}/examples/41_read_detection.py +0 -0
  56. {spluspy-2.1.1 → spluspy-2.1.2}/examples/42_raw_events.py +0 -0
  57. {spluspy-2.1.1 → spluspy-2.1.2}/examples/43_poll_handler.py +0 -0
  58. {spluspy-2.1.1 → spluspy-2.1.2}/examples/44_reaction_handler.py +0 -0
  59. {spluspy-2.1.1 → spluspy-2.1.2}/examples/45_typing_handler.py +0 -0
  60. {spluspy-2.1.1 → spluspy-2.1.2}/examples/46_get_messages.py +0 -0
  61. {spluspy-2.1.1 → spluspy-2.1.2}/examples/47_iter_messages.py +0 -0
  62. {spluspy-2.1.1 → spluspy-2.1.2}/examples/48_get_members.py +0 -0
  63. {spluspy-2.1.1 → spluspy-2.1.2}/examples/49_resolve_username.py +0 -0
  64. {spluspy-2.1.1 → spluspy-2.1.2}/examples/50_invoke.py +0 -0
  65. {spluspy-2.1.1 → spluspy-2.1.2}/setup.py +0 -0
  66. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/__init__.py +0 -0
  67. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/__init__.py +0 -0
  68. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/_updates/__init__.py +0 -0
  69. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/_updates/entitycache.py +0 -0
  70. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/_updates/messagebox.py +0 -0
  71. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/_updates/session.py +0 -0
  72. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/__init__.py +0 -0
  73. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/account.py +0 -0
  74. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/auth.py +0 -0
  75. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/bots.py +0 -0
  76. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/buttons.py +0 -0
  77. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/chats.py +0 -0
  78. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/dialogs.py +0 -0
  79. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/downloads.py +0 -0
  80. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/messageparse.py +0 -0
  81. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/messages.py +0 -0
  82. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/soroushclient.py +0 -0
  83. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/telegrambaseclient.py +0 -0
  84. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/updates.py +0 -0
  85. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/uploads.py +0 -0
  86. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/client/users.py +0 -0
  87. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/__init__.py +0 -0
  88. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/aes.py +0 -0
  89. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/aesctr.py +0 -0
  90. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/authkey.py +0 -0
  91. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/cdndecrypter.py +0 -0
  92. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/factorization.py +0 -0
  93. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/fast_aes.pyx +0 -0
  94. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/fast_rsa.pyx +0 -0
  95. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/libssl.py +0 -0
  96. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/crypto/rsa.py +0 -0
  97. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/custom.py +0 -0
  98. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/errors/__init__.py +0 -0
  99. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/errors/common.py +0 -0
  100. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/errors/rpcbaseerrors.py +0 -0
  101. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/errors/rpcerrorlist.py +0 -0
  102. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/__init__.py +0 -0
  103. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/album.py +0 -0
  104. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/callbackquery.py +0 -0
  105. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/chataction.py +0 -0
  106. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/common.py +0 -0
  107. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/inlinequery.py +0 -0
  108. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/messagedeleted.py +0 -0
  109. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/messageedited.py +0 -0
  110. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/messageread.py +0 -0
  111. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/newmessage.py +0 -0
  112. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/raw.py +0 -0
  113. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/events/userupdate.py +0 -0
  114. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/extensions/__init__.py +0 -0
  115. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/extensions/binaryreader.py +0 -0
  116. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/extensions/html.py +0 -0
  117. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/extensions/markdown.py +0 -0
  118. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/extensions/messagepacker.py +0 -0
  119. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/functions.py +0 -0
  120. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/helpers.py +0 -0
  121. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/hints.py +0 -0
  122. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/__init__.py +0 -0
  123. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/authenticator.py +0 -0
  124. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/__init__.py +0 -0
  125. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/connection.py +0 -0
  126. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/http.py +0 -0
  127. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/tcpabridged.py +0 -0
  128. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/tcpfull.py +0 -0
  129. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/tcpintermediate.py +0 -0
  130. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/tcpmtproxy.py +0 -0
  131. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/tcpobfuscated.py +0 -0
  132. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/connection/websocket.py +0 -0
  133. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/mtprotoplainsender.py +0 -0
  134. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/mtprotosender.py +0 -0
  135. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/mtprotostate.py +0 -0
  136. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/network/requeststate.py +0 -0
  137. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/password.py +0 -0
  138. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/requestiter.py +0 -0
  139. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/sessions/__init__.py +0 -0
  140. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/sessions/abstract.py +0 -0
  141. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/sessions/memory.py +0 -0
  142. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/sessions/sqlite.py +0 -0
  143. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/sessions/string.py +0 -0
  144. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/sync.py +0 -0
  145. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/__init__.py +0 -0
  146. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/alltlobjects.py +0 -0
  147. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/core/__init__.py +0 -0
  148. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/core/gzippacked.py +0 -0
  149. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/core/messagecontainer.py +0 -0
  150. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/core/rpcresult.py +0 -0
  151. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/core/tlmessage.py +0 -0
  152. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/__init__.py +0 -0
  153. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/adminlogevent.py +0 -0
  154. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/button.py +0 -0
  155. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/chatgetter.py +0 -0
  156. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/conversation.py +0 -0
  157. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/dialog.py +0 -0
  158. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/draft.py +0 -0
  159. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/file.py +0 -0
  160. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/forward.py +0 -0
  161. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/inlinebuilder.py +0 -0
  162. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/inlineresult.py +0 -0
  163. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/inlineresults.py +0 -0
  164. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/inputsizedfile.py +0 -0
  165. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/message.py +0 -0
  166. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/messagebutton.py +0 -0
  167. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/participantpermissions.py +0 -0
  168. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/qrlogin.py +0 -0
  169. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/sendergetter.py +0 -0
  170. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/custom/types.py +0 -0
  171. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/__init__.py +0 -0
  172. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/account.py +0 -0
  173. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/auth.py +0 -0
  174. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/bots.py +0 -0
  175. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/channels.py +0 -0
  176. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/chatlists.py +0 -0
  177. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/conference.py +0 -0
  178. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/contacts.py +0 -0
  179. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/folders.py +0 -0
  180. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/help.py +0 -0
  181. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/langpack.py +0 -0
  182. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/messages.py +0 -0
  183. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/payments.py +0 -0
  184. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/phone.py +0 -0
  185. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/photos.py +0 -0
  186. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/premium.py +0 -0
  187. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/stats.py +0 -0
  188. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/stories.py +0 -0
  189. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/thirdParty.py +0 -0
  190. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/updates.py +0 -0
  191. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/upload.py +0 -0
  192. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/functions/users.py +0 -0
  193. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/patched/__init__.py +0 -0
  194. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/tlobject.py +0 -0
  195. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/__init__.py +0 -0
  196. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/account.py +0 -0
  197. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/auth.py +0 -0
  198. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/bots.py +0 -0
  199. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/channels.py +0 -0
  200. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/chatlists.py +0 -0
  201. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/conference.py +0 -0
  202. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/contacts.py +0 -0
  203. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/help.py +0 -0
  204. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/messages.py +0 -0
  205. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/payments.py +0 -0
  206. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/phone.py +0 -0
  207. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/photos.py +0 -0
  208. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/premium.py +0 -0
  209. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/stats.py +0 -0
  210. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/stickers.py +0 -0
  211. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/storage.py +0 -0
  212. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/stories.py +0 -0
  213. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/thirdParty.py +0 -0
  214. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/update.py +0 -0
  215. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/updates.py +0 -0
  216. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/upload.py +0 -0
  217. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/tl/types/users.py +0 -0
  218. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/types.py +0 -0
  219. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/_engine/utils.py +0 -0
  220. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/admin.py +0 -0
  221. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/afk.py +0 -0
  222. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/cli.py +0 -0
  223. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/client/__init__.py +0 -0
  224. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/client/client.py +0 -0
  225. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/client/conversation.py +0 -0
  226. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/client/media_mixin.py +0 -0
  227. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/compat.py +0 -0
  228. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/config.py +0 -0
  229. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/errors/__init__.py +0 -0
  230. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/errors/exceptions.py +0 -0
  231. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/__init__.py +0 -0
  232. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/album.py +0 -0
  233. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/base.py +0 -0
  234. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/callback.py +0 -0
  235. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/chat_action.py +0 -0
  236. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/edited.py +0 -0
  237. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/inline.py +0 -0
  238. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/message.py +0 -0
  239. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/message_deleted.py +0 -0
  240. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/message_read.py +0 -0
  241. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/events/user_update.py +0 -0
  242. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/filters/__init__.py +0 -0
  243. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/filters/filters.py +0 -0
  244. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/fsm/__init__.py +0 -0
  245. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/fsm/state.py +0 -0
  246. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/middleware/__init__.py +0 -0
  247. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/middleware/base.py +0 -0
  248. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/middleware/rate_limit.py +0 -0
  249. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/mirror.py +0 -0
  250. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/models/__init__.py +0 -0
  251. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/models/bot.py +0 -0
  252. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/models/chat.py +0 -0
  253. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/models/enums.py +0 -0
  254. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/models/media.py +0 -0
  255. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/models/message.py +0 -0
  256. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/models/objects.py +0 -0
  257. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/models/user.py +0 -0
  258. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/network/__init__.py +0 -0
  259. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/network/client.py +0 -0
  260. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/network/connection.py +0 -0
  261. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/network/http_client.py +0 -0
  262. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/network/mtproto.py +0 -0
  263. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/network/protocols.py +0 -0
  264. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/network/spluspy_adapter.py +0 -0
  265. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/network/transport.py +0 -0
  266. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/plugins/__init__.py +0 -0
  267. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/plugins/loader.py +0 -0
  268. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/py.typed +0 -0
  269. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/scheduler/__init__.py +0 -0
  270. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/scheduler/scheduler.py +0 -0
  271. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/session/__init__.py +0 -0
  272. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/session/base.py +0 -0
  273. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/session/memory.py +0 -0
  274. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/session/sqlite.py +0 -0
  275. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/session/string.py +0 -0
  276. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/storage/__init__.py +0 -0
  277. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/storage/base.py +0 -0
  278. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/storage/entity_cache.py +0 -0
  279. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/storage/memory.py +0 -0
  280. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/storage/postgres.py +0 -0
  281. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/storage/redis.py +0 -0
  282. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/storage/sqlite.py +0 -0
  283. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/sync/__init__.py +0 -0
  284. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/sync/client.py +0 -0
  285. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/__init__.py +0 -0
  286. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/batch.py +0 -0
  287. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/cache.py +0 -0
  288. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/chat_lock.py +0 -0
  289. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/file_transfer.py +0 -0
  290. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/helpers.py +0 -0
  291. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/logger.py +0 -0
  292. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/rate_limiter.py +0 -0
  293. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/resolver.py +0 -0
  294. {spluspy-2.1.1 → spluspy-2.1.2}/spluspy/utils/version_check.py +0 -0
  295. {spluspy-2.1.1 → spluspy-2.1.2}/tests/__init__.py +0 -0
  296. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_client.py +0 -0
  297. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_filters.py +0 -0
  298. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_fsm.py +0 -0
  299. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_fsm_enhanced.py +0 -0
  300. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_middleware.py +0 -0
  301. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_rate_limiter.py +0 -0
  302. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_resolver.py +0 -0
  303. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_scheduler.py +0 -0
  304. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_session.py +0 -0
  305. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_storage.py +0 -0
  306. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_types.py +0 -0
  307. {spluspy-2.1.1 → spluspy-2.1.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: spluspy
3
- Version: 2.1.1
3
+ Version: 2.1.2
4
4
  Summary: A modern async Python library for interacting with Soroush Plus
5
5
  Project-URL: Homepage, https://github.com/Itskillmaster/spluspy
6
6
  Project-URL: Documentation, https://github.com/Itskillmaster/spluspy#readme
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "spluspy"
7
- version = "2.1.1"
7
+ version = "2.1.2"
8
8
  description = "A modern async Python library for interacting with Soroush Plus"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  """SplusPy version information."""
2
2
 
3
- __version__ = "2.1.1"
3
+ __version__ = "2.1.2"
4
4
  __author__ = "Ali Mirshekari"
5
5
  __license__ = "MIT"
6
6
  __url__ = "https://github.com/Itskillmaster/spluspy"
@@ -1,3 +1,3 @@
1
1
  # Versions should comply with PEP440.
2
2
  # This line is parsed in setup.py:
3
- __version__ = '2.1.1'
3
+ __version__ = '2.1.2'
@@ -398,6 +398,472 @@ class ChatManagementMixin:
398
398
  )
399
399
  return False
400
400
 
401
+ async def set_chat_permissions(
402
+ self,
403
+ chat_id: Union[int, str],
404
+ send_messages: Optional[bool] = None,
405
+ send_media: Optional[bool] = None,
406
+ send_stickers: Optional[bool] = None,
407
+ send_gifs: Optional[bool] = None,
408
+ send_polls: Optional[bool] = None,
409
+ embed_links: Optional[bool] = None,
410
+ invite_users: Optional[bool] = None,
411
+ change_info: Optional[bool] = None,
412
+ pin_messages: Optional[bool] = None,
413
+ ) -> bool:
414
+ """Set the default chat permissions (default banned rights) for a group.
415
+
416
+ Controls what actions regular members are allowed to perform.
417
+ This applies to ALL non-admin members of the group.
418
+
419
+ Args:
420
+ chat_id: Channel/supergroup identifier (int ID, @username, etc.).
421
+ send_messages: ``True`` to ALLOW sending text messages,
422
+ ``False`` to RESTRICT. ``None`` keeps current state.
423
+ send_media: ``True`` to ALLOW sending media (photos, videos, etc.),
424
+ ``False`` to RESTRICT. ``None`` keeps current state.
425
+ send_stickers: ``True`` to ALLOW sending stickers,
426
+ ``False`` to RESTRICT. ``None`` keeps current state.
427
+ send_gifs: ``True`` to ALLOW sending GIFs,
428
+ ``False`` to RESTRICT. ``None`` keeps current state.
429
+ send_polls: ``True`` to ALLOW sending polls,
430
+ ``False`` to RESTRICT. ``None`` keeps current state.
431
+ embed_links: ``True`` to ALLOW embedding links in messages,
432
+ ``False`` to RESTRICT. ``None`` keeps current state.
433
+ invite_users: ``True`` to ALLOW inviting other users,
434
+ ``False`` to RESTRICT. ``None`` keeps current state.
435
+ change_info: ``True`` to ALLOW changing group info,
436
+ ``False`` to RESTRICT. ``None`` keeps current state.
437
+ pin_messages: ``True`` to ALLOW pinning messages,
438
+ ``False`` to RESTRICT. ``None`` keeps current state.
439
+
440
+ Returns:
441
+ ``True`` on success, ``False`` on failure.
442
+
443
+ Note:
444
+ In MTProto, ``ChatBannedRights`` flags are **positive-ban**:
445
+ setting a flag to ``True`` means the user is BANNED from that
446
+ action. This method inverts the semantics so that ``True``
447
+ means "allowed" (intuitive for the developer).
448
+
449
+ Example:
450
+ >>> # Lock everything: no messages, no media, no stickers
451
+ >>> await client.set_chat_permissions(chat_id,
452
+ ... send_messages=False, send_media=False,
453
+ ... send_stickers=False)
454
+ >>>
455
+ >>> # Only restrict media; keep everything else as-is
456
+ >>> await client.set_chat_permissions(chat_id,
457
+ ... send_media=False)
458
+ >>>
459
+ >>> # Unlock everything
460
+ >>> await client.set_chat_permissions(chat_id,
461
+ ... send_messages=True, send_media=True,
462
+ ... send_stickers=True, send_gifs=True,
463
+ ... send_polls=True, embed_links=True,
464
+ ... invite_users=True, change_info=True,
465
+ ... pin_messages=True)
466
+ """
467
+ client = self._get_client()
468
+ if not client:
469
+ logger.warning("set_chat_permissions skipped: client not connected")
470
+ return False
471
+
472
+ try:
473
+ from spluspy._engine import functions, types
474
+ except ImportError:
475
+ from telethon import functions, types
476
+
477
+ try:
478
+ # Resolve chat_id to InputPeer
479
+ input_peer = await self._resolve_to_input_peer(client, chat_id)
480
+ if input_peer is None:
481
+ # Fallback: try get_input_entity directly
482
+ try:
483
+ input_peer = await client.get_input_entity(chat_id)
484
+ except Exception:
485
+ logger.error(
486
+ "set_chat_permissions: cannot resolve %s to InputPeer",
487
+ chat_id,
488
+ )
489
+ return False
490
+
491
+ # Map developer-friendly booleans to MTProto banned-rights.
492
+ # In MTProto: True = BANNED (restricted).
493
+ # Here: True = ALLOWED (not banned), False = RESTRICTED (banned).
494
+ # None means "don't change" (omit from ChatBannedRights).
495
+
496
+ def _to_banned(val: Optional[bool]) -> Optional[bool]:
497
+ """Convert developer-friendly bool to MTProto banned flag.
498
+
499
+ True (allowed) -> False (not banned)
500
+ False (restricted) -> True (banned)
501
+ None -> None (omit)
502
+ """
503
+ if val is None:
504
+ return None
505
+ return not val # Invert: allowed -> not banned, restricted -> banned
506
+
507
+ banned_rights = types.ChatBannedRights(
508
+ until_date=None,
509
+ view_messages=False, # Never restrict viewing messages
510
+ send_messages=_to_banned(send_messages),
511
+ send_media=_to_banned(send_media),
512
+ send_stickers=_to_banned(send_stickers),
513
+ send_gifs=_to_banned(send_gifs),
514
+ send_games=_to_banned(send_media), # Games use media permission
515
+ send_inline=_to_banned(send_media), # Inline bots use media permission
516
+ embed_links=_to_banned(embed_links),
517
+ send_polls=_to_banned(send_polls),
518
+ change_info=_to_banned(change_info),
519
+ invite_users=_to_banned(invite_users),
520
+ pin_messages=_to_banned(pin_messages),
521
+ manage_topics=_to_banned(change_info), # Topics use change_info permission
522
+ send_photos=_to_banned(send_media),
523
+ send_videos=_to_banned(send_media),
524
+ send_roundvideos=_to_banned(send_media),
525
+ send_audios=_to_banned(send_media),
526
+ send_voices=_to_banned(send_media),
527
+ send_docs=_to_banned(send_media),
528
+ send_plain=_to_banned(send_messages),
529
+ )
530
+
531
+ request = functions.messages.EditChatDefaultBannedRightsRequest(
532
+ peer=input_peer,
533
+ banned_rights=banned_rights,
534
+ )
535
+
536
+ await client(request)
537
+ logger.debug(
538
+ "set_chat_permissions: updated default permissions for %s",
539
+ chat_id,
540
+ )
541
+ return True
542
+
543
+ except Exception as exc:
544
+ logger.error(
545
+ "set_chat_permissions(chat=%s) failed: %s",
546
+ chat_id, exc,
547
+ )
548
+ return False
549
+
550
+ async def set_chat_title(
551
+ self,
552
+ chat_id: Union[int, str],
553
+ title: str,
554
+ ) -> bool:
555
+ """Change the title of a channel or supergroup.
556
+
557
+ Uses ``channels.EditTitleRequest`` to update the group/channel name.
558
+
559
+ Args:
560
+ chat_id: Channel/supergroup identifier (int ID, @username, etc.).
561
+ title: New title for the chat (1–128 characters).
562
+
563
+ Returns:
564
+ ``True`` on success, ``False`` on failure.
565
+
566
+ Example:
567
+ >>> await client.set_chat_title(-1001234567890, "New Group Name")
568
+ """
569
+ client = self._get_client()
570
+ if not client:
571
+ logger.warning("set_chat_title skipped: client not connected")
572
+ return False
573
+
574
+ try:
575
+ from spluspy._engine import functions
576
+ except ImportError:
577
+ from telethon import functions
578
+
579
+ try:
580
+ input_channel = await self._resolve_to_input_channel(client, chat_id)
581
+ if input_channel is None:
582
+ logger.error("set_chat_title: cannot resolve %s to InputChannel", chat_id)
583
+ return False
584
+
585
+ request = functions.channels.EditTitleRequest(
586
+ channel=input_channel,
587
+ title=title,
588
+ )
589
+ await client(request)
590
+ logger.debug("set_chat_title: updated title for %s", chat_id)
591
+ return True
592
+
593
+ except Exception as exc:
594
+ logger.error("set_chat_title(chat=%s) failed: %s", chat_id, exc)
595
+ return False
596
+
597
+ async def set_chat_about(
598
+ self,
599
+ chat_id: Union[int, str],
600
+ about: str,
601
+ ) -> bool:
602
+ """Change the about/description text of a chat.
603
+
604
+ Uses ``messages.EditChatAboutRequest`` to update the chat bio.
605
+ Works for both basic groups and supergroups/channels.
606
+
607
+ Args:
608
+ chat_id: Chat identifier (int ID, @username, etc.).
609
+ about: New about text (0–70 characters). Pass empty string to clear.
610
+
611
+ Returns:
612
+ ``True`` on success, ``False`` on failure.
613
+
614
+ Example:
615
+ >>> await client.set_chat_about(-1001234567890, "Welcome to our group!")
616
+ """
617
+ client = self._get_client()
618
+ if not client:
619
+ logger.warning("set_chat_about skipped: client not connected")
620
+ return False
621
+
622
+ try:
623
+ from spluspy._engine import functions
624
+ except ImportError:
625
+ from telethon import functions
626
+
627
+ try:
628
+ input_peer = await self._resolve_to_input_peer(client, chat_id)
629
+ if input_peer is None:
630
+ # Fallback: try get_input_entity directly
631
+ try:
632
+ input_peer = await client.get_input_entity(chat_id)
633
+ except Exception:
634
+ logger.error("set_chat_about: cannot resolve %s to InputPeer", chat_id)
635
+ return False
636
+
637
+ request = functions.messages.EditChatAboutRequest(
638
+ peer=input_peer,
639
+ about=about,
640
+ )
641
+ await client(request)
642
+ logger.debug("set_chat_about: updated about for %s", chat_id)
643
+ return True
644
+
645
+ except Exception as exc:
646
+ logger.error("set_chat_about(chat=%s) failed: %s", chat_id, exc)
647
+ return False
648
+
649
+ async def set_chat_photo(
650
+ self,
651
+ chat_id: Union[int, str],
652
+ file_path: str,
653
+ ) -> bool:
654
+ """Upload and set a new photo for a channel or supergroup.
655
+
656
+ Reads the photo from *file_path*, uploads it to Telegram servers,
657
+ then applies it via ``channels.EditPhotoRequest``.
658
+
659
+ Args:
660
+ chat_id: Channel/supergroup identifier (int ID, @username, etc.).
661
+ file_path: Local filesystem path to the image file
662
+ (JPEG, PNG, or GIF recommended).
663
+
664
+ Returns:
665
+ ``True`` on success, ``False`` on failure.
666
+
667
+ Example:
668
+ >>> await client.set_chat_photo(-1001234567890, "/path/to/photo.jpg")
669
+ """
670
+ client = self._get_client()
671
+ if not client:
672
+ logger.warning("set_chat_photo skipped: client not connected")
673
+ return False
674
+
675
+ try:
676
+ from spluspy._engine import functions, types
677
+ except ImportError:
678
+ from telethon import functions, types
679
+
680
+ try:
681
+ input_channel = await self._resolve_to_input_channel(client, chat_id)
682
+ if input_channel is None:
683
+ logger.error("set_chat_photo: cannot resolve %s to InputChannel", chat_id)
684
+ return False
685
+
686
+ # Read and upload the photo file
687
+ import os
688
+ import hashlib
689
+
690
+ file_path_str = str(file_path)
691
+ file_size = os.path.getsize(file_path_str)
692
+ file_name = os.path.basename(file_path_str)
693
+
694
+ with open(file_path_str, "rb") as f:
695
+ file_data = f.read()
696
+
697
+ # Use client's built-in upload helper if available,
698
+ # otherwise do a manual upload via upload.saveFilePart
699
+ file_id = int.from_bytes(os.urandom(8), "big", signed=True)
700
+ CHUNK_SIZE = 512 * 1024 # 512 KB per part
701
+ total_parts = max(1, (file_size + CHUNK_SIZE - 1) // CHUNK_SIZE)
702
+
703
+ for part_idx in range(total_parts):
704
+ offset = part_idx * CHUNK_SIZE
705
+ chunk = file_data[offset:offset + CHUNK_SIZE]
706
+
707
+ if total_parts > 1:
708
+ result = await client(functions.upload.SaveBigFilePartRequest(
709
+ file_id=file_id,
710
+ file_part=part_idx,
711
+ file_total_parts=total_parts,
712
+ bytes=chunk,
713
+ ))
714
+ else:
715
+ result = await client(functions.upload.SaveFilePartRequest(
716
+ file_id=file_id,
717
+ file_part=part_idx,
718
+ bytes=chunk,
719
+ ))
720
+
721
+ if not result:
722
+ logger.error("set_chat_photo: upload failed at part %d", part_idx)
723
+ return False
724
+
725
+ uploaded_file = types.InputFile(
726
+ id=file_id,
727
+ parts=total_parts,
728
+ name=file_name,
729
+ md5_checksum="",
730
+ )
731
+
732
+ photo_obj = types.InputChatUploadedPhoto(file=uploaded_file)
733
+
734
+ request = functions.channels.EditPhotoRequest(
735
+ channel=input_channel,
736
+ photo=photo_obj,
737
+ )
738
+ await client(request)
739
+ logger.debug("set_chat_photo: updated photo for %s", chat_id)
740
+ return True
741
+
742
+ except Exception as exc:
743
+ logger.error("set_chat_photo(chat=%s) failed: %s", chat_id, exc)
744
+ return False
745
+
746
+ async def start_group_call(
747
+ self,
748
+ chat_id: Union[int, str],
749
+ title: Optional[str] = None,
750
+ ) -> bool:
751
+ """Start a new group call (voice chat) in a supergroup.
752
+
753
+ Uses ``phone.CreateGroupCallRequest`` to initiate the call.
754
+ The caller must have admin rights with ``manage_call`` enabled.
755
+
756
+ Args:
757
+ chat_id: Supergroup/channel identifier (int ID, @username, etc.).
758
+ title: Optional title for the group call (e.g. "Team Meeting").
759
+
760
+ Returns:
761
+ ``True`` on success, ``False`` on failure.
762
+
763
+ Raises:
764
+ No exceptions — errors are caught and logged.
765
+
766
+ Example:
767
+ >>> await client.start_group_call(-1001234567890, title="Daily Standup")
768
+ """
769
+ client = self._get_client()
770
+ if not client:
771
+ logger.warning("start_group_call skipped: client not connected")
772
+ return False
773
+
774
+ try:
775
+ from spluspy._engine import functions
776
+ except ImportError:
777
+ from telethon import functions
778
+
779
+ try:
780
+ input_peer = await self._resolve_to_input_peer(client, chat_id)
781
+ if input_peer is None:
782
+ # Fallback: try get_input_entity directly
783
+ try:
784
+ input_peer = await client.get_input_entity(chat_id)
785
+ except Exception:
786
+ logger.error("start_group_call: cannot resolve %s to InputPeer", chat_id)
787
+ return False
788
+
789
+ import os
790
+ random_id = int.from_bytes(os.urandom(4), "big", signed=True)
791
+
792
+ request = functions.phone.CreateGroupCallRequest(
793
+ peer=input_peer,
794
+ random_id=random_id,
795
+ title=title,
796
+ )
797
+ await client(request)
798
+ logger.debug("start_group_call: started call in %s", chat_id)
799
+ return True
800
+
801
+ except Exception as exc:
802
+ logger.error("start_group_call(chat=%s) failed: %s", chat_id, exc)
803
+ return False
804
+
805
+ async def stop_group_call(
806
+ self,
807
+ chat_id: Union[int, str],
808
+ ) -> bool:
809
+ """Stop (discard) an active group call in a supergroup.
810
+
811
+ Fetches the current group call via ``channels.GetFullChannelRequest``,
812
+ extracts the ``InputGroupCall`` from the ``full_chat.call`` attribute,
813
+ and sends ``phone.DiscardGroupCallRequest`` to end it.
814
+
815
+ Args:
816
+ chat_id: Supergroup/channel identifier (int ID, @username, etc.).
817
+
818
+ Returns:
819
+ ``True`` on success, ``False`` on failure (including when no
820
+ active call exists).
821
+
822
+ Example:
823
+ >>> await client.stop_group_call(-1001234567890)
824
+ """
825
+ client = self._get_client()
826
+ if not client:
827
+ logger.warning("stop_group_call skipped: client not connected")
828
+ return False
829
+
830
+ try:
831
+ from spluspy._engine import functions, types
832
+ except ImportError:
833
+ from telethon import functions, types
834
+
835
+ try:
836
+ input_channel = await self._resolve_to_input_channel(client, chat_id)
837
+ if input_channel is None:
838
+ logger.error("stop_group_call: cannot resolve %s to InputChannel", chat_id)
839
+ return False
840
+
841
+ # Fetch full channel info to get the active group call
842
+ full_chat_result = await client(functions.channels.GetFullChannelRequest(
843
+ channel=input_channel,
844
+ ))
845
+
846
+ full_chat = getattr(full_chat_result, "full_chat", None)
847
+ if full_chat is None:
848
+ logger.warning("stop_group_call: no full_chat returned for %s", chat_id)
849
+ return False
850
+
851
+ input_group_call = getattr(full_chat, "call", None)
852
+ if input_group_call is None:
853
+ logger.warning("stop_group_call: no active group call in %s", chat_id)
854
+ return False
855
+
856
+ request = functions.phone.DiscardGroupCallRequest(
857
+ call=input_group_call,
858
+ )
859
+ await client(request)
860
+ logger.debug("stop_group_call: stopped call in %s", chat_id)
861
+ return True
862
+
863
+ except Exception as exc:
864
+ logger.error("stop_group_call(chat=%s) failed: %s", chat_id, exc)
865
+ return False
866
+
401
867
  # ── Helper Methods ────────────────────────────────────────────
402
868
 
403
869
  async def _resolve_to_input_channel(
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