Rubka 7.2.8__py3-none-any.whl

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 (45) hide show
  1. rubka/__init__.py +79 -0
  2. rubka/adaptorrubka/__init__.py +4 -0
  3. rubka/adaptorrubka/client/__init__.py +1 -0
  4. rubka/adaptorrubka/client/client.py +60 -0
  5. rubka/adaptorrubka/crypto/__init__.py +1 -0
  6. rubka/adaptorrubka/crypto/crypto.py +82 -0
  7. rubka/adaptorrubka/enums.py +36 -0
  8. rubka/adaptorrubka/exceptions.py +22 -0
  9. rubka/adaptorrubka/methods/__init__.py +1 -0
  10. rubka/adaptorrubka/methods/methods.py +90 -0
  11. rubka/adaptorrubka/network/__init__.py +3 -0
  12. rubka/adaptorrubka/network/helper.py +22 -0
  13. rubka/adaptorrubka/network/network.py +221 -0
  14. rubka/adaptorrubka/network/socket.py +31 -0
  15. rubka/adaptorrubka/sessions/__init__.py +1 -0
  16. rubka/adaptorrubka/sessions/sessions.py +72 -0
  17. rubka/adaptorrubka/types/__init__.py +1 -0
  18. rubka/adaptorrubka/types/socket/__init__.py +1 -0
  19. rubka/adaptorrubka/types/socket/message.py +187 -0
  20. rubka/adaptorrubka/utils/__init__.py +2 -0
  21. rubka/adaptorrubka/utils/configs.py +18 -0
  22. rubka/adaptorrubka/utils/utils.py +251 -0
  23. rubka/api.py +1723 -0
  24. rubka/asynco.py +2541 -0
  25. rubka/button.py +404 -0
  26. rubka/config.py +3 -0
  27. rubka/context.py +1077 -0
  28. rubka/decorators.py +30 -0
  29. rubka/exceptions.py +37 -0
  30. rubka/filters.py +330 -0
  31. rubka/helpers.py +1461 -0
  32. rubka/jobs.py +15 -0
  33. rubka/keyboards.py +16 -0
  34. rubka/keypad.py +298 -0
  35. rubka/logger.py +12 -0
  36. rubka/metadata.py +114 -0
  37. rubka/rubino.py +1271 -0
  38. rubka/tv.py +145 -0
  39. rubka/update.py +1038 -0
  40. rubka/utils.py +3 -0
  41. rubka-7.2.8.dist-info/METADATA +1047 -0
  42. rubka-7.2.8.dist-info/RECORD +45 -0
  43. rubka-7.2.8.dist-info/WHEEL +5 -0
  44. rubka-7.2.8.dist-info/entry_points.txt +2 -0
  45. rubka-7.2.8.dist-info/top_level.txt +1 -0
rubka/context.py ADDED
@@ -0,0 +1,1077 @@
1
+ from typing import Union
2
+ from pathlib import Path
3
+ from typing import List, Optional, Dict, Any, Literal, Callable, Union,Set
4
+ import re,inspect
5
+ import asyncio
6
+ _EMOJI_PATTERN = re.compile(
7
+ "["
8
+ "\U0001F300-\U0001F5FF"
9
+ "\U0001F600-\U0001F64F"
10
+ "\U0001F680-\U0001F6FF"
11
+ "\U0001F700-\U0001F77F"
12
+ "\U0001F780-\U0001F7FF"
13
+ "\U0001F800-\U0001F8FF"
14
+ "\U0001F900-\U0001F9FF"
15
+ "\U0001FA00-\U0001FA6F"
16
+ "\U0001FA70-\U0001FAFF"
17
+ "\U00002700-\U000027BF"
18
+ "\U00002600-\U000026FF"
19
+ "\U00002000-\U000023FF"
20
+ "]+",
21
+ flags=re.UNICODE
22
+ )
23
+
24
+ def contains_emoji(text: str) -> bool:
25
+ if not text:return False
26
+ return bool(_EMOJI_PATTERN.search(text))
27
+
28
+ def count_emojis(text: str) -> int:
29
+ if not text:return 0
30
+ return len(_EMOJI_PATTERN.findall(text))
31
+ def contains_link_or_mention(text: str) -> bool:
32
+ if not text:return False
33
+ pattern = re.compile(
34
+ r"(?i)\b("
35
+ r"https?://[^\s]+"
36
+ r"|www\.[^\s]+"
37
+ r"|[a-zA-Z0-9.-]+\.(com|net|org|ir|edu|gov|info|biz|io|me|co|xyz|in|us|uk|ru|tv|cc|app|dev|site|store|cloud|shop)"
38
+ r"|t\.me/[^\s]+"
39
+ r"|telegram\.me/[^\s]+"
40
+ r"|rubika\.(ir|app)/[^\s]+"
41
+ r"|whatsapp\.com/[^\s]+"
42
+ r"|wa\.me/[^\s]+"
43
+ r"|instagram\.com/[^\s]+"
44
+ r"|instagr\.am/[^\s]+"
45
+ r"|youtube\.com/[^\s]+"
46
+ r"|youtu\.be/[^\s]+"
47
+ r"|aparat\.com/[^\s]+"
48
+ r"|discord\.gg/[^\s]+"
49
+ r"|discord\.com/[^\s]+"
50
+ r"|splus\.ir/[^\s]+"
51
+ r"|eitaa\.com/[^\s]+"
52
+ r"|ble\.ir/[^\s]+"
53
+ r"|gap\.im/[^\s]+"
54
+ r"|rubino\.ir/[^\s]+"
55
+ r"|pin\.it/[^\s]+"
56
+ r"|twitter\.com/[^\s]+"
57
+ r"|x\.com/[^\s]+"
58
+ r"|facebook\.com/[^\s]+"
59
+ r"|threads\.net/[^\s]+"
60
+ r"|@\w+"
61
+ r")\b"
62
+ )
63
+ return bool(pattern.search(text))
64
+ class File:
65
+ def __init__(self, data: dict):
66
+ self.file_id: str = data.get("file_id")
67
+ self.file_name: str = data.get("file_name")
68
+ self.size: str = data.get("size")
69
+
70
+
71
+ class Sticker:
72
+ def __init__(self, data: dict):
73
+ self.sticker_id: str = data.get("sticker_id")
74
+ self.emoji_character: str = data.get("emoji_character")
75
+ self.file = File(data.get("file", {}))
76
+
77
+
78
+
79
+
80
+
81
+ class PollStatus:
82
+ def __init__(self, data: dict):
83
+ self.state: str = data.get("state")
84
+ self.selection_index: int = data.get("selection_index")
85
+ self.percent_vote_options: List[int] = data.get("percent_vote_options", [])
86
+ self.total_vote: int = data.get("total_vote")
87
+ self.show_total_votes: bool = data.get("show_total_votes")
88
+
89
+
90
+ class Poll:
91
+ def __init__(self, data: dict):
92
+ self.question: str = data.get("question")
93
+ self.options: List[str] = data.get("options", [])
94
+ self.poll_status = PollStatus(data.get("poll_status", {}))
95
+
96
+
97
+
98
+
99
+
100
+ class Location:
101
+ def __init__(self, data: dict):
102
+ self.latitude: str = data.get("latitude")
103
+ self.longitude: str = data.get("longitude")
104
+
105
+
106
+ class LiveLocation:
107
+ def __init__(self, data: dict):
108
+ self.start_time: str = data.get("start_time")
109
+ self.live_period: int = data.get("live_period")
110
+ self.current_location = Location(data.get("current_location", {}))
111
+ self.user_id: str = data.get("user_id")
112
+ self.status: str = data.get("status")
113
+ self.last_update_time: str = data.get("last_update_time")
114
+
115
+
116
+ class ContactMessage:
117
+ def __init__(self, data: dict):
118
+ self.phone_number: str = data.get("phone_number")
119
+ self.first_name: str = data.get("first_name")
120
+ self.last_name: str = data.get("last_name")
121
+
122
+
123
+ class ForwardedFrom:
124
+ def __init__(self, data: dict):
125
+ self.type_from: str = data.get("type_from")
126
+ self.message_id: str = data.get("message_id")
127
+ self.from_chat_id: str = data.get("from_chat_id")
128
+ self.from_sender_id: str = data.get("from_sender_id")
129
+
130
+
131
+
132
+
133
+
134
+ class AuxData:
135
+ def __init__(self, data: dict):
136
+ self.start_id: str = data.get("start_id")
137
+ self.button_id: str = data.get("button_id")
138
+
139
+
140
+
141
+
142
+
143
+ class ButtonTextbox:
144
+ def __init__(self, data: dict):
145
+ self.type_line: str = data.get("type_line")
146
+ self.type_keypad: str = data.get("type_keypad")
147
+ self.place_holder: Optional[str] = data.get("place_holder")
148
+ self.title: Optional[str] = data.get("title")
149
+ self.default_value: Optional[str] = data.get("default_value")
150
+
151
+
152
+ class ButtonNumberPicker:
153
+ def __init__(self, data: dict):
154
+ self.min_value: str = data.get("min_value")
155
+ self.max_value: str = data.get("max_value")
156
+ self.default_value: Optional[str] = data.get("default_value")
157
+ self.title: str = data.get("title")
158
+
159
+
160
+ class ButtonStringPicker:
161
+ def __init__(self, data: dict):
162
+ self.items: List[str] = data.get("items", [])
163
+ self.default_value: Optional[str] = data.get("default_value")
164
+ self.title: Optional[str] = data.get("title")
165
+
166
+
167
+ class ButtonCalendar:
168
+ def __init__(self, data: dict):
169
+ self.default_value: Optional[str] = data.get("default_value")
170
+ self.type: str = data.get("type")
171
+ self.min_year: str = data.get("min_year")
172
+ self.max_year: str = data.get("max_year")
173
+ self.title: str = data.get("title")
174
+
175
+
176
+ class ButtonLocation:
177
+ def __init__(self, data: dict):
178
+ self.default_pointer_location = Location(data.get("default_pointer_location", {}))
179
+ self.default_map_location = Location(data.get("default_map_location", {}))
180
+ self.type: str = data.get("type")
181
+ self.title: Optional[str] = data.get("title")
182
+ self.location_image_url: str = data.get("location_image_url")
183
+
184
+
185
+ class ButtonSelectionItem:
186
+ def __init__(self, data: dict):
187
+ self.text: str = data.get("text")
188
+ self.image_url: str = data.get("image_url")
189
+ self.type: str = data.get("type")
190
+
191
+
192
+ class ButtonSelection:
193
+ def __init__(self, data: dict):
194
+ self.selection_id: str = data.get("selection_id")
195
+ self.search_type: str = data.get("search_type")
196
+ self.get_type: str = data.get("get_type")
197
+ self.items: List[ButtonSelectionItem] = [ButtonSelectionItem(i) for i in data.get("items", [])]
198
+ self.is_multi_selection: bool = data.get("is_multi_selection")
199
+ self.columns_count: str = data.get("columns_count")
200
+ self.title: str = data.get("title")
201
+
202
+
203
+ class Button:
204
+ def __init__(self, data: dict):
205
+ self.id: str = data.get("id")
206
+ self.type: str = data.get("type")
207
+ self.button_text: str = data.get("button_text")
208
+ self.button_selection = ButtonSelection(data.get("button_selection", {})) if "button_selection" in data else None
209
+ self.button_calendar = ButtonCalendar(data.get("button_calendar", {})) if "button_calendar" in data else None
210
+ self.button_number_picker = ButtonNumberPicker(data.get("button_number_picker", {})) if "button_number_picker" in data else None
211
+ self.button_string_picker = ButtonStringPicker(data.get("button_string_picker", {})) if "button_string_picker" in data else None
212
+ self.button_location = ButtonLocation(data.get("button_location", {})) if "button_location" in data else None
213
+ self.button_textbox = ButtonTextbox(data.get("button_textbox", {})) if "button_textbox" in data else None
214
+
215
+
216
+ class KeypadRow:
217
+ def __init__(self, data: dict):
218
+ self.buttons: List[Button] = [Button(btn) for btn in data.get("buttons", [])]
219
+
220
+
221
+ class Keypad:
222
+ def __init__(self, data: dict):
223
+ self.rows: List[KeypadRow] = [KeypadRow(r) for r in data.get("rows", [])]
224
+ self.resize_keyboard: bool = data.get("resize_keyboard", False)
225
+ self.on_time_keyboard: bool = data.get("on_time_keyboard", False)
226
+
227
+
228
+ class Chat:
229
+ def __init__(self, data: dict):
230
+ self.chat_id: str = data.get("chat_id")
231
+ self.chat_type: str = data.get("chat_type")
232
+ self.user_id: str = data.get("user_id")
233
+ self.first_name: str = data.get("first_name")
234
+ self.last_name: str = data.get("last_name")
235
+ self.title: str = data.get("title")
236
+ self.username: str = data.get("username")
237
+
238
+
239
+ class Bot:
240
+ def __init__(self, data: dict):
241
+ self.bot_id: str = data.get("bot_id")
242
+ self.bot_title: str = data.get("bot_title")
243
+ self.avatar = File(data.get("avatar", {}))
244
+ self.description: str = data.get("description")
245
+ self.username: str = data.get("username")
246
+ self.start_message: str = data.get("start_message")
247
+ self.share_url: str = data.get("share_url")
248
+
249
+ class hybrid_property:
250
+ def __init__(self, func):
251
+ self.func = func
252
+
253
+ def __get__(self, instance, owner):
254
+ if instance is None:
255
+ return self
256
+ coro = self.func(instance)
257
+ try:
258
+ loop = asyncio.get_running_loop()
259
+ return coro
260
+ except RuntimeError:
261
+ try:
262
+ loop = asyncio.get_event_loop()
263
+ except RuntimeError:
264
+ loop = asyncio.new_event_loop()
265
+ asyncio.set_event_loop(loop)
266
+ return loop.run_until_complete(coro)
267
+ class Message:
268
+ def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
269
+ self.bot = bot
270
+ self.raw_data = raw_data or {}
271
+ self.chat_id = chat_id
272
+ self.object_guid = chat_id
273
+ self.author_guid = self.raw_data.get("sender_id", sender_id)
274
+ self.message_id: str = self.raw_data.get("message_id", message_id)
275
+ self.text: str = self.raw_data.get("text", text)
276
+ self.has_link = contains_link_or_mention(self.raw_data.get("text", text))
277
+ self.is_link = self.has_link
278
+ self.is_mention = bool(re.search(r"@\w+", self.raw_data.get("text", text) or ""))
279
+ self.is_hashtag = bool(re.search(r"#\w+", text or ""))
280
+ self.is_number = bool(re.search(r"\d+", text or ""))
281
+ self.is_emoji = contains_emoji(self.raw_data.get("text", text))
282
+ self.emoji_count = count_emojis(self.raw_data.get("text", text))
283
+ self.is_pure_emoji = bool(self.is_emoji and self.emoji_count == len(self.text))
284
+ self.is_photo = None
285
+ self.is_video = None
286
+ self.is_gif = None
287
+ self.is_audio = None
288
+ self.is_voice = None
289
+ self.is_document = None
290
+ self.is_music = None
291
+ self.is_archive = None
292
+ self.is_executable = None
293
+ self.is_font = None
294
+ self.metadata = self.raw_data.get("metadata", {})
295
+ self.is_metadata = self.metadata
296
+ self.meta_parts = self.metadata.get("meta_data_parts", [])
297
+ self.has_metadata = bool(self.meta_parts)
298
+ self.meta_types = [part.get("type") for part in self.meta_parts] if self.has_metadata else []
299
+ self.is_bold = "Bold" in self.meta_types
300
+ self.is_italic = "Italic" in self.meta_types
301
+ self.is_strike = "Strike" in self.meta_types
302
+ self.is_underline = "Underline" in self.meta_types
303
+ self.is_quote = "Quote" in self.meta_types
304
+ self.is_spoiler = "Spoiler" in self.meta_types
305
+ self.is_pre = "Pre" in self.meta_types
306
+ self.is_mono = "Mono" in self.meta_types
307
+ self.is_link_meta = "Link" in self.meta_types
308
+ self.meta_links = [part.get("link_url") for part in self.meta_parts if part.get("type") == "Link"]
309
+ self.meta_link_positions = [
310
+ {"from": part.get("from_index"), "length": part.get("length"), "url": part.get("link_url")}
311
+ for part in self.meta_parts if part.get("type") == "Link"
312
+ ]
313
+ self.has_link = contains_link_or_mention(self.text) or self.is_link_meta
314
+ self.is_formatted = any([
315
+ self.is_bold,
316
+ self.is_italic,
317
+ self.is_strike,
318
+ self.is_underline,
319
+ self.is_quote,
320
+ self.is_spoiler,
321
+ self.is_pre,
322
+ self.is_mono
323
+ ])
324
+ self.sender_id: str = self.raw_data.get("sender_id", sender_id)
325
+ self.time: str = self.raw_data.get("time")
326
+ self.is_edited: bool = self.raw_data.get("is_edited", False)
327
+ self.sender_type: str = self.raw_data.get("sender_type")
328
+ self.args = []
329
+ self.is_command = bool(self.text and self.text.startswith("/"))
330
+ self.is_user = self.chat_id.startswith("b")
331
+ self.is_private = self.chat_id.startswith("b")
332
+ self.is_group = self.chat_id.startswith("g")
333
+ self.is_channel = self.chat_id.startswith("c")
334
+ self.reply_to_message_id: Optional[str] = self.raw_data.get("reply_to_message_id")
335
+ self.forwarded_from = ForwardedFrom(self.raw_data["forwarded_from"]) if "forwarded_from" in self.raw_data else None
336
+ self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
337
+ self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
338
+ self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
339
+ self.poll = Poll(self.raw_data["poll"]) if "poll" in self.raw_data else None
340
+ self.poll_data = self.raw_data.get("poll", {})
341
+ self.poll_question = self.poll_data.get("question", "")
342
+ self.poll_options = self.poll_data.get("options", [])
343
+ self.poll_status = self.poll_data.get("poll_status", {})
344
+ self.poll_state = self.poll_status.get("state", None)
345
+ self.poll_selection_index = self.poll_status.get("selection_index", None)
346
+ self.poll_percent_vote_options = self.poll_status.get("percent_vote_options", None)
347
+ self.poll_total_vote = self.poll_status.get("total_vote", None)
348
+ self.poll_show_total_votes = self.poll_status.get("show_total_votes", None)
349
+ self.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
350
+ self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
351
+ self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
352
+ self.is_reply = self.reply_to_message_id is not None
353
+ self.has_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
354
+ self.is_forwarded = self.forwarded_from is not None
355
+ self.is_text = bool(self.text and not self.has_media)
356
+ self.is_media = self.has_media
357
+ self.is_poll = self.poll is not None
358
+ self.is_location = self.location is not None
359
+ self.is_live_location = self.live_location is not None
360
+ self.is_contact = self.contact_message is not None
361
+ self.has_buttons = "buttons" in self.raw_data
362
+ self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
363
+ self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
364
+ if self.file and self.file.file_name:
365
+ name = self.file.file_name.lower()
366
+ size = getattr(self.file, "size", 0)
367
+ self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
368
+ self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
369
+ self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
370
+ self.is_music = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
371
+ self.is_voice = name.endswith((".ogg", ".m4a"))
372
+ self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
373
+ self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
374
+ self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
375
+ self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
376
+ self.is_gif = name.endswith(".mp4") or (1024 <= size <= 1_048_000)
377
+ @property
378
+ def session(self):
379
+ if self.chat_id not in self.bot.sessions:
380
+ self.bot.sessions[self.chat_id] = {}
381
+ return self.bot.sessions[self.chat_id]
382
+
383
+ def reply(self, text: str, delete_after: int = None,parse_mode : Optional[Literal["HTML", "Markdown"]] = None , **kwargs):
384
+ async def _reply_async():
385
+ send_func = self.bot.send_message
386
+ if inspect.iscoroutinefunction(send_func):
387
+ msg = await send_func(
388
+ self.chat_id,
389
+ text,
390
+ reply_to_message_id=self.message_id,
391
+ delete_after=delete_after,
392
+ parse_mode=parse_mode,
393
+ **kwargs
394
+ )
395
+ else:
396
+ msg = send_func(
397
+ self.chat_id,
398
+ text,
399
+ reply_to_message_id=self.message_id,
400
+ delete_after=delete_after,
401
+ **kwargs
402
+ )
403
+ class Pick:
404
+ def __init__(self, bot, chat_id, message_id):
405
+ self.bot = bot
406
+ self.chat_id = chat_id
407
+ self.message_id = message_id
408
+
409
+ def edit(self, new_text):
410
+ async def _edit():
411
+ func = self.bot.edit_message_text
412
+ if inspect.iscoroutinefunction(func):
413
+ await func(self.chat_id, self.message_id, new_text)
414
+ else:
415
+ func(self.chat_id, self.message_id, new_text)
416
+
417
+ try:
418
+ loop = asyncio.get_running_loop()
419
+ if loop.is_running():
420
+ return asyncio.create_task(_edit())
421
+ except RuntimeError:
422
+ return asyncio.run(_edit())
423
+
424
+ def delete(self):
425
+ async def _delete():
426
+ func = self.bot.delete_message
427
+ if inspect.iscoroutinefunction(func):
428
+ await func(self.chat_id, self.message_id)
429
+ else:
430
+ func(self.chat_id, self.message_id)
431
+ try:
432
+ loop = asyncio.get_running_loop()
433
+ if loop.is_running():
434
+ return asyncio.create_task(_delete())
435
+ except RuntimeError:
436
+ return asyncio.run(_delete())
437
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
438
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
439
+ return Pick(self.bot, chat_id, message_id)
440
+ try:
441
+ loop = asyncio.get_running_loop()
442
+ if loop.is_running():
443
+ return asyncio.create_task(_reply_async())
444
+ except RuntimeError:
445
+ return asyncio.run(_reply_async())
446
+ def answer(self, text: str, **kwargs):
447
+ return self.bot.send_message(
448
+ self.chat_id,
449
+ text,
450
+ reply_to_message_id=self.message_id,
451
+ **kwargs
452
+ )
453
+ async def copy(self, to_chat_id: Optional[str], message_id: Optional[str] = None):await self.copy_message(to_chat_id, message_id)
454
+ async def copy_message(self, to_chat_id: Optional[str], message_id: Optional[str] = None):
455
+ try:
456
+ send_func = None
457
+ kwargs = {
458
+ "chat_id": to_chat_id,
459
+ "reply_to_message_id": message_id,
460
+ "meta_data": self.metadata
461
+ }
462
+ if getattr(self, "is_photo", False):
463
+ send_func = self.bot.send_image
464
+ elif getattr(self, "is_video", False):
465
+ send_func = self.bot.send_video
466
+ elif getattr(self, "is_music", False):
467
+ send_func = self.bot.send_music
468
+ elif getattr(self, "is_document", False):
469
+ send_func = self.bot.send_document
470
+ elif getattr(self, "is_text", False):
471
+ send_func = self.bot.send_message
472
+ kwargs["text"] = self.text
473
+ if send_func:
474
+ if hasattr(self, "file") and self.file:
475
+ kwargs["path"] = await self.bot.get_url_file(self.file.file_id)
476
+ return await send_func(**kwargs)
477
+ else:
478
+ raise Exception("Unsupported message type.")
479
+ except Exception as e:
480
+ raise Exception(f"Error: {e}")
481
+ def reply_poll(
482
+ self,
483
+ question: str,
484
+ options: List[str],
485
+ type: Literal['Regular', 'Quiz'] = "Regular",
486
+ allows_multiple_answers: bool = False,
487
+ is_anonymous: bool = True,
488
+ correct_option_index: Optional[int] = None,
489
+ hint: Optional[str] = None,
490
+ reply_to_message_id: Optional[str] = None,
491
+ disable_notification: bool = False,
492
+ show_results: bool = False,
493
+ inline_keypad: Optional[Dict[str, Any]] = None,
494
+ chat_keypad: Optional[Dict[str, Any]] = None,
495
+ chat_keypad_type: Optional[Literal['New', 'Remove', 'None']] = None,
496
+ **kwargs
497
+ ) -> dict:
498
+ payload = {
499
+ "chat_id": self.chat_id,
500
+ "question": question,
501
+ "options": options,
502
+ "type": type,
503
+ "allows_multiple_answers": allows_multiple_answers,
504
+ "is_anonymous": is_anonymous,
505
+ "correct_option_index": correct_option_index,
506
+ "hint": hint,
507
+ "reply_to_message_id": self.message_id if not reply_to_message_id else reply_to_message_id,
508
+ "disable_notification": disable_notification,
509
+ "show_results": show_results,
510
+ "inline_keypad": inline_keypad,
511
+ "chat_keypad": chat_keypad,
512
+ "chat_keypad_type": chat_keypad_type,
513
+ }
514
+ return self.bot._post("sendPoll", {key: value for key, value in payload.items() if value is not None}, **kwargs)
515
+
516
+
517
+ def reply_document(
518
+ self,
519
+ path: Optional[Union[str, Path]] = None,
520
+ file_id: Optional[str] = None,
521
+ text: Optional[str] = None,
522
+ chat_keypad: Optional[Dict[str, Any]] = None,
523
+ inline_keypad: Optional[Dict[str, Any]] = None,
524
+ chat_keypad_type: Optional[str] = "None",
525
+ disable_notification: bool = False
526
+ ):
527
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
528
+ return self.bot.send_document(
529
+ chat_id=self.chat_id,
530
+ path=path,
531
+ file_id=file_id,
532
+ text=text,
533
+ chat_keypad=chat_keypad,
534
+ inline_keypad=inline_keypad,
535
+ chat_keypad_type=chat_keypad_type,
536
+ disable_notification=disable_notification,
537
+ reply_to_message_id=self.message_id
538
+ )
539
+ def reply_file(
540
+ self,
541
+ path: Optional[Union[str, Path]] = None,
542
+ file_id: Optional[str] = None,
543
+ text: Optional[str] = None,
544
+ chat_keypad: Optional[Dict[str, Any]] = None,
545
+ inline_keypad: Optional[Dict[str, Any]] = None,
546
+ chat_keypad_type: Optional[str] = "None",
547
+ disable_notification: bool = False
548
+ ):
549
+ if chat_keypad and chat_keypad_type == "none":
550
+ chat_keypad_type == "New"
551
+
552
+ return self.bot.send_document(
553
+ chat_id=self.chat_id,
554
+ path=path,
555
+ file_id=file_id,
556
+ text=text,
557
+ chat_keypad=chat_keypad,
558
+ inline_keypad=inline_keypad,
559
+ chat_keypad_type=chat_keypad_type,
560
+ disable_notification=disable_notification,
561
+ reply_to_message_id=self.message_id
562
+ )
563
+
564
+ def reply_image(
565
+ self,
566
+ path: Optional[Union[str, Path]] = None,
567
+ file_id: Optional[str] = None,
568
+ text: Optional[str] = None,
569
+ chat_keypad: Optional[Dict[str, Any]] = None,
570
+ inline_keypad: Optional[Dict[str, Any]] = None,
571
+ chat_keypad_type: Optional[str] = "None",
572
+ disable_notification: bool = False
573
+ ):
574
+ if chat_keypad and chat_keypad_type == "none":
575
+ chat_keypad_type == "New"
576
+ return self.bot.send_image(
577
+ chat_id=self.chat_id,
578
+ path=path,
579
+ file_id=file_id,
580
+ text=text,
581
+ chat_keypad=chat_keypad,
582
+ inline_keypad=inline_keypad,
583
+ chat_keypad_type=chat_keypad_type,
584
+ disable_notification=disable_notification,
585
+ reply_to_message_id=self.message_id
586
+ )
587
+
588
+ def reply_music(
589
+ self,
590
+ path: Optional[Union[str, Path]] = None,
591
+ file_id: Optional[str] = None,
592
+ text: Optional[str] = None,
593
+ chat_keypad: Optional[Dict[str, Any]] = None,
594
+ inline_keypad: Optional[Dict[str, Any]] = None,
595
+ chat_keypad_type: Optional[str] = "None",
596
+ disable_notification: bool = False
597
+ ):
598
+ if chat_keypad and chat_keypad_type == "none":
599
+ chat_keypad_type == "New"
600
+ return self.bot.send_music(
601
+ chat_id=self.chat_id,
602
+ path=path,
603
+ file_id=file_id,
604
+ text=text,
605
+ chat_keypad=chat_keypad,
606
+ inline_keypad=inline_keypad,
607
+ chat_keypad_type=chat_keypad_type,
608
+ disable_notification=disable_notification,
609
+ reply_to_message_id=self.message_id
610
+ )
611
+
612
+ def reply_voice(
613
+ self,
614
+ path: Optional[Union[str, Path]] = None,
615
+ file_id: Optional[str] = None,
616
+ text: Optional[str] = None,
617
+ chat_keypad: Optional[Dict[str, Any]] = None,
618
+ inline_keypad: Optional[Dict[str, Any]] = None,
619
+ chat_keypad_type: Optional[str] = "None",
620
+ disable_notification: bool = False
621
+ ):
622
+ if chat_keypad and chat_keypad_type == "none":
623
+ chat_keypad_type == "New"
624
+ return self.bot.send_voice(
625
+ chat_id=self.chat_id,
626
+ path=path,
627
+ file_id=file_id,
628
+ text=text,
629
+ chat_keypad=chat_keypad,
630
+ inline_keypad=inline_keypad,
631
+ chat_keypad_type=chat_keypad_type,
632
+ disable_notification=disable_notification,
633
+ reply_to_message_id=self.message_id
634
+ )
635
+
636
+ def reply_gif(
637
+ self,
638
+ path: Optional[Union[str, Path]] = None,
639
+ file_id: Optional[str] = None,
640
+ text: Optional[str] = None,
641
+ chat_keypad: Optional[Dict[str, Any]] = None,
642
+ inline_keypad: Optional[Dict[str, Any]] = None,
643
+ chat_keypad_type: Optional[str] = "None",
644
+ disable_notification: bool = False
645
+ ):
646
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
647
+ return self.bot.send_gif(
648
+ chat_id=self.chat_id,
649
+ path=path,
650
+ file_id=file_id,
651
+ text=text,
652
+ chat_keypad=chat_keypad,
653
+ inline_keypad=inline_keypad,
654
+ chat_keypad_type=chat_keypad_type,
655
+ disable_notification=disable_notification,
656
+ reply_to_message_id=self.message_id
657
+ )
658
+
659
+ def reply_location(self, latitude: str, longitude: str, **kwargs) -> Dict[str, Any]:
660
+ return self.bot.send_location(
661
+ chat_id=self.chat_id,
662
+ latitude=latitude,
663
+ longitude=longitude,
664
+ reply_to_message_id=self.message_id,
665
+ **kwargs
666
+ )
667
+
668
+ def reply_contact(self, first_name: str, last_name: str, phone_number: str, **kwargs) -> Dict[str, Any]:
669
+ return self.bot.send_contact(
670
+ chat_id=self.chat_id,
671
+ first_name=first_name,
672
+ last_name=last_name,
673
+ phone_number=phone_number,
674
+ reply_to_message_id=self.message_id,
675
+ **kwargs
676
+ )
677
+
678
+ def reply_keypad(self, text: str, keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
679
+ return self.bot.send_message(
680
+ chat_id=self.chat_id,
681
+ text=text,
682
+ chat_keypad_type="New",
683
+ chat_keypad=keypad,
684
+ reply_to_message_id=self.message_id,
685
+ **kwargs
686
+ )
687
+
688
+ def reply_inline(self, text: str, inline_keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
689
+ return self.bot.send_message(
690
+ chat_id=self.chat_id,
691
+ text=text,
692
+ inline_keypad=inline_keypad,
693
+ reply_to_message_id=self.message_id,
694
+ **kwargs
695
+ )
696
+
697
+ def reply_sticker(self, sticker_id: str, **kwargs) -> Dict[str, Any]:
698
+ return self.bot._post("sendSticker", {
699
+ "chat_id": self.chat_id,
700
+ "sticker_id": sticker_id,
701
+ "reply_to_message_id": self.message_id,
702
+ **kwargs
703
+ })
704
+
705
+ def edit(self, new_text: str) -> Dict[str, Any]:
706
+ return self.bot.edit_message_text(
707
+ chat_id=self.chat_id,
708
+ message_id=self.message_id,
709
+ text=new_text
710
+ )
711
+
712
+ def delete(self) -> Dict[str, Any]:
713
+ return self.bot.delete_message(
714
+ chat_id=self.chat_id,
715
+ message_id=self.message_id
716
+ )
717
+ @hybrid_property
718
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
719
+ @hybrid_property
720
+ async def name(self):return await self.bot.get_name(self.chat_id)
721
+ @hybrid_property
722
+ async def username(self):return await self.bot.get_username(self.chat_id)
723
+ @hybrid_property
724
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)
725
+ class AuxData:
726
+ def __init__(self, data: dict):
727
+ self.start_id = data.get("start_id")
728
+ self.button_id = data.get("button_id")
729
+
730
+
731
+ class InlineMessage:
732
+ def __init__(self, bot, raw_data: dict):
733
+ self.bot = bot
734
+ self.raw_data = raw_data
735
+ chat_id : str = raw_data.get("chat_id")
736
+ sender_id : str = raw_data.get("sender_id")
737
+ self.chat_id: str = raw_data.get("chat_id")
738
+ self.message_id: str = raw_data.get("message_id")
739
+ self.sender_id: str = raw_data.get("sender_id")
740
+ self.text: str = raw_data.get("text")
741
+ self.aux_data = AuxData(raw_data.get("aux_data", {})) if "aux_data" in raw_data else None
742
+ self.bot = bot
743
+ self.raw_data = raw_data or {}
744
+ self.object_guid = chat_id
745
+ self.author_guid = self.raw_data.get("sender_id", sender_id)
746
+ self.has_link = bool(re.search(r"(https?://[^\s]+ | www\.[^\s]+ | [a-zA-Z0-9.-]+\.(com|net|org|ir|edu|gov|info|biz|io|me|co) | t\.me/[^\s]+ | telegram\.me/[^\s]+ | @\w+ | \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)", self.text))
747
+ self.sender_id: str = self.raw_data.get("sender_id", sender_id)
748
+ self.time: str = self.raw_data.get("time")
749
+ self.is_edited: bool = self.raw_data.get("is_edited", False)
750
+ self.sender_type: str = self.raw_data.get("sender_type")
751
+ self.args = []
752
+ self.is_command = bool(self.text and self.text.startswith("/"))
753
+ self.is_user = self.chat_id.startswith("b")
754
+ self.is_private = self.chat_id.startswith("b")
755
+ self.is_group = self.chat_id.startswith("g")
756
+ self.is_channel = self.chat_id.startswith("c")
757
+ self.reply_to_message_id: Optional[str] = self.raw_data.get("reply_to_message_id")
758
+ self.forwarded_from = ForwardedFrom(self.raw_data["forwarded_from"]) if "forwarded_from" in self.raw_data else None
759
+ self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
760
+ self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
761
+ self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
762
+ self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
763
+ self.is_reply = self.reply_to_message_id is not None
764
+ self.has_media = any([self.file, self.sticker])
765
+ self.is_forwarded = self.forwarded_from is not None
766
+ self.is_text = bool(self.text and not self.has_media)
767
+ self.is_media = self.has_media
768
+ self.is_contact = self.contact_message is not None
769
+ self.has_any_media = any([self.file, self.sticker,])
770
+ self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
771
+ if self.file and self.file.file_name:
772
+ name = self.file.file_name.lower()
773
+ self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
774
+ self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
775
+ self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
776
+ self.is_voice = name.endswith((".ogg", ".m4a"))
777
+ self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
778
+ self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
779
+ self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
780
+ self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
781
+
782
+
783
+ @property
784
+ def session(self):
785
+ if self.chat_id not in self.bot.sessions:
786
+ self.bot.sessions[self.chat_id] = {}
787
+ return self.bot.sessions[self.chat_id]
788
+
789
+ def reply(self, text: str, delete_after: int = None, **kwargs):
790
+ async def _reply_async():
791
+ send_func = self.bot.send_message
792
+ if inspect.iscoroutinefunction(send_func):
793
+ msg = await send_func(
794
+ self.chat_id,
795
+ text,
796
+ reply_to_message_id=self.message_id,
797
+ delete_after=delete_after,
798
+ **kwargs
799
+ )
800
+ else:
801
+ msg = send_func(
802
+ self.chat_id,
803
+ text,
804
+ reply_to_message_id=self.message_id,
805
+ delete_after=delete_after,
806
+ **kwargs
807
+ )
808
+ class Pick:
809
+ def __init__(self, bot, chat_id, message_id):
810
+ self.bot = bot
811
+ self.chat_id = chat_id
812
+ self.message_id = message_id
813
+
814
+ def edit(self, new_text):
815
+ async def _edit():
816
+ func = self.bot.edit_message_text
817
+ if inspect.iscoroutinefunction(func):
818
+ await func(self.chat_id, self.message_id, new_text)
819
+ else:
820
+ func(self.chat_id, self.message_id, new_text)
821
+
822
+ try:
823
+ loop = asyncio.get_running_loop()
824
+ if loop.is_running():
825
+ return asyncio.create_task(_edit())
826
+ except RuntimeError:
827
+ return asyncio.run(_edit())
828
+
829
+ def delete(self):
830
+ async def _delete():
831
+ func = self.bot.delete_message
832
+ if inspect.iscoroutinefunction(func):
833
+ await func(self.chat_id, self.message_id)
834
+ else:
835
+ func(self.chat_id, self.message_id)
836
+ try:
837
+ loop = asyncio.get_running_loop()
838
+ if loop.is_running():
839
+ return asyncio.create_task(_delete())
840
+ except RuntimeError:
841
+ return asyncio.run(_delete())
842
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
843
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
844
+ return Pick(self.bot, chat_id, message_id)
845
+ try:
846
+ loop = asyncio.get_running_loop()
847
+ if loop.is_running():
848
+ return asyncio.create_task(_reply_async())
849
+ except RuntimeError:
850
+ return asyncio.run(_reply_async())
851
+ def answer(self, text: str, **kwargs):
852
+ return self.bot.send_message(
853
+ self.chat_id,
854
+ text,
855
+ reply_to_message_id=self.message_id,
856
+ **kwargs
857
+ )
858
+
859
+
860
+ def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
861
+ return self.bot._post("sendPoll", {
862
+ "chat_id": self.chat_id,
863
+ "question": question,
864
+ "options": options,
865
+ "reply_to_message_id": self.message_id,
866
+ **kwargs
867
+ })
868
+
869
+
870
+ def reply_document(
871
+ self,
872
+ path: Optional[Union[str, Path]] = None,
873
+ file_id: Optional[str] = None,
874
+ text: Optional[str] = None,
875
+ chat_keypad: Optional[Dict[str, Any]] = None,
876
+ inline_keypad: Optional[Dict[str, Any]] = None,
877
+ chat_keypad_type: Optional[str] = "None",
878
+ disable_notification: bool = False
879
+ ):
880
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
881
+ return self.bot.send_document(
882
+ chat_id=self.chat_id,
883
+ path=path,
884
+ file_id=file_id,
885
+ text=text,
886
+ chat_keypad=chat_keypad,
887
+ inline_keypad=inline_keypad,
888
+ chat_keypad_type=chat_keypad_type,
889
+ disable_notification=disable_notification,
890
+ reply_to_message_id=self.message_id
891
+ )
892
+ def reply_file(
893
+ self,
894
+ path: Optional[Union[str, Path]] = None,
895
+ file_id: Optional[str] = None,
896
+ text: Optional[str] = None,
897
+ chat_keypad: Optional[Dict[str, Any]] = None,
898
+ inline_keypad: Optional[Dict[str, Any]] = None,
899
+ chat_keypad_type: Optional[str] = "None",
900
+ disable_notification: bool = False
901
+ ):
902
+ if chat_keypad and chat_keypad_type == "none":
903
+ chat_keypad_type == "New"
904
+
905
+ return self.bot.send_document(
906
+ chat_id=self.chat_id,
907
+ path=path,
908
+ file_id=file_id,
909
+ text=text,
910
+ chat_keypad=chat_keypad,
911
+ inline_keypad=inline_keypad,
912
+ chat_keypad_type=chat_keypad_type,
913
+ disable_notification=disable_notification,
914
+ reply_to_message_id=self.message_id
915
+ )
916
+
917
+ def reply_image(
918
+ self,
919
+ path: Optional[Union[str, Path]] = None,
920
+ file_id: Optional[str] = None,
921
+ text: Optional[str] = None,
922
+ chat_keypad: Optional[Dict[str, Any]] = None,
923
+ inline_keypad: Optional[Dict[str, Any]] = None,
924
+ chat_keypad_type: Optional[str] = "None",
925
+ disable_notification: bool = False
926
+ ):
927
+ if chat_keypad and chat_keypad_type == "none":
928
+ chat_keypad_type == "New"
929
+ return self.bot.send_image(
930
+ chat_id=self.chat_id,
931
+ path=path,
932
+ file_id=file_id,
933
+ text=text,
934
+ chat_keypad=chat_keypad,
935
+ inline_keypad=inline_keypad,
936
+ chat_keypad_type=chat_keypad_type,
937
+ disable_notification=disable_notification,
938
+ reply_to_message_id=self.message_id
939
+ )
940
+
941
+ def reply_music(
942
+ self,
943
+ path: Optional[Union[str, Path]] = None,
944
+ file_id: Optional[str] = None,
945
+ text: Optional[str] = None,
946
+ chat_keypad: Optional[Dict[str, Any]] = None,
947
+ inline_keypad: Optional[Dict[str, Any]] = None,
948
+ chat_keypad_type: Optional[str] = "None",
949
+ disable_notification: bool = False
950
+ ):
951
+ if chat_keypad and chat_keypad_type == "none":
952
+ chat_keypad_type == "New"
953
+ return self.bot.send_music(
954
+ chat_id=self.chat_id,
955
+ path=path,
956
+ file_id=file_id,
957
+ text=text,
958
+ chat_keypad=chat_keypad,
959
+ inline_keypad=inline_keypad,
960
+ chat_keypad_type=chat_keypad_type,
961
+ disable_notification=disable_notification,
962
+ reply_to_message_id=self.message_id
963
+ )
964
+
965
+ def reply_voice(
966
+ self,
967
+ path: Optional[Union[str, Path]] = None,
968
+ file_id: Optional[str] = None,
969
+ text: Optional[str] = None,
970
+ chat_keypad: Optional[Dict[str, Any]] = None,
971
+ inline_keypad: Optional[Dict[str, Any]] = None,
972
+ chat_keypad_type: Optional[str] = "None",
973
+ disable_notification: bool = False
974
+ ):
975
+ if chat_keypad and chat_keypad_type == "none":
976
+ chat_keypad_type == "New"
977
+ return self.bot.send_voice(
978
+ chat_id=self.chat_id,
979
+ path=path,
980
+ file_id=file_id,
981
+ text=text,
982
+ chat_keypad=chat_keypad,
983
+ inline_keypad=inline_keypad,
984
+ chat_keypad_type=chat_keypad_type,
985
+ disable_notification=disable_notification,
986
+ reply_to_message_id=self.message_id
987
+ )
988
+
989
+ def reply_gif(
990
+ self,
991
+ path: Optional[Union[str, Path]] = None,
992
+ file_id: Optional[str] = None,
993
+ text: Optional[str] = None,
994
+ chat_keypad: Optional[Dict[str, Any]] = None,
995
+ inline_keypad: Optional[Dict[str, Any]] = None,
996
+ chat_keypad_type: Optional[str] = "None",
997
+ disable_notification: bool = False
998
+ ):
999
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
1000
+ return self.bot.send_gif(
1001
+ chat_id=self.chat_id,
1002
+ path=path,
1003
+ file_id=file_id,
1004
+ text=text,
1005
+ chat_keypad=chat_keypad,
1006
+ inline_keypad=inline_keypad,
1007
+ chat_keypad_type=chat_keypad_type,
1008
+ disable_notification=disable_notification,
1009
+ reply_to_message_id=self.message_id
1010
+ )
1011
+
1012
+ def reply_location(self, latitude: str, longitude: str, **kwargs) -> Dict[str, Any]:
1013
+ return self.bot.send_location(
1014
+ chat_id=self.chat_id,
1015
+ latitude=latitude,
1016
+ longitude=longitude,
1017
+ reply_to_message_id=self.message_id,
1018
+ **kwargs
1019
+ )
1020
+
1021
+ def reply_contact(self, first_name: str, last_name: str, phone_number: str, **kwargs) -> Dict[str, Any]:
1022
+ return self.bot.send_contact(
1023
+ chat_id=self.chat_id,
1024
+ first_name=first_name,
1025
+ last_name=last_name,
1026
+ phone_number=phone_number,
1027
+ reply_to_message_id=self.message_id,
1028
+ **kwargs
1029
+ )
1030
+
1031
+ def reply_keypad(self, text: str, keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
1032
+ return self.bot.send_message(
1033
+ chat_id=self.chat_id,
1034
+ text=text,
1035
+ chat_keypad_type="New",
1036
+ chat_keypad=keypad,
1037
+ reply_to_message_id=self.message_id,
1038
+ **kwargs
1039
+ )
1040
+
1041
+ def reply_inline(self, text: str, inline_keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
1042
+ return self.bot.send_message(
1043
+ chat_id=self.chat_id,
1044
+ text=text,
1045
+ inline_keypad=inline_keypad,
1046
+ reply_to_message_id=self.message_id,
1047
+ **kwargs
1048
+ )
1049
+
1050
+ def reply_sticker(self, sticker_id: str, **kwargs) -> Dict[str, Any]:
1051
+ return self.bot._post("sendSticker", {
1052
+ "chat_id": self.chat_id,
1053
+ "sticker_id": sticker_id,
1054
+ "reply_to_message_id": self.message_id,
1055
+ **kwargs
1056
+ })
1057
+
1058
+ def edit(self, new_text: str) -> Dict[str, Any]:
1059
+ return self.bot.edit_message_text(
1060
+ chat_id=self.chat_id,
1061
+ message_id=self.message_id,
1062
+ text=new_text
1063
+ )
1064
+
1065
+ def delete(self) -> Dict[str, Any]:
1066
+ return self.bot.delete_message(
1067
+ chat_id=self.chat_id,
1068
+ message_id=self.message_id
1069
+ )
1070
+ @hybrid_property
1071
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
1072
+ @hybrid_property
1073
+ async def name(self):return await self.bot.get_name(self.chat_id)
1074
+ @hybrid_property
1075
+ async def username(self):return await self.bot.get_username(self.chat_id)
1076
+ @hybrid_property
1077
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)