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/update.py ADDED
@@ -0,0 +1,1038 @@
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\d{1,3}(?:\.\d{1,3}){3}\b"
62
+ r"|\[?[A-F0-9:]{2,39}\]?"
63
+ r")\b"
64
+ )
65
+ return bool(pattern.search(text))
66
+ class File:
67
+ def __init__(self, data: dict):
68
+ self.file_id: str = data.get("file_id")
69
+ self.file_name: str = data.get("file_name")
70
+ self.size: str = data.get("size")
71
+
72
+
73
+ class Sticker:
74
+ def __init__(self, data: dict):
75
+ self.sticker_id: str = data.get("sticker_id")
76
+ self.emoji_character: str = data.get("emoji_character")
77
+ self.file = File(data.get("file", {}))
78
+
79
+
80
+
81
+
82
+
83
+ class PollStatus:
84
+ def __init__(self, data: dict):
85
+ self.state: str = data.get("state")
86
+ self.selection_index: int = data.get("selection_index")
87
+ self.percent_vote_options: List[int] = data.get("percent_vote_options", [])
88
+ self.total_vote: int = data.get("total_vote")
89
+ self.show_total_votes: bool = data.get("show_total_votes")
90
+
91
+
92
+ class Poll:
93
+ def __init__(self, data: dict):
94
+ self.question: str = data.get("question")
95
+ self.options: List[str] = data.get("options", [])
96
+ self.poll_status = PollStatus(data.get("poll_status", {}))
97
+
98
+
99
+
100
+
101
+
102
+ class Location:
103
+ def __init__(self, data: dict):
104
+ self.latitude: str = data.get("latitude")
105
+ self.longitude: str = data.get("longitude")
106
+
107
+
108
+ class LiveLocation:
109
+ def __init__(self, data: dict):
110
+ self.start_time: str = data.get("start_time")
111
+ self.live_period: int = data.get("live_period")
112
+ self.current_location = Location(data.get("current_location", {}))
113
+ self.user_id: str = data.get("user_id")
114
+ self.status: str = data.get("status")
115
+ self.last_update_time: str = data.get("last_update_time")
116
+
117
+
118
+ class ContactMessage:
119
+ def __init__(self, data: dict):
120
+ self.phone_number: str = data.get("phone_number")
121
+ self.first_name: str = data.get("first_name")
122
+ self.last_name: str = data.get("last_name")
123
+
124
+
125
+ class ForwardedFrom:
126
+ def __init__(self, data: dict):
127
+ self.type_from: str = data.get("type_from")
128
+ self.message_id: str = data.get("message_id")
129
+ self.from_chat_id: str = data.get("from_chat_id")
130
+ self.from_sender_id: str = data.get("from_sender_id")
131
+
132
+
133
+
134
+
135
+
136
+ class AuxData:
137
+ def __init__(self, data: dict):
138
+ self.start_id: str = data.get("start_id")
139
+ self.button_id: str = data.get("button_id")
140
+
141
+
142
+
143
+
144
+
145
+ class ButtonTextbox:
146
+ def __init__(self, data: dict):
147
+ self.type_line: str = data.get("type_line")
148
+ self.type_keypad: str = data.get("type_keypad")
149
+ self.place_holder: Optional[str] = data.get("place_holder")
150
+ self.title: Optional[str] = data.get("title")
151
+ self.default_value: Optional[str] = data.get("default_value")
152
+
153
+
154
+ class ButtonNumberPicker:
155
+ def __init__(self, data: dict):
156
+ self.min_value: str = data.get("min_value")
157
+ self.max_value: str = data.get("max_value")
158
+ self.default_value: Optional[str] = data.get("default_value")
159
+ self.title: str = data.get("title")
160
+
161
+
162
+ class ButtonStringPicker:
163
+ def __init__(self, data: dict):
164
+ self.items: List[str] = data.get("items", [])
165
+ self.default_value: Optional[str] = data.get("default_value")
166
+ self.title: Optional[str] = data.get("title")
167
+
168
+
169
+ class ButtonCalendar:
170
+ def __init__(self, data: dict):
171
+ self.default_value: Optional[str] = data.get("default_value")
172
+ self.type: str = data.get("type")
173
+ self.min_year: str = data.get("min_year")
174
+ self.max_year: str = data.get("max_year")
175
+ self.title: str = data.get("title")
176
+
177
+
178
+ class ButtonLocation:
179
+ def __init__(self, data: dict):
180
+ self.default_pointer_location = Location(data.get("default_pointer_location", {}))
181
+ self.default_map_location = Location(data.get("default_map_location", {}))
182
+ self.type: str = data.get("type")
183
+ self.title: Optional[str] = data.get("title")
184
+ self.location_image_url: str = data.get("location_image_url")
185
+
186
+
187
+ class ButtonSelectionItem:
188
+ def __init__(self, data: dict):
189
+ self.text: str = data.get("text")
190
+ self.image_url: str = data.get("image_url")
191
+ self.type: str = data.get("type")
192
+
193
+
194
+ class ButtonSelection:
195
+ def __init__(self, data: dict):
196
+ self.selection_id: str = data.get("selection_id")
197
+ self.search_type: str = data.get("search_type")
198
+ self.get_type: str = data.get("get_type")
199
+ self.items: List[ButtonSelectionItem] = [ButtonSelectionItem(i) for i in data.get("items", [])]
200
+ self.is_multi_selection: bool = data.get("is_multi_selection")
201
+ self.columns_count: str = data.get("columns_count")
202
+ self.title: str = data.get("title")
203
+
204
+
205
+ class Button:
206
+ def __init__(self, data: dict):
207
+ self.id: str = data.get("id")
208
+ self.type: str = data.get("type")
209
+ self.button_text: str = data.get("button_text")
210
+ self.button_selection = ButtonSelection(data.get("button_selection", {})) if "button_selection" in data else None
211
+ self.button_calendar = ButtonCalendar(data.get("button_calendar", {})) if "button_calendar" in data else None
212
+ self.button_number_picker = ButtonNumberPicker(data.get("button_number_picker", {})) if "button_number_picker" in data else None
213
+ self.button_string_picker = ButtonStringPicker(data.get("button_string_picker", {})) if "button_string_picker" in data else None
214
+ self.button_location = ButtonLocation(data.get("button_location", {})) if "button_location" in data else None
215
+ self.button_textbox = ButtonTextbox(data.get("button_textbox", {})) if "button_textbox" in data else None
216
+
217
+
218
+ class KeypadRow:
219
+ def __init__(self, data: dict):
220
+ self.buttons: List[Button] = [Button(btn) for btn in data.get("buttons", [])]
221
+
222
+
223
+ class Keypad:
224
+ def __init__(self, data: dict):
225
+ self.rows: List[KeypadRow] = [KeypadRow(r) for r in data.get("rows", [])]
226
+ self.resize_keyboard: bool = data.get("resize_keyboard", False)
227
+ self.on_time_keyboard: bool = data.get("on_time_keyboard", False)
228
+
229
+
230
+ class Chat:
231
+ def __init__(self, data: dict):
232
+ self.chat_id: str = data.get("chat_id")
233
+ self.chat_type: str = data.get("chat_type")
234
+ self.user_id: str = data.get("user_id")
235
+ self.first_name: str = data.get("first_name")
236
+ self.last_name: str = data.get("last_name")
237
+ self.title: str = data.get("title")
238
+ self.username: str = data.get("username")
239
+
240
+
241
+ class Bot:
242
+ def __init__(self, data: dict):
243
+ self.bot_id: str = data.get("bot_id")
244
+ self.bot_title: str = data.get("bot_title")
245
+ self.avatar = File(data.get("avatar", {}))
246
+ self.description: str = data.get("description")
247
+ self.username: str = data.get("username")
248
+ self.start_message: str = data.get("start_message")
249
+ self.share_url: str = data.get("share_url")
250
+
251
+ class hybrid_property:
252
+ def __init__(self, func):
253
+ self.func = func
254
+
255
+ def __get__(self, instance, owner):
256
+ if instance is None:
257
+ return self
258
+ coro = self.func(instance)
259
+ try:
260
+ loop = asyncio.get_running_loop()
261
+ return coro
262
+ except RuntimeError:
263
+ try:
264
+ loop = asyncio.get_event_loop()
265
+ except RuntimeError:
266
+ loop = asyncio.new_event_loop()
267
+ asyncio.set_event_loop(loop)
268
+ return loop.run_until_complete(coro)
269
+ class Message:
270
+ def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
271
+ self.bot = bot
272
+ self.raw_data = raw_data or {}
273
+ self.chat_id = chat_id
274
+ self.object_guid = chat_id
275
+ self.author_guid = self.raw_data.get("sender_id", sender_id)
276
+ self.message_id: str = self.raw_data.get("message_id", message_id)
277
+ self.text: str = self.raw_data.get("text", text)
278
+ self.has_link = contains_link_or_mention(self.raw_data.get("text", text))
279
+ self.is_link = self.has_link
280
+ self.is_mention = bool(re.search(r"@\w+", self.raw_data.get("text", text) or ""))
281
+ self.is_hashtag = bool(re.search(r"#\w+", text or ""))
282
+ self.is_number = bool(re.search(r"\d+", text or ""))
283
+ self.is_emoji = contains_emoji(self.raw_data.get("text", text))
284
+ self.emoji_count = count_emojis(self.raw_data.get("text", text))
285
+ self.is_pure_emoji = bool(self.is_emoji and self.emoji_count == len(self.text))
286
+ self.is_photo = None
287
+ self.is_video = None
288
+ self.is_audio = None
289
+ self.is_voice = None
290
+ self.is_document = 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.location = Location(self.raw_data["location"]) if "location" in self.raw_data else None
341
+ self.live_location = LiveLocation(self.raw_data["live_location"]) if "live_location" in self.raw_data else None
342
+ self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
343
+ self.is_reply = self.reply_to_message_id is not None
344
+ self.has_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
345
+ self.is_forwarded = self.forwarded_from is not None
346
+ self.is_text = bool(self.text and not self.has_media)
347
+ self.is_media = self.has_media
348
+ self.is_poll = self.poll is not None
349
+ self.is_location = self.location is not None
350
+ self.is_live_location = self.live_location is not None
351
+ self.is_contact = self.contact_message is not None
352
+ self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
353
+ self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
354
+ if self.file and self.file.file_name:
355
+ name = self.file.file_name.lower()
356
+ self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
357
+ self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
358
+ self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
359
+ self.is_voice = name.endswith((".ogg", ".m4a"))
360
+ self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
361
+ self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
362
+ self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
363
+ self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
364
+ @property
365
+ def session(self):
366
+ if self.chat_id not in self.bot.sessions:
367
+ self.bot.sessions[self.chat_id] = {}
368
+ return self.bot.sessions[self.chat_id]
369
+
370
+ def reply(self, text: str, delete_after: int = None,parse_mode : Optional[Literal["HTML", "Markdown"]] = None , **kwargs):
371
+ async def _reply_async():
372
+ send_func = self.bot.send_message
373
+ if inspect.iscoroutinefunction(send_func):
374
+ msg = await send_func(
375
+ self.chat_id,
376
+ text,
377
+ reply_to_message_id=self.message_id,
378
+ delete_after=delete_after,
379
+ parse_mode=parse_mode,
380
+ **kwargs
381
+ )
382
+ else:
383
+ msg = send_func(
384
+ self.chat_id,
385
+ text,
386
+ reply_to_message_id=self.message_id,
387
+ delete_after=delete_after,
388
+ **kwargs
389
+ )
390
+ class Pick:
391
+ def __init__(self, bot, chat_id, message_id):
392
+ self.bot = bot
393
+ self.chat_id = chat_id
394
+ self.message_id = message_id
395
+
396
+ def edit(self, new_text):
397
+ async def _edit():
398
+ func = self.bot.edit_message_text
399
+ if inspect.iscoroutinefunction(func):
400
+ await func(self.chat_id, self.message_id, new_text)
401
+ else:
402
+ func(self.chat_id, self.message_id, new_text)
403
+
404
+ try:
405
+ loop = asyncio.get_running_loop()
406
+ if loop.is_running():
407
+ return asyncio.create_task(_edit())
408
+ except RuntimeError:
409
+ return asyncio.run(_edit())
410
+
411
+ def delete(self):
412
+ async def _delete():
413
+ func = self.bot.delete_message
414
+ if inspect.iscoroutinefunction(func):
415
+ await func(self.chat_id, self.message_id)
416
+ else:
417
+ func(self.chat_id, self.message_id)
418
+ try:
419
+ loop = asyncio.get_running_loop()
420
+ if loop.is_running():
421
+ return asyncio.create_task(_delete())
422
+ except RuntimeError:
423
+ return asyncio.run(_delete())
424
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
425
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
426
+ return Pick(self.bot, chat_id, message_id)
427
+ try:
428
+ loop = asyncio.get_running_loop()
429
+ if loop.is_running():
430
+ return asyncio.create_task(_reply_async())
431
+ except RuntimeError:
432
+ return asyncio.run(_reply_async())
433
+ def answer(self, text: str, **kwargs):
434
+ return self.bot.send_message(
435
+ self.chat_id,
436
+ text,
437
+ reply_to_message_id=self.message_id,
438
+ **kwargs
439
+ )
440
+
441
+
442
+ def reply_poll(
443
+ self,
444
+ question: str,
445
+ options: List[str],
446
+ type: Literal['Regular', 'Quiz'] = "Regular",
447
+ allows_multiple_answers: bool = False,
448
+ is_anonymous: bool = True,
449
+ correct_option_index: Optional[int] = None,
450
+ hint: Optional[str] = None,
451
+ reply_to_message_id: Optional[str] = None,
452
+ disable_notification: bool = False,
453
+ show_results: bool = False,
454
+ inline_keypad: Optional[Dict[str, Any]] = None,
455
+ chat_keypad: Optional[Dict[str, Any]] = None,
456
+ chat_keypad_type: Optional[Literal['New', 'Remove', 'None']] = None,
457
+ **kwargs
458
+ ) -> dict:
459
+ payload = {
460
+ "chat_id": self.chat_id,
461
+ "question": question,
462
+ "options": options,
463
+ "type": type,
464
+ "allows_multiple_answers": allows_multiple_answers,
465
+ "is_anonymous": is_anonymous,
466
+ "correct_option_index": correct_option_index,
467
+ "hint": hint,
468
+ "reply_to_message_id": self.message_id if not reply_to_message_id else reply_to_message_id,
469
+ "disable_notification": disable_notification,
470
+ "show_results": show_results,
471
+ "inline_keypad": inline_keypad,
472
+ "chat_keypad": chat_keypad,
473
+ "chat_keypad_type": chat_keypad_type,
474
+ }
475
+ return self.bot._post("sendPoll", {key: value for key, value in payload.items() if value is not None}, **kwargs)
476
+
477
+
478
+ def reply_document(
479
+ self,
480
+ path: Optional[Union[str, Path]] = None,
481
+ file_id: Optional[str] = None,
482
+ text: Optional[str] = None,
483
+ chat_keypad: Optional[Dict[str, Any]] = None,
484
+ inline_keypad: Optional[Dict[str, Any]] = None,
485
+ chat_keypad_type: Optional[str] = "None",
486
+ disable_notification: bool = False
487
+ ):
488
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
489
+ return self.bot.send_document(
490
+ chat_id=self.chat_id,
491
+ path=path,
492
+ file_id=file_id,
493
+ text=text,
494
+ chat_keypad=chat_keypad,
495
+ inline_keypad=inline_keypad,
496
+ chat_keypad_type=chat_keypad_type,
497
+ disable_notification=disable_notification,
498
+ reply_to_message_id=self.message_id
499
+ )
500
+ def reply_file(
501
+ self,
502
+ path: Optional[Union[str, Path]] = None,
503
+ file_id: Optional[str] = None,
504
+ text: Optional[str] = None,
505
+ chat_keypad: Optional[Dict[str, Any]] = None,
506
+ inline_keypad: Optional[Dict[str, Any]] = None,
507
+ chat_keypad_type: Optional[str] = "None",
508
+ disable_notification: bool = False
509
+ ):
510
+ if chat_keypad and chat_keypad_type == "none":
511
+ chat_keypad_type == "New"
512
+
513
+ return self.bot.send_document(
514
+ chat_id=self.chat_id,
515
+ path=path,
516
+ file_id=file_id,
517
+ text=text,
518
+ chat_keypad=chat_keypad,
519
+ inline_keypad=inline_keypad,
520
+ chat_keypad_type=chat_keypad_type,
521
+ disable_notification=disable_notification,
522
+ reply_to_message_id=self.message_id
523
+ )
524
+
525
+ def reply_image(
526
+ self,
527
+ path: Optional[Union[str, Path]] = None,
528
+ file_id: Optional[str] = None,
529
+ text: Optional[str] = None,
530
+ chat_keypad: Optional[Dict[str, Any]] = None,
531
+ inline_keypad: Optional[Dict[str, Any]] = None,
532
+ chat_keypad_type: Optional[str] = "None",
533
+ disable_notification: bool = False
534
+ ):
535
+ if chat_keypad and chat_keypad_type == "none":
536
+ chat_keypad_type == "New"
537
+ return self.bot.send_image(
538
+ chat_id=self.chat_id,
539
+ path=path,
540
+ file_id=file_id,
541
+ text=text,
542
+ chat_keypad=chat_keypad,
543
+ inline_keypad=inline_keypad,
544
+ chat_keypad_type=chat_keypad_type,
545
+ disable_notification=disable_notification,
546
+ reply_to_message_id=self.message_id
547
+ )
548
+
549
+ def reply_music(
550
+ self,
551
+ path: Optional[Union[str, Path]] = None,
552
+ file_id: Optional[str] = None,
553
+ text: Optional[str] = None,
554
+ chat_keypad: Optional[Dict[str, Any]] = None,
555
+ inline_keypad: Optional[Dict[str, Any]] = None,
556
+ chat_keypad_type: Optional[str] = "None",
557
+ disable_notification: bool = False
558
+ ):
559
+ if chat_keypad and chat_keypad_type == "none":
560
+ chat_keypad_type == "New"
561
+ return self.bot.send_music(
562
+ chat_id=self.chat_id,
563
+ path=path,
564
+ file_id=file_id,
565
+ text=text,
566
+ chat_keypad=chat_keypad,
567
+ inline_keypad=inline_keypad,
568
+ chat_keypad_type=chat_keypad_type,
569
+ disable_notification=disable_notification,
570
+ reply_to_message_id=self.message_id
571
+ )
572
+
573
+ def reply_voice(
574
+ self,
575
+ path: Optional[Union[str, Path]] = None,
576
+ file_id: Optional[str] = None,
577
+ text: Optional[str] = None,
578
+ chat_keypad: Optional[Dict[str, Any]] = None,
579
+ inline_keypad: Optional[Dict[str, Any]] = None,
580
+ chat_keypad_type: Optional[str] = "None",
581
+ disable_notification: bool = False
582
+ ):
583
+ if chat_keypad and chat_keypad_type == "none":
584
+ chat_keypad_type == "New"
585
+ return self.bot.send_voice(
586
+ chat_id=self.chat_id,
587
+ path=path,
588
+ file_id=file_id,
589
+ text=text,
590
+ chat_keypad=chat_keypad,
591
+ inline_keypad=inline_keypad,
592
+ chat_keypad_type=chat_keypad_type,
593
+ disable_notification=disable_notification,
594
+ reply_to_message_id=self.message_id
595
+ )
596
+
597
+ def reply_gif(
598
+ self,
599
+ path: Optional[Union[str, Path]] = None,
600
+ file_id: Optional[str] = None,
601
+ text: Optional[str] = None,
602
+ chat_keypad: Optional[Dict[str, Any]] = None,
603
+ inline_keypad: Optional[Dict[str, Any]] = None,
604
+ chat_keypad_type: Optional[str] = "None",
605
+ disable_notification: bool = False
606
+ ):
607
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
608
+ return self.bot.send_gif(
609
+ chat_id=self.chat_id,
610
+ path=path,
611
+ file_id=file_id,
612
+ text=text,
613
+ chat_keypad=chat_keypad,
614
+ inline_keypad=inline_keypad,
615
+ chat_keypad_type=chat_keypad_type,
616
+ disable_notification=disable_notification,
617
+ reply_to_message_id=self.message_id
618
+ )
619
+
620
+ def reply_location(self, latitude: str, longitude: str, **kwargs) -> Dict[str, Any]:
621
+ return self.bot.send_location(
622
+ chat_id=self.chat_id,
623
+ latitude=latitude,
624
+ longitude=longitude,
625
+ reply_to_message_id=self.message_id,
626
+ **kwargs
627
+ )
628
+
629
+ def reply_contact(self, first_name: str, last_name: str, phone_number: str, **kwargs) -> Dict[str, Any]:
630
+ return self.bot.send_contact(
631
+ chat_id=self.chat_id,
632
+ first_name=first_name,
633
+ last_name=last_name,
634
+ phone_number=phone_number,
635
+ reply_to_message_id=self.message_id,
636
+ **kwargs
637
+ )
638
+
639
+ def reply_keypad(self, text: str, keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
640
+ return self.bot.send_message(
641
+ chat_id=self.chat_id,
642
+ text=text,
643
+ chat_keypad_type="New",
644
+ chat_keypad=keypad,
645
+ reply_to_message_id=self.message_id,
646
+ **kwargs
647
+ )
648
+
649
+ def reply_inline(self, text: str, inline_keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
650
+ return self.bot.send_message(
651
+ chat_id=self.chat_id,
652
+ text=text,
653
+ inline_keypad=inline_keypad,
654
+ reply_to_message_id=self.message_id,
655
+ **kwargs
656
+ )
657
+
658
+ def reply_sticker(self, sticker_id: str, **kwargs) -> Dict[str, Any]:
659
+ return self.bot._post("sendSticker", {
660
+ "chat_id": self.chat_id,
661
+ "sticker_id": sticker_id,
662
+ "reply_to_message_id": self.message_id,
663
+ **kwargs
664
+ })
665
+
666
+ def edit(self, new_text: str) -> Dict[str, Any]:
667
+ return self.bot.edit_message_text(
668
+ chat_id=self.chat_id,
669
+ message_id=self.message_id,
670
+ text=new_text
671
+ )
672
+
673
+ def delete(self) -> Dict[str, Any]:
674
+ return self.bot.delete_message(
675
+ chat_id=self.chat_id,
676
+ message_id=self.message_id
677
+ )
678
+ @hybrid_property
679
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
680
+ @hybrid_property
681
+ async def name(self):return await self.bot.get_name(self.chat_id)
682
+ @hybrid_property
683
+ async def username(self):return await self.bot.get_username(self.chat_id)
684
+ @hybrid_property
685
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)
686
+ class AuxData:
687
+ def __init__(self, data: dict):
688
+ self.start_id = data.get("start_id")
689
+ self.button_id = data.get("button_id")
690
+
691
+
692
+ class InlineMessage:
693
+ def __init__(self, bot, raw_data: dict):
694
+ self.bot = bot
695
+ self.raw_data = raw_data
696
+ chat_id : str = raw_data.get("chat_id")
697
+ sender_id : str = raw_data.get("sender_id")
698
+ self.chat_id: str = raw_data.get("chat_id")
699
+ self.message_id: str = raw_data.get("message_id")
700
+ self.sender_id: str = raw_data.get("sender_id")
701
+ self.text: str = raw_data.get("text")
702
+ self.aux_data = AuxData(raw_data.get("aux_data", {})) if "aux_data" in raw_data else None
703
+ self.bot = bot
704
+ self.raw_data = raw_data or {}
705
+ self.object_guid = chat_id
706
+ self.author_guid = self.raw_data.get("sender_id", sender_id)
707
+ 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))
708
+ self.sender_id: str = self.raw_data.get("sender_id", sender_id)
709
+ self.time: str = self.raw_data.get("time")
710
+ self.is_edited: bool = self.raw_data.get("is_edited", False)
711
+ self.sender_type: str = self.raw_data.get("sender_type")
712
+ self.args = []
713
+ self.is_command = bool(self.text and self.text.startswith("/"))
714
+ self.is_user = self.chat_id.startswith("b")
715
+ self.is_private = self.chat_id.startswith("b")
716
+ self.is_group = self.chat_id.startswith("g")
717
+ self.is_channel = self.chat_id.startswith("c")
718
+ self.reply_to_message_id: Optional[str] = self.raw_data.get("reply_to_message_id")
719
+ self.forwarded_from = ForwardedFrom(self.raw_data["forwarded_from"]) if "forwarded_from" in self.raw_data else None
720
+ self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
721
+ self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
722
+ self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
723
+ self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
724
+ self.is_reply = self.reply_to_message_id is not None
725
+ self.has_media = any([self.file, self.sticker])
726
+ self.is_forwarded = self.forwarded_from is not None
727
+ self.is_text = bool(self.text and not self.has_media)
728
+ self.is_media = self.has_media
729
+ self.is_contact = self.contact_message is not None
730
+ self.has_any_media = any([self.file, self.sticker,])
731
+ self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
732
+ if self.file and self.file.file_name:
733
+ name = self.file.file_name.lower()
734
+ self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
735
+ self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
736
+ self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
737
+ self.is_voice = name.endswith((".ogg", ".m4a"))
738
+ self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
739
+ self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
740
+ self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
741
+ self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
742
+
743
+
744
+ @property
745
+ def session(self):
746
+ if self.chat_id not in self.bot.sessions:
747
+ self.bot.sessions[self.chat_id] = {}
748
+ return self.bot.sessions[self.chat_id]
749
+
750
+ def reply(self, text: str, delete_after: int = None, **kwargs):
751
+ async def _reply_async():
752
+ send_func = self.bot.send_message
753
+ if inspect.iscoroutinefunction(send_func):
754
+ msg = await send_func(
755
+ self.chat_id,
756
+ text,
757
+ reply_to_message_id=self.message_id,
758
+ delete_after=delete_after,
759
+ **kwargs
760
+ )
761
+ else:
762
+ msg = send_func(
763
+ self.chat_id,
764
+ text,
765
+ reply_to_message_id=self.message_id,
766
+ delete_after=delete_after,
767
+ **kwargs
768
+ )
769
+ class Pick:
770
+ def __init__(self, bot, chat_id, message_id):
771
+ self.bot = bot
772
+ self.chat_id = chat_id
773
+ self.message_id = message_id
774
+
775
+ def edit(self, new_text):
776
+ async def _edit():
777
+ func = self.bot.edit_message_text
778
+ if inspect.iscoroutinefunction(func):
779
+ await func(self.chat_id, self.message_id, new_text)
780
+ else:
781
+ func(self.chat_id, self.message_id, new_text)
782
+
783
+ try:
784
+ loop = asyncio.get_running_loop()
785
+ if loop.is_running():
786
+ return asyncio.create_task(_edit())
787
+ except RuntimeError:
788
+ return asyncio.run(_edit())
789
+
790
+ def delete(self):
791
+ async def _delete():
792
+ func = self.bot.delete_message
793
+ if inspect.iscoroutinefunction(func):
794
+ await func(self.chat_id, self.message_id)
795
+ else:
796
+ func(self.chat_id, self.message_id)
797
+ try:
798
+ loop = asyncio.get_running_loop()
799
+ if loop.is_running():
800
+ return asyncio.create_task(_delete())
801
+ except RuntimeError:
802
+ return asyncio.run(_delete())
803
+ chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
804
+ message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
805
+ return Pick(self.bot, chat_id, message_id)
806
+ try:
807
+ loop = asyncio.get_running_loop()
808
+ if loop.is_running():
809
+ return asyncio.create_task(_reply_async())
810
+ except RuntimeError:
811
+ return asyncio.run(_reply_async())
812
+ def answer(self, text: str, **kwargs):
813
+ return self.bot.send_message(
814
+ self.chat_id,
815
+ text,
816
+ reply_to_message_id=self.message_id,
817
+ **kwargs
818
+ )
819
+
820
+
821
+ def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
822
+ return self.bot._post("sendPoll", {
823
+ "chat_id": self.chat_id,
824
+ "question": question,
825
+ "options": options,
826
+ "reply_to_message_id": self.message_id,
827
+ **kwargs
828
+ })
829
+
830
+
831
+ def reply_document(
832
+ self,
833
+ path: Optional[Union[str, Path]] = None,
834
+ file_id: Optional[str] = None,
835
+ text: Optional[str] = None,
836
+ chat_keypad: Optional[Dict[str, Any]] = None,
837
+ inline_keypad: Optional[Dict[str, Any]] = None,
838
+ chat_keypad_type: Optional[str] = "None",
839
+ disable_notification: bool = False
840
+ ):
841
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
842
+ return self.bot.send_document(
843
+ chat_id=self.chat_id,
844
+ path=path,
845
+ file_id=file_id,
846
+ text=text,
847
+ chat_keypad=chat_keypad,
848
+ inline_keypad=inline_keypad,
849
+ chat_keypad_type=chat_keypad_type,
850
+ disable_notification=disable_notification,
851
+ reply_to_message_id=self.message_id
852
+ )
853
+ def reply_file(
854
+ self,
855
+ path: Optional[Union[str, Path]] = None,
856
+ file_id: Optional[str] = None,
857
+ text: Optional[str] = None,
858
+ chat_keypad: Optional[Dict[str, Any]] = None,
859
+ inline_keypad: Optional[Dict[str, Any]] = None,
860
+ chat_keypad_type: Optional[str] = "None",
861
+ disable_notification: bool = False
862
+ ):
863
+ if chat_keypad and chat_keypad_type == "none":
864
+ chat_keypad_type == "New"
865
+
866
+ return self.bot.send_document(
867
+ chat_id=self.chat_id,
868
+ path=path,
869
+ file_id=file_id,
870
+ text=text,
871
+ chat_keypad=chat_keypad,
872
+ inline_keypad=inline_keypad,
873
+ chat_keypad_type=chat_keypad_type,
874
+ disable_notification=disable_notification,
875
+ reply_to_message_id=self.message_id
876
+ )
877
+
878
+ def reply_image(
879
+ self,
880
+ path: Optional[Union[str, Path]] = None,
881
+ file_id: Optional[str] = None,
882
+ text: Optional[str] = None,
883
+ chat_keypad: Optional[Dict[str, Any]] = None,
884
+ inline_keypad: Optional[Dict[str, Any]] = None,
885
+ chat_keypad_type: Optional[str] = "None",
886
+ disable_notification: bool = False
887
+ ):
888
+ if chat_keypad and chat_keypad_type == "none":
889
+ chat_keypad_type == "New"
890
+ return self.bot.send_image(
891
+ chat_id=self.chat_id,
892
+ path=path,
893
+ file_id=file_id,
894
+ text=text,
895
+ chat_keypad=chat_keypad,
896
+ inline_keypad=inline_keypad,
897
+ chat_keypad_type=chat_keypad_type,
898
+ disable_notification=disable_notification,
899
+ reply_to_message_id=self.message_id
900
+ )
901
+
902
+ def reply_music(
903
+ self,
904
+ path: Optional[Union[str, Path]] = None,
905
+ file_id: Optional[str] = None,
906
+ text: Optional[str] = None,
907
+ chat_keypad: Optional[Dict[str, Any]] = None,
908
+ inline_keypad: Optional[Dict[str, Any]] = None,
909
+ chat_keypad_type: Optional[str] = "None",
910
+ disable_notification: bool = False
911
+ ):
912
+ if chat_keypad and chat_keypad_type == "none":
913
+ chat_keypad_type == "New"
914
+ return self.bot.send_music(
915
+ chat_id=self.chat_id,
916
+ path=path,
917
+ file_id=file_id,
918
+ text=text,
919
+ chat_keypad=chat_keypad,
920
+ inline_keypad=inline_keypad,
921
+ chat_keypad_type=chat_keypad_type,
922
+ disable_notification=disable_notification,
923
+ reply_to_message_id=self.message_id
924
+ )
925
+
926
+ def reply_voice(
927
+ self,
928
+ path: Optional[Union[str, Path]] = None,
929
+ file_id: Optional[str] = None,
930
+ text: Optional[str] = None,
931
+ chat_keypad: Optional[Dict[str, Any]] = None,
932
+ inline_keypad: Optional[Dict[str, Any]] = None,
933
+ chat_keypad_type: Optional[str] = "None",
934
+ disable_notification: bool = False
935
+ ):
936
+ if chat_keypad and chat_keypad_type == "none":
937
+ chat_keypad_type == "New"
938
+ return self.bot.send_voice(
939
+ chat_id=self.chat_id,
940
+ path=path,
941
+ file_id=file_id,
942
+ text=text,
943
+ chat_keypad=chat_keypad,
944
+ inline_keypad=inline_keypad,
945
+ chat_keypad_type=chat_keypad_type,
946
+ disable_notification=disable_notification,
947
+ reply_to_message_id=self.message_id
948
+ )
949
+
950
+ def reply_gif(
951
+ self,
952
+ path: Optional[Union[str, Path]] = None,
953
+ file_id: Optional[str] = None,
954
+ text: Optional[str] = None,
955
+ chat_keypad: Optional[Dict[str, Any]] = None,
956
+ inline_keypad: Optional[Dict[str, Any]] = None,
957
+ chat_keypad_type: Optional[str] = "None",
958
+ disable_notification: bool = False
959
+ ):
960
+ if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
961
+ return self.bot.send_gif(
962
+ chat_id=self.chat_id,
963
+ path=path,
964
+ file_id=file_id,
965
+ text=text,
966
+ chat_keypad=chat_keypad,
967
+ inline_keypad=inline_keypad,
968
+ chat_keypad_type=chat_keypad_type,
969
+ disable_notification=disable_notification,
970
+ reply_to_message_id=self.message_id
971
+ )
972
+
973
+ def reply_location(self, latitude: str, longitude: str, **kwargs) -> Dict[str, Any]:
974
+ return self.bot.send_location(
975
+ chat_id=self.chat_id,
976
+ latitude=latitude,
977
+ longitude=longitude,
978
+ reply_to_message_id=self.message_id,
979
+ **kwargs
980
+ )
981
+
982
+ def reply_contact(self, first_name: str, last_name: str, phone_number: str, **kwargs) -> Dict[str, Any]:
983
+ return self.bot.send_contact(
984
+ chat_id=self.chat_id,
985
+ first_name=first_name,
986
+ last_name=last_name,
987
+ phone_number=phone_number,
988
+ reply_to_message_id=self.message_id,
989
+ **kwargs
990
+ )
991
+
992
+ def reply_keypad(self, text: str, keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
993
+ return self.bot.send_message(
994
+ chat_id=self.chat_id,
995
+ text=text,
996
+ chat_keypad_type="New",
997
+ chat_keypad=keypad,
998
+ reply_to_message_id=self.message_id,
999
+ **kwargs
1000
+ )
1001
+
1002
+ def reply_inline(self, text: str, inline_keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
1003
+ return self.bot.send_message(
1004
+ chat_id=self.chat_id,
1005
+ text=text,
1006
+ inline_keypad=inline_keypad,
1007
+ reply_to_message_id=self.message_id,
1008
+ **kwargs
1009
+ )
1010
+
1011
+ def reply_sticker(self, sticker_id: str, **kwargs) -> Dict[str, Any]:
1012
+ return self.bot._post("sendSticker", {
1013
+ "chat_id": self.chat_id,
1014
+ "sticker_id": sticker_id,
1015
+ "reply_to_message_id": self.message_id,
1016
+ **kwargs
1017
+ })
1018
+
1019
+ def edit(self, new_text: str) -> Dict[str, Any]:
1020
+ return self.bot.edit_message_text(
1021
+ chat_id=self.chat_id,
1022
+ message_id=self.message_id,
1023
+ text=new_text
1024
+ )
1025
+
1026
+ def delete(self) -> Dict[str, Any]:
1027
+ return self.bot.delete_message(
1028
+ chat_id=self.chat_id,
1029
+ message_id=self.message_id
1030
+ )
1031
+ @hybrid_property
1032
+ async def author_name(self):return await self.bot.get_name(self.chat_id)
1033
+ @hybrid_property
1034
+ async def name(self):return await self.bot.get_name(self.chat_id)
1035
+ @hybrid_property
1036
+ async def username(self):return await self.bot.get_username(self.chat_id)
1037
+ @hybrid_property
1038
+ async def author_info(self):return await self.bot.get_chat(self.chat_id)