Rubka 6.6.2__py3-none-any.whl → 7.2.2__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.
- rubka/__init__.py +71 -2
- rubka/api.py +6 -17
- rubka/asynco.py +1088 -256
- rubka/button.py +1 -1
- rubka/context.py +587 -26
- rubka/exceptions.py +35 -1
- rubka/filters.py +29 -4
- rubka/helpers.py +1461 -0
- rubka/metadata.py +117 -0
- rubka/rubino.py +267 -96
- rubka/tv.py +145 -0
- rubka/update.py +560 -25
- {rubka-6.6.2.dist-info → rubka-7.2.2.dist-info}/METADATA +29 -11
- {rubka-6.6.2.dist-info → rubka-7.2.2.dist-info}/RECORD +17 -13
- rubka-7.2.2.dist-info/entry_points.txt +2 -0
- {rubka-6.6.2.dist-info → rubka-7.2.2.dist-info}/WHEEL +0 -0
- {rubka-6.6.2.dist-info → rubka-7.2.2.dist-info}/top_level.txt +0 -0
rubka/context.py
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
|
-
from typing import
|
|
2
|
-
|
|
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))
|
|
3
66
|
class File:
|
|
4
67
|
def __init__(self, data: dict):
|
|
5
68
|
self.file_id: str = data.get("file_id")
|
|
@@ -184,9 +247,25 @@ class Bot:
|
|
|
184
247
|
self.username: str = data.get("username")
|
|
185
248
|
self.start_message: str = data.get("start_message")
|
|
186
249
|
self.share_url: str = data.get("share_url")
|
|
187
|
-
from typing import Union
|
|
188
|
-
from pathlib import Path
|
|
189
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)
|
|
190
269
|
class Message:
|
|
191
270
|
def __init__(self, bot, chat_id, message_id, sender_id, text=None, raw_data=None):
|
|
192
271
|
self.bot = bot
|
|
@@ -196,6 +275,53 @@ class Message:
|
|
|
196
275
|
self.author_guid = self.raw_data.get("sender_id", sender_id)
|
|
197
276
|
self.message_id: str = self.raw_data.get("message_id", message_id)
|
|
198
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_music = None
|
|
292
|
+
self.is_archive = None
|
|
293
|
+
self.is_executable = None
|
|
294
|
+
self.is_font = None
|
|
295
|
+
self.metadata = self.raw_data.get("metadata", {})
|
|
296
|
+
self.is_metadata = self.metadata
|
|
297
|
+
self.meta_parts = self.metadata.get("meta_data_parts", [])
|
|
298
|
+
self.has_metadata = bool(self.meta_parts)
|
|
299
|
+
self.meta_types = [part.get("type") for part in self.meta_parts] if self.has_metadata else []
|
|
300
|
+
self.is_bold = "Bold" in self.meta_types
|
|
301
|
+
self.is_italic = "Italic" in self.meta_types
|
|
302
|
+
self.is_strike = "Strike" in self.meta_types
|
|
303
|
+
self.is_underline = "Underline" in self.meta_types
|
|
304
|
+
self.is_quote = "Quote" in self.meta_types
|
|
305
|
+
self.is_spoiler = "Spoiler" in self.meta_types
|
|
306
|
+
self.is_pre = "Pre" in self.meta_types
|
|
307
|
+
self.is_mono = "Mono" in self.meta_types
|
|
308
|
+
self.is_link_meta = "Link" in self.meta_types
|
|
309
|
+
self.meta_links = [part.get("link_url") for part in self.meta_parts if part.get("type") == "Link"]
|
|
310
|
+
self.meta_link_positions = [
|
|
311
|
+
{"from": part.get("from_index"), "length": part.get("length"), "url": part.get("link_url")}
|
|
312
|
+
for part in self.meta_parts if part.get("type") == "Link"
|
|
313
|
+
]
|
|
314
|
+
self.has_link = contains_link_or_mention(self.text) or self.is_link_meta
|
|
315
|
+
self.is_formatted = any([
|
|
316
|
+
self.is_bold,
|
|
317
|
+
self.is_italic,
|
|
318
|
+
self.is_strike,
|
|
319
|
+
self.is_underline,
|
|
320
|
+
self.is_quote,
|
|
321
|
+
self.is_spoiler,
|
|
322
|
+
self.is_pre,
|
|
323
|
+
self.is_mono
|
|
324
|
+
])
|
|
199
325
|
self.sender_id: str = self.raw_data.get("sender_id", sender_id)
|
|
200
326
|
self.time: str = self.raw_data.get("time")
|
|
201
327
|
self.is_edited: bool = self.raw_data.get("is_edited", False)
|
|
@@ -226,19 +352,86 @@ class Message:
|
|
|
226
352
|
self.is_contact = self.contact_message is not None
|
|
227
353
|
self.has_any_media = any([self.file, self.sticker, self.poll, self.location, self.live_location])
|
|
228
354
|
self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
|
|
229
|
-
self.
|
|
355
|
+
if self.file and self.file.file_name:
|
|
356
|
+
name = self.file.file_name.lower()
|
|
357
|
+
self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
|
|
358
|
+
self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
|
|
359
|
+
self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
|
|
360
|
+
self.is_music = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
|
|
361
|
+
self.is_voice = name.endswith((".ogg", ".m4a"))
|
|
362
|
+
self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
|
|
363
|
+
self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
|
|
364
|
+
self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
|
|
365
|
+
self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
|
|
230
366
|
@property
|
|
231
367
|
def session(self):
|
|
232
368
|
if self.chat_id not in self.bot.sessions:
|
|
233
369
|
self.bot.sessions[self.chat_id] = {}
|
|
234
370
|
return self.bot.sessions[self.chat_id]
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
371
|
+
|
|
372
|
+
def reply(self, text: str, delete_after: int = None,parse_mode : Optional[Literal["HTML", "Markdown"]] = None , **kwargs):
|
|
373
|
+
async def _reply_async():
|
|
374
|
+
send_func = self.bot.send_message
|
|
375
|
+
if inspect.iscoroutinefunction(send_func):
|
|
376
|
+
msg = await send_func(
|
|
377
|
+
self.chat_id,
|
|
378
|
+
text,
|
|
379
|
+
reply_to_message_id=self.message_id,
|
|
380
|
+
delete_after=delete_after,
|
|
381
|
+
parse_mode=parse_mode,
|
|
382
|
+
**kwargs
|
|
383
|
+
)
|
|
384
|
+
else:
|
|
385
|
+
msg = send_func(
|
|
386
|
+
self.chat_id,
|
|
387
|
+
text,
|
|
388
|
+
reply_to_message_id=self.message_id,
|
|
389
|
+
delete_after=delete_after,
|
|
390
|
+
**kwargs
|
|
391
|
+
)
|
|
392
|
+
class Pick:
|
|
393
|
+
def __init__(self, bot, chat_id, message_id):
|
|
394
|
+
self.bot = bot
|
|
395
|
+
self.chat_id = chat_id
|
|
396
|
+
self.message_id = message_id
|
|
397
|
+
|
|
398
|
+
def edit(self, new_text):
|
|
399
|
+
async def _edit():
|
|
400
|
+
func = self.bot.edit_message_text
|
|
401
|
+
if inspect.iscoroutinefunction(func):
|
|
402
|
+
await func(self.chat_id, self.message_id, new_text)
|
|
403
|
+
else:
|
|
404
|
+
func(self.chat_id, self.message_id, new_text)
|
|
405
|
+
|
|
406
|
+
try:
|
|
407
|
+
loop = asyncio.get_running_loop()
|
|
408
|
+
if loop.is_running():
|
|
409
|
+
return asyncio.create_task(_edit())
|
|
410
|
+
except RuntimeError:
|
|
411
|
+
return asyncio.run(_edit())
|
|
412
|
+
|
|
413
|
+
def delete(self):
|
|
414
|
+
async def _delete():
|
|
415
|
+
func = self.bot.delete_message
|
|
416
|
+
if inspect.iscoroutinefunction(func):
|
|
417
|
+
await func(self.chat_id, self.message_id)
|
|
418
|
+
else:
|
|
419
|
+
func(self.chat_id, self.message_id)
|
|
420
|
+
try:
|
|
421
|
+
loop = asyncio.get_running_loop()
|
|
422
|
+
if loop.is_running():
|
|
423
|
+
return asyncio.create_task(_delete())
|
|
424
|
+
except RuntimeError:
|
|
425
|
+
return asyncio.run(_delete())
|
|
426
|
+
chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
|
|
427
|
+
message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
|
|
428
|
+
return Pick(self.bot, chat_id, message_id)
|
|
429
|
+
try:
|
|
430
|
+
loop = asyncio.get_running_loop()
|
|
431
|
+
if loop.is_running():
|
|
432
|
+
return asyncio.create_task(_reply_async())
|
|
433
|
+
except RuntimeError:
|
|
434
|
+
return asyncio.run(_reply_async())
|
|
242
435
|
def answer(self, text: str, **kwargs):
|
|
243
436
|
return self.bot.send_message(
|
|
244
437
|
self.chat_id,
|
|
@@ -246,15 +439,66 @@ class Message:
|
|
|
246
439
|
reply_to_message_id=self.message_id,
|
|
247
440
|
**kwargs
|
|
248
441
|
)
|
|
249
|
-
|
|
250
|
-
def
|
|
251
|
-
|
|
442
|
+
async def copy(self, to_chat_id: Optional[str], message_id: Optional[str] = None):await self.copy_message(to_chat_id, message_id)
|
|
443
|
+
async def copy_message(self, to_chat_id: Optional[str], message_id: Optional[str] = None):
|
|
444
|
+
try:
|
|
445
|
+
send_func = None
|
|
446
|
+
kwargs = {
|
|
447
|
+
"chat_id": to_chat_id,
|
|
448
|
+
"reply_to_message_id": message_id,
|
|
449
|
+
"meta_data": self.metadata
|
|
450
|
+
}
|
|
451
|
+
if getattr(self, "is_photo", False):
|
|
452
|
+
send_func = self.bot.send_image
|
|
453
|
+
elif getattr(self, "is_video", False):
|
|
454
|
+
send_func = self.bot.send_video
|
|
455
|
+
elif getattr(self, "is_document", False):
|
|
456
|
+
send_func = self.bot.send_document
|
|
457
|
+
elif getattr(self, "is_text", False):
|
|
458
|
+
send_func = self.bot.send_message
|
|
459
|
+
kwargs["text"] = self.text
|
|
460
|
+
if send_func:
|
|
461
|
+
if hasattr(self, "file") and self.file:
|
|
462
|
+
kwargs["path"] = await self.bot.get_url_file(self.file.file_id)
|
|
463
|
+
return await send_func(**kwargs)
|
|
464
|
+
else:
|
|
465
|
+
raise Exception("Unsupported message type.")
|
|
466
|
+
except Exception as e:
|
|
467
|
+
raise Exception(f"Error: {e}")
|
|
468
|
+
def reply_poll(
|
|
469
|
+
self,
|
|
470
|
+
question: str,
|
|
471
|
+
options: List[str],
|
|
472
|
+
type: Literal['Regular', 'Quiz'] = "Regular",
|
|
473
|
+
allows_multiple_answers: bool = False,
|
|
474
|
+
is_anonymous: bool = True,
|
|
475
|
+
correct_option_index: Optional[int] = None,
|
|
476
|
+
hint: Optional[str] = None,
|
|
477
|
+
reply_to_message_id: Optional[str] = None,
|
|
478
|
+
disable_notification: bool = False,
|
|
479
|
+
show_results: bool = False,
|
|
480
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
481
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
482
|
+
chat_keypad_type: Optional[Literal['New', 'Remove', 'None']] = None,
|
|
483
|
+
**kwargs
|
|
484
|
+
) -> dict:
|
|
485
|
+
payload = {
|
|
252
486
|
"chat_id": self.chat_id,
|
|
253
487
|
"question": question,
|
|
254
488
|
"options": options,
|
|
255
|
-
"
|
|
256
|
-
|
|
257
|
-
|
|
489
|
+
"type": type,
|
|
490
|
+
"allows_multiple_answers": allows_multiple_answers,
|
|
491
|
+
"is_anonymous": is_anonymous,
|
|
492
|
+
"correct_option_index": correct_option_index,
|
|
493
|
+
"hint": hint,
|
|
494
|
+
"reply_to_message_id": self.message_id if not reply_to_message_id else reply_to_message_id,
|
|
495
|
+
"disable_notification": disable_notification,
|
|
496
|
+
"show_results": show_results,
|
|
497
|
+
"inline_keypad": inline_keypad,
|
|
498
|
+
"chat_keypad": chat_keypad,
|
|
499
|
+
"chat_keypad_type": chat_keypad_type,
|
|
500
|
+
}
|
|
501
|
+
return self.bot._post("sendPoll", {key: value for key, value in payload.items() if value is not None}, **kwargs)
|
|
258
502
|
|
|
259
503
|
|
|
260
504
|
def reply_document(
|
|
@@ -457,6 +701,14 @@ class Message:
|
|
|
457
701
|
chat_id=self.chat_id,
|
|
458
702
|
message_id=self.message_id
|
|
459
703
|
)
|
|
704
|
+
@hybrid_property
|
|
705
|
+
async def author_name(self):return await self.bot.get_name(self.chat_id)
|
|
706
|
+
@hybrid_property
|
|
707
|
+
async def name(self):return await self.bot.get_name(self.chat_id)
|
|
708
|
+
@hybrid_property
|
|
709
|
+
async def username(self):return await self.bot.get_username(self.chat_id)
|
|
710
|
+
@hybrid_property
|
|
711
|
+
async def author_info(self):return await self.bot.get_chat(self.chat_id)
|
|
460
712
|
class AuxData:
|
|
461
713
|
def __init__(self, data: dict):
|
|
462
714
|
self.start_id = data.get("start_id")
|
|
@@ -467,37 +719,346 @@ class InlineMessage:
|
|
|
467
719
|
def __init__(self, bot, raw_data: dict):
|
|
468
720
|
self.bot = bot
|
|
469
721
|
self.raw_data = raw_data
|
|
470
|
-
|
|
722
|
+
chat_id : str = raw_data.get("chat_id")
|
|
723
|
+
sender_id : str = raw_data.get("sender_id")
|
|
471
724
|
self.chat_id: str = raw_data.get("chat_id")
|
|
472
725
|
self.message_id: str = raw_data.get("message_id")
|
|
473
726
|
self.sender_id: str = raw_data.get("sender_id")
|
|
474
727
|
self.text: str = raw_data.get("text")
|
|
475
728
|
self.aux_data = AuxData(raw_data.get("aux_data", {})) if "aux_data" in raw_data else None
|
|
729
|
+
self.bot = bot
|
|
730
|
+
self.raw_data = raw_data or {}
|
|
731
|
+
self.object_guid = chat_id
|
|
732
|
+
self.author_guid = self.raw_data.get("sender_id", sender_id)
|
|
733
|
+
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))
|
|
734
|
+
self.sender_id: str = self.raw_data.get("sender_id", sender_id)
|
|
735
|
+
self.time: str = self.raw_data.get("time")
|
|
736
|
+
self.is_edited: bool = self.raw_data.get("is_edited", False)
|
|
737
|
+
self.sender_type: str = self.raw_data.get("sender_type")
|
|
738
|
+
self.args = []
|
|
739
|
+
self.is_command = bool(self.text and self.text.startswith("/"))
|
|
740
|
+
self.is_user = self.chat_id.startswith("b")
|
|
741
|
+
self.is_private = self.chat_id.startswith("b")
|
|
742
|
+
self.is_group = self.chat_id.startswith("g")
|
|
743
|
+
self.is_channel = self.chat_id.startswith("c")
|
|
744
|
+
self.reply_to_message_id: Optional[str] = self.raw_data.get("reply_to_message_id")
|
|
745
|
+
self.forwarded_from = ForwardedFrom(self.raw_data["forwarded_from"]) if "forwarded_from" in self.raw_data else None
|
|
746
|
+
self.file = File(self.raw_data["file"]) if "file" in self.raw_data else None
|
|
747
|
+
self.sticker = Sticker(self.raw_data["sticker"]) if "sticker" in self.raw_data else None
|
|
748
|
+
self.contact_message = ContactMessage(self.raw_data["contact_message"]) if "contact_message" in self.raw_data else None
|
|
749
|
+
self.aux_data = AuxData(self.raw_data["aux_data"]) if "aux_data" in self.raw_data else None
|
|
750
|
+
self.is_reply = self.reply_to_message_id is not None
|
|
751
|
+
self.has_media = any([self.file, self.sticker])
|
|
752
|
+
self.is_forwarded = self.forwarded_from is not None
|
|
753
|
+
self.is_text = bool(self.text and not self.has_media)
|
|
754
|
+
self.is_media = self.has_media
|
|
755
|
+
self.is_contact = self.contact_message is not None
|
|
756
|
+
self.has_any_media = any([self.file, self.sticker,])
|
|
757
|
+
self.edited_text = self.raw_data.get("edited_text") if self.is_edited else None
|
|
758
|
+
if self.file and self.file.file_name:
|
|
759
|
+
name = self.file.file_name.lower()
|
|
760
|
+
self.is_photo = name.endswith((".jpg", ".jpeg", ".png", ".gif", ".webp"))
|
|
761
|
+
self.is_video = name.endswith((".mp4", ".mov", ".avi", ".mkv", ".webm"))
|
|
762
|
+
self.is_audio = name.endswith((".mp3", ".wav", ".ogg", ".m4a", ".flac"))
|
|
763
|
+
self.is_voice = name.endswith((".ogg", ".m4a"))
|
|
764
|
+
self.is_document = name.endswith((".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx"))
|
|
765
|
+
self.is_archive = name.endswith((".zip", ".rar", ".7z", ".tar", ".gz"))
|
|
766
|
+
self.is_executable = name.endswith((".exe", ".msi", ".bat", ".sh"))
|
|
767
|
+
self.is_font = name.endswith((".ttf", ".otf", ".woff", ".woff2"))
|
|
768
|
+
|
|
476
769
|
|
|
477
|
-
|
|
770
|
+
@property
|
|
771
|
+
def session(self):
|
|
772
|
+
if self.chat_id not in self.bot.sessions:
|
|
773
|
+
self.bot.sessions[self.chat_id] = {}
|
|
774
|
+
return self.bot.sessions[self.chat_id]
|
|
775
|
+
|
|
776
|
+
def reply(self, text: str, delete_after: int = None, **kwargs):
|
|
777
|
+
async def _reply_async():
|
|
778
|
+
send_func = self.bot.send_message
|
|
779
|
+
if inspect.iscoroutinefunction(send_func):
|
|
780
|
+
msg = await send_func(
|
|
781
|
+
self.chat_id,
|
|
782
|
+
text,
|
|
783
|
+
reply_to_message_id=self.message_id,
|
|
784
|
+
delete_after=delete_after,
|
|
785
|
+
**kwargs
|
|
786
|
+
)
|
|
787
|
+
else:
|
|
788
|
+
msg = send_func(
|
|
789
|
+
self.chat_id,
|
|
790
|
+
text,
|
|
791
|
+
reply_to_message_id=self.message_id,
|
|
792
|
+
delete_after=delete_after,
|
|
793
|
+
**kwargs
|
|
794
|
+
)
|
|
795
|
+
class Pick:
|
|
796
|
+
def __init__(self, bot, chat_id, message_id):
|
|
797
|
+
self.bot = bot
|
|
798
|
+
self.chat_id = chat_id
|
|
799
|
+
self.message_id = message_id
|
|
800
|
+
|
|
801
|
+
def edit(self, new_text):
|
|
802
|
+
async def _edit():
|
|
803
|
+
func = self.bot.edit_message_text
|
|
804
|
+
if inspect.iscoroutinefunction(func):
|
|
805
|
+
await func(self.chat_id, self.message_id, new_text)
|
|
806
|
+
else:
|
|
807
|
+
func(self.chat_id, self.message_id, new_text)
|
|
808
|
+
|
|
809
|
+
try:
|
|
810
|
+
loop = asyncio.get_running_loop()
|
|
811
|
+
if loop.is_running():
|
|
812
|
+
return asyncio.create_task(_edit())
|
|
813
|
+
except RuntimeError:
|
|
814
|
+
return asyncio.run(_edit())
|
|
815
|
+
|
|
816
|
+
def delete(self):
|
|
817
|
+
async def _delete():
|
|
818
|
+
func = self.bot.delete_message
|
|
819
|
+
if inspect.iscoroutinefunction(func):
|
|
820
|
+
await func(self.chat_id, self.message_id)
|
|
821
|
+
else:
|
|
822
|
+
func(self.chat_id, self.message_id)
|
|
823
|
+
try:
|
|
824
|
+
loop = asyncio.get_running_loop()
|
|
825
|
+
if loop.is_running():
|
|
826
|
+
return asyncio.create_task(_delete())
|
|
827
|
+
except RuntimeError:
|
|
828
|
+
return asyncio.run(_delete())
|
|
829
|
+
chat_id = msg.get("chat_id") if isinstance(msg, dict) else getattr(msg, "chat_id", self.chat_id)
|
|
830
|
+
message_id = msg.get("message_id") if isinstance(msg, dict) else getattr(msg, "message_id", self.message_id)
|
|
831
|
+
return Pick(self.bot, chat_id, message_id)
|
|
832
|
+
try:
|
|
833
|
+
loop = asyncio.get_running_loop()
|
|
834
|
+
if loop.is_running():
|
|
835
|
+
return asyncio.create_task(_reply_async())
|
|
836
|
+
except RuntimeError:
|
|
837
|
+
return asyncio.run(_reply_async())
|
|
838
|
+
def answer(self, text: str, **kwargs):
|
|
478
839
|
return self.bot.send_message(
|
|
840
|
+
self.chat_id,
|
|
841
|
+
text,
|
|
842
|
+
reply_to_message_id=self.message_id,
|
|
843
|
+
**kwargs
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
def reply_poll(self, question: str, options: List[str], **kwargs) -> Dict[str, Any]:
|
|
848
|
+
return self.bot._post("sendPoll", {
|
|
849
|
+
"chat_id": self.chat_id,
|
|
850
|
+
"question": question,
|
|
851
|
+
"options": options,
|
|
852
|
+
"reply_to_message_id": self.message_id,
|
|
853
|
+
**kwargs
|
|
854
|
+
})
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
def reply_document(
|
|
858
|
+
self,
|
|
859
|
+
path: Optional[Union[str, Path]] = None,
|
|
860
|
+
file_id: Optional[str] = None,
|
|
861
|
+
text: Optional[str] = None,
|
|
862
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
863
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
864
|
+
chat_keypad_type: Optional[str] = "None",
|
|
865
|
+
disable_notification: bool = False
|
|
866
|
+
):
|
|
867
|
+
if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
|
|
868
|
+
return self.bot.send_document(
|
|
869
|
+
chat_id=self.chat_id,
|
|
870
|
+
path=path,
|
|
871
|
+
file_id=file_id,
|
|
872
|
+
text=text,
|
|
873
|
+
chat_keypad=chat_keypad,
|
|
874
|
+
inline_keypad=inline_keypad,
|
|
875
|
+
chat_keypad_type=chat_keypad_type,
|
|
876
|
+
disable_notification=disable_notification,
|
|
877
|
+
reply_to_message_id=self.message_id
|
|
878
|
+
)
|
|
879
|
+
def reply_file(
|
|
880
|
+
self,
|
|
881
|
+
path: Optional[Union[str, Path]] = None,
|
|
882
|
+
file_id: Optional[str] = None,
|
|
883
|
+
text: Optional[str] = None,
|
|
884
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
885
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
886
|
+
chat_keypad_type: Optional[str] = "None",
|
|
887
|
+
disable_notification: bool = False
|
|
888
|
+
):
|
|
889
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
890
|
+
chat_keypad_type == "New"
|
|
891
|
+
|
|
892
|
+
return self.bot.send_document(
|
|
479
893
|
chat_id=self.chat_id,
|
|
894
|
+
path=path,
|
|
895
|
+
file_id=file_id,
|
|
480
896
|
text=text,
|
|
897
|
+
chat_keypad=chat_keypad,
|
|
898
|
+
inline_keypad=inline_keypad,
|
|
899
|
+
chat_keypad_type=chat_keypad_type,
|
|
900
|
+
disable_notification=disable_notification,
|
|
901
|
+
reply_to_message_id=self.message_id
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
def reply_image(
|
|
905
|
+
self,
|
|
906
|
+
path: Optional[Union[str, Path]] = None,
|
|
907
|
+
file_id: Optional[str] = None,
|
|
908
|
+
text: Optional[str] = None,
|
|
909
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
910
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
911
|
+
chat_keypad_type: Optional[str] = "None",
|
|
912
|
+
disable_notification: bool = False
|
|
913
|
+
):
|
|
914
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
915
|
+
chat_keypad_type == "New"
|
|
916
|
+
return self.bot.send_image(
|
|
917
|
+
chat_id=self.chat_id,
|
|
918
|
+
path=path,
|
|
919
|
+
file_id=file_id,
|
|
920
|
+
text=text,
|
|
921
|
+
chat_keypad=chat_keypad,
|
|
922
|
+
inline_keypad=inline_keypad,
|
|
923
|
+
chat_keypad_type=chat_keypad_type,
|
|
924
|
+
disable_notification=disable_notification,
|
|
925
|
+
reply_to_message_id=self.message_id
|
|
926
|
+
)
|
|
927
|
+
|
|
928
|
+
def reply_music(
|
|
929
|
+
self,
|
|
930
|
+
path: Optional[Union[str, Path]] = None,
|
|
931
|
+
file_id: Optional[str] = None,
|
|
932
|
+
text: Optional[str] = None,
|
|
933
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
934
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
935
|
+
chat_keypad_type: Optional[str] = "None",
|
|
936
|
+
disable_notification: bool = False
|
|
937
|
+
):
|
|
938
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
939
|
+
chat_keypad_type == "New"
|
|
940
|
+
return self.bot.send_music(
|
|
941
|
+
chat_id=self.chat_id,
|
|
942
|
+
path=path,
|
|
943
|
+
file_id=file_id,
|
|
944
|
+
text=text,
|
|
945
|
+
chat_keypad=chat_keypad,
|
|
946
|
+
inline_keypad=inline_keypad,
|
|
947
|
+
chat_keypad_type=chat_keypad_type,
|
|
948
|
+
disable_notification=disable_notification,
|
|
949
|
+
reply_to_message_id=self.message_id
|
|
950
|
+
)
|
|
951
|
+
|
|
952
|
+
def reply_voice(
|
|
953
|
+
self,
|
|
954
|
+
path: Optional[Union[str, Path]] = None,
|
|
955
|
+
file_id: Optional[str] = None,
|
|
956
|
+
text: Optional[str] = None,
|
|
957
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
958
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
959
|
+
chat_keypad_type: Optional[str] = "None",
|
|
960
|
+
disable_notification: bool = False
|
|
961
|
+
):
|
|
962
|
+
if chat_keypad and chat_keypad_type == "none":
|
|
963
|
+
chat_keypad_type == "New"
|
|
964
|
+
return self.bot.send_voice(
|
|
965
|
+
chat_id=self.chat_id,
|
|
966
|
+
path=path,
|
|
967
|
+
file_id=file_id,
|
|
968
|
+
text=text,
|
|
969
|
+
chat_keypad=chat_keypad,
|
|
970
|
+
inline_keypad=inline_keypad,
|
|
971
|
+
chat_keypad_type=chat_keypad_type,
|
|
972
|
+
disable_notification=disable_notification,
|
|
973
|
+
reply_to_message_id=self.message_id
|
|
974
|
+
)
|
|
975
|
+
|
|
976
|
+
def reply_gif(
|
|
977
|
+
self,
|
|
978
|
+
path: Optional[Union[str, Path]] = None,
|
|
979
|
+
file_id: Optional[str] = None,
|
|
980
|
+
text: Optional[str] = None,
|
|
981
|
+
chat_keypad: Optional[Dict[str, Any]] = None,
|
|
982
|
+
inline_keypad: Optional[Dict[str, Any]] = None,
|
|
983
|
+
chat_keypad_type: Optional[str] = "None",
|
|
984
|
+
disable_notification: bool = False
|
|
985
|
+
):
|
|
986
|
+
if chat_keypad and chat_keypad_type == "none":chat_keypad_type == "New"
|
|
987
|
+
return self.bot.send_gif(
|
|
988
|
+
chat_id=self.chat_id,
|
|
989
|
+
path=path,
|
|
990
|
+
file_id=file_id,
|
|
991
|
+
text=text,
|
|
992
|
+
chat_keypad=chat_keypad,
|
|
993
|
+
inline_keypad=inline_keypad,
|
|
994
|
+
chat_keypad_type=chat_keypad_type,
|
|
995
|
+
disable_notification=disable_notification,
|
|
996
|
+
reply_to_message_id=self.message_id
|
|
997
|
+
)
|
|
998
|
+
|
|
999
|
+
def reply_location(self, latitude: str, longitude: str, **kwargs) -> Dict[str, Any]:
|
|
1000
|
+
return self.bot.send_location(
|
|
1001
|
+
chat_id=self.chat_id,
|
|
1002
|
+
latitude=latitude,
|
|
1003
|
+
longitude=longitude,
|
|
481
1004
|
reply_to_message_id=self.message_id,
|
|
482
1005
|
**kwargs
|
|
483
1006
|
)
|
|
484
|
-
|
|
1007
|
+
|
|
1008
|
+
def reply_contact(self, first_name: str, last_name: str, phone_number: str, **kwargs) -> Dict[str, Any]:
|
|
1009
|
+
return self.bot.send_contact(
|
|
1010
|
+
chat_id=self.chat_id,
|
|
1011
|
+
first_name=first_name,
|
|
1012
|
+
last_name=last_name,
|
|
1013
|
+
phone_number=phone_number,
|
|
1014
|
+
reply_to_message_id=self.message_id,
|
|
1015
|
+
**kwargs
|
|
1016
|
+
)
|
|
1017
|
+
|
|
1018
|
+
def reply_keypad(self, text: str, keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
|
|
485
1019
|
return self.bot.send_message(
|
|
486
|
-
self.chat_id,
|
|
487
|
-
text,
|
|
1020
|
+
chat_id=self.chat_id,
|
|
1021
|
+
text=text,
|
|
1022
|
+
chat_keypad_type="New",
|
|
1023
|
+
chat_keypad=keypad,
|
|
1024
|
+
reply_to_message_id=self.message_id,
|
|
1025
|
+
**kwargs
|
|
1026
|
+
)
|
|
1027
|
+
|
|
1028
|
+
def reply_inline(self, text: str, inline_keypad: Dict[str, Any], **kwargs) -> Dict[str, Any]:
|
|
1029
|
+
return self.bot.send_message(
|
|
1030
|
+
chat_id=self.chat_id,
|
|
1031
|
+
text=text,
|
|
1032
|
+
inline_keypad=inline_keypad,
|
|
488
1033
|
reply_to_message_id=self.message_id,
|
|
489
1034
|
**kwargs
|
|
490
1035
|
)
|
|
491
1036
|
|
|
492
|
-
def
|
|
1037
|
+
def reply_sticker(self, sticker_id: str, **kwargs) -> Dict[str, Any]:
|
|
1038
|
+
return self.bot._post("sendSticker", {
|
|
1039
|
+
"chat_id": self.chat_id,
|
|
1040
|
+
"sticker_id": sticker_id,
|
|
1041
|
+
"reply_to_message_id": self.message_id,
|
|
1042
|
+
**kwargs
|
|
1043
|
+
})
|
|
1044
|
+
|
|
1045
|
+
def edit(self, new_text: str) -> Dict[str, Any]:
|
|
493
1046
|
return self.bot.edit_message_text(
|
|
494
1047
|
chat_id=self.chat_id,
|
|
495
1048
|
message_id=self.message_id,
|
|
496
1049
|
text=new_text
|
|
497
1050
|
)
|
|
498
1051
|
|
|
499
|
-
def delete(self):
|
|
1052
|
+
def delete(self) -> Dict[str, Any]:
|
|
500
1053
|
return self.bot.delete_message(
|
|
501
1054
|
chat_id=self.chat_id,
|
|
502
1055
|
message_id=self.message_id
|
|
503
|
-
)
|
|
1056
|
+
)
|
|
1057
|
+
@hybrid_property
|
|
1058
|
+
async def author_name(self):return await self.bot.get_name(self.chat_id)
|
|
1059
|
+
@hybrid_property
|
|
1060
|
+
async def name(self):return await self.bot.get_name(self.chat_id)
|
|
1061
|
+
@hybrid_property
|
|
1062
|
+
async def username(self):return await self.bot.get_username(self.chat_id)
|
|
1063
|
+
@hybrid_property
|
|
1064
|
+
async def author_info(self):return await self.bot.get_chat(self.chat_id)
|